go-ini.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "git.giaever.org/joachimmg/go-ini.git/ini"
  6. "io"
  7. "strings"
  8. "time"
  9. )
  10. type App struct {
  11. Name string
  12. Url string
  13. Scheme string
  14. }
  15. func m1() {
  16. // Set some data into the struct
  17. settings := &App{
  18. Name: "My Application",
  19. Url: "localhost",
  20. Scheme: "https",
  21. }
  22. // Read struct and format to INI
  23. idata, err := ini.Marshal(settings)
  24. if err != nil {
  25. fmt.Println("An error occured", err)
  26. return
  27. }
  28. // Save here? No errors.
  29. fmt.Println(string(idata))
  30. }
  31. func m2() {
  32. // Same as output from m1,
  33. // but we're now reading this and filling the struct
  34. idata := `
  35. Name = My Application
  36. Url = localhost
  37. Scheme = https`
  38. settings := &App{}
  39. // Must make idata from string to []byte
  40. if err := ini.Unmarshal([]byte(idata), settings); err != nil {
  41. fmt.Println("An error occured", err)
  42. return
  43. }
  44. // User setting here.
  45. fmt.Println(settings, settings.Name)
  46. }
  47. // AccessLevel type (easier to transform into text)
  48. type AccessLevel int
  49. // Make some access levels
  50. const (
  51. Admin AccessLevel = 1 << iota
  52. User
  53. Guest
  54. Unknown
  55. )
  56. // String returns the text representation
  57. func (a AccessLevel) String() string {
  58. switch a {
  59. case Admin:
  60. return "ADMIN"
  61. case User:
  62. return "USER"
  63. case Guest:
  64. return "GUEST"
  65. default:
  66. return "UNKNOWN"
  67. }
  68. }
  69. // We must be able to restore the numeric value
  70. func (a *AccessLevel) SetAccessLevel(al string) {
  71. for i := 1; AccessLevel(i) != Unknown; i = i << 1 {
  72. if AccessLevel(i).String() == al {
  73. *a = AccessLevel(i)
  74. return
  75. }
  76. }
  77. *a = Unknown
  78. }
  79. // Person defines an user
  80. type Person struct {
  81. Name string
  82. Birth ini.Date
  83. Access AccessLevel
  84. }
  85. // MarshalINI to get the ini-format of one person
  86. func (p *Person) MarshalINI() ([]byte, error) {
  87. // Uses ini.Date own marshaller method (see: types.go)
  88. b, err := p.Birth.MarshalINI()
  89. if err != nil {
  90. return nil, err
  91. }
  92. // Format: <name>|<ini.Date>|<access level>, e.g my name|1985-09-85-UTC-0
  93. return []byte(fmt.Sprintf("%s|%s|%s", string(p.Name), string(b), p.Access.String())), nil
  94. }
  95. // UnmarshalINI reads the format produces by MarshalINI
  96. // and creates the person/user again
  97. func (p *Person) UnmarshalINI(b []byte) error {
  98. // Split <name>|<ini.Date>|<access level>(see MarshalINI above for format)
  99. spl := strings.Split(string(b), "|")
  100. // Do some form of validation (remember: this is just an example!)
  101. if len(spl) != 3 {
  102. return fmt.Errorf("Invalid format. Expected <name|birth.ini.Date>|<AccessLevel>. Got %s", string(b))
  103. }
  104. // Set name
  105. p.Name = spl[0]
  106. // Uses trimspace here to ensure that the trailing \n (newline) is removed
  107. // as this is last item in <name>|<ini.Date>|<access level>
  108. p.Access.SetAccessLevel(strings.TrimSpace(spl[2]))
  109. // And use ini.Date's own unmarshaller method (see: types.go)
  110. return p.Birth.UnmarshalINI([]byte(spl[1]))
  111. }
  112. // Persons is several persons
  113. type Persons []Person
  114. // Personell is users with given access levels
  115. type Personell struct {
  116. Users Persons
  117. }
  118. func (p *Persons) MarshalINI() ([]byte, error) {
  119. // []string to store each person in
  120. var persons []string
  121. for i := 0; i < len(*p); i++ {
  122. // Run marshaller method on each (see Person.Marshal() above)
  123. person, err := (*p)[i].MarshalINI()
  124. // Ensure there arent any errors...
  125. if err != nil {
  126. return nil, err
  127. }
  128. // Add the person visual representation to the list of persons
  129. persons = append(persons, string(person))
  130. }
  131. // Return as a multiline ini-entry
  132. return []byte(strings.Join(persons, "\\\n")), nil
  133. }
  134. // This is left for the reader to solve ;)
  135. func (p *Persons) UnmarshalINI(b []byte) error {
  136. persons := bytes.NewBuffer(b)
  137. for pbytes, err := persons.ReadBytes('\n'); err == nil; pbytes, err = persons.ReadBytes('\n') {
  138. var person Person
  139. person.UnmarshalINI(pbytes)
  140. *p = append(*p, person)
  141. if err == io.EOF {
  142. break
  143. }
  144. }
  145. return nil
  146. }
  147. func m3() {
  148. p := &Personell{}
  149. // Fill some data!
  150. p.Users = append(p.Users,
  151. Person{
  152. Name: "Testing Johanson",
  153. Birth: ini.Date{time.Date(1985, time.Month(9), 23, 0, 0, 0, 0, time.UTC)},
  154. Access: Admin, // Admin
  155. },
  156. Person{
  157. Name: "Testing Aniston",
  158. Birth: ini.Date{time.Date(1987, time.Month(1), 12, 0, 0, 0, 0, time.UTC)},
  159. Access: User, // Unknown user
  160. },
  161. Person{
  162. Name: "Testing Cubain",
  163. Birth: ini.Date{time.Date(1986, time.Month(3), 3, 0, 0, 0, 0, time.UTC)},
  164. Access: Guest, // Guest
  165. },
  166. )
  167. idata, err := ini.Marshal(p)
  168. if err != nil {
  169. fmt.Println(err)
  170. return
  171. }
  172. fmt.Println(string(idata))
  173. }
  174. func m4() {
  175. // Output from m3
  176. idata := `
  177. Users = Testing Johanson|1985-9-23-UTC-0|ADMIN\
  178. Testing Aniston|1987-1-12-UTC-0|USER\
  179. Testing Cubain|1986-3-3-UTC-0|GUEST`
  180. p := &Personell{}
  181. if err := ini.Unmarshal([]byte(idata), p); err != nil {
  182. fmt.Println(err)
  183. return
  184. }
  185. fmt.Println("Success, you did it!", p)
  186. }
  187. func main() {
  188. m1()
  189. m2()
  190. m3()
  191. m4()
  192. }
  193. /**
  194. * DEBUG DATA
  195. **/
  196. type Test struct {
  197. Str string `ini:"String"`
  198. UnquotedString string
  199. MultipleLines string
  200. WithoutValue bool
  201. Date ini.Date
  202. Time ini.Time
  203. TestTime time.Time
  204. IP ini.IP
  205. Int struct {
  206. Int int
  207. Int8 int8
  208. Int16 int16
  209. Int32 int32
  210. Int64 int64
  211. Uint struct {
  212. Uint uint
  213. Uint8 uint8
  214. Uint16 uint16
  215. Uint32 uint32
  216. Uint64 uint64
  217. }
  218. }
  219. Float struct {
  220. Float32 float32
  221. Float64 float64
  222. }
  223. }
  224. func (t *Test) String() string {
  225. return fmt.Sprintf(`
  226. STRUCT DATA:
  227. Str: %v
  228. UnquotedString: %v
  229. MultipleLines: %v
  230. WithoutValue: %v
  231. Date: %v
  232. Time: %v
  233. TestTime: %v
  234. IP: %v
  235. Int {
  236. Int: %v
  237. Int8: %v
  238. Int16: %v
  239. Int32: %v
  240. Int64: %v
  241. Uint {
  242. Uint: %v
  243. Uint8: %v
  244. Uint16: %v
  245. Uint32: %v
  246. Uint64: %v
  247. }
  248. }
  249. Float {
  250. Float32: %v
  251. Float64: %v
  252. }`,
  253. t.Str, t.UnquotedString, strings.Replace(t.MultipleLines, "\n", "\n\t\t\t\t", -1), t.WithoutValue, t.Date, t.Time, t.TestTime, t.IP,
  254. t.Int.Int, t.Int.Int8, t.Int.Int16, t.Int.Int32, t.Int.Int64,
  255. t.Int.Uint.Uint, t.Int.Uint.Uint8, t.Int.Uint.Uint16, t.Int.Uint.Uint32, t.Int.Uint.Uint64,
  256. t.Float.Float32, t.Float.Float64,
  257. )
  258. }
  259. func sep(f, e string) {
  260. var s []byte
  261. for i := 0; i < 80; i++ {
  262. s = append(s, '/')
  263. }
  264. fmt.Println(f, string(s), e)
  265. }
  266. func debug() {
  267. text := `
  268. String = "This is some text"
  269. UnquotedString = This is some unquoted text
  270. MultipleLines = This is \
  271. multiple lines \
  272. going on
  273. WithoutValue
  274. Date = 2017-9-28-Local-0
  275. Time = 01 Jan 01 00:00 UTC
  276. IP = ::
  277. [Int]
  278. Int = -1
  279. Int8 = -8
  280. Int16 = -16
  281. Int32 = -32
  282. Int64 = -64
  283. [Int.Uint]
  284. Uint = 1
  285. Uint8 = 8
  286. Uint16 = 16
  287. Uint32 = 32
  288. Uint64 = 64
  289. Uint64 = 64
  290. [Float]
  291. Float32 = 3.14722354762387648273648726348
  292. Float64 = 10.00003423472342734897234872347293748`
  293. first := &Test{}
  294. sep("", "")
  295. fmt.Println(" ### INI TO UNMARSHAL:")
  296. sep("", "")
  297. fmt.Println(text)
  298. sep("\n", "")
  299. fmt.Println(" ### INITIAL STRUCT VALUES (empty/unset values):")
  300. sep("", "")
  301. fmt.Println(first)
  302. sep("\n", "")
  303. fmt.Println(" --- NOW MARSHALING: INI -> STRUCT ---")
  304. err := ini.Unmarshal([]byte(text), first)
  305. fmt.Println(" !!! ERROR ON UMARSHALING:", err)
  306. sep("", "")
  307. fmt.Println(" ### NEW STRUCT VALUES (unmarshaled from INI):")
  308. sep("", "\n")
  309. fmt.Println(first)
  310. sep("\n", "")
  311. fmt.Println(" --- NOW UNMARSHALING: STRUCT -> INI ---")
  312. unm, err := ini.Marshal(first)
  313. fmt.Println(" !!! ERROR ON MARCHALING:", err)
  314. sep("", "")
  315. fmt.Println(" ### PRODUCED INI (marshaled from STRUCT)")
  316. sep("", "")
  317. fmt.Println(string(unm))
  318. sep("", "")
  319. }