1 package ini
2
3 import (
4 "bytes"
5 "errors"
6 "fmt"
7 "reflect"
8 "sort"
9 "strconv"
10 "strings"
11 "time"
12 "unicode"
13 )
14
15
16 type NameMapper func(string) string
17
18
19 var (
20
21 SnackCase NameMapper = func(raw string) string {
22 newstr := make([]rune, 0, len(raw))
23 for i, chr := range raw {
24 if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
25 if i > 0 {
26 newstr = append(newstr, '_')
27 }
28 }
29 newstr = append(newstr, unicode.ToUpper(chr))
30 }
31 return string(newstr)
32 }
33
34 TitleUnderscore NameMapper = func(raw string) string {
35 newstr := make([]rune, 0, len(raw))
36 for i, chr := range raw {
37 if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
38 if i > 0 {
39 newstr = append(newstr, '_')
40 }
41 chr -= 'A' - 'a'
42 }
43 newstr = append(newstr, chr)
44 }
45 return string(newstr)
46 }
47 )
48
49 func (s *Section) parseFieldName(raw, actual string) string {
50 if len(actual) > 0 {
51 return actual
52 }
53 if s.f.NameMapper != nil {
54 return s.f.NameMapper(raw)
55 }
56 return raw
57 }
58
59 func parseDelim(actual string) string {
60 if len(actual) > 0 {
61 return actual
62 }
63 return ","
64 }
65
66 var reflectTime = reflect.TypeOf(time.Now()).Kind()
67
68
69 func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error {
70 var strs []string
71 if allowShadow {
72 strs = key.StringsWithShadows(delim)
73 } else {
74 strs = key.Strings(delim)
75 }
76
77 numVals := len(strs)
78 if numVals == 0 {
79 return nil
80 }
81
82 var vals interface{}
83 var err error
84
85 sliceOf := field.Type().Elem().Kind()
86 switch sliceOf {
87 case reflect.String:
88 vals = strs
89 case reflect.Int:
90 vals, err = key.parseInts(strs, true, false)
91 case reflect.Int64:
92 vals, err = key.parseInt64s(strs, true, false)
93 case reflect.Uint:
94 vals, err = key.parseUints(strs, true, false)
95 case reflect.Uint64:
96 vals, err = key.parseUint64s(strs, true, false)
97 case reflect.Float64:
98 vals, err = key.parseFloat64s(strs, true, false)
99 case reflect.Bool:
100 vals, err = key.parseBools(strs, true, false)
101 case reflectTime:
102 vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false)
103 default:
104 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
105 }
106 if err != nil && isStrict {
107 return err
108 }
109
110 slice := reflect.MakeSlice(field.Type(), numVals, numVals)
111 for i := 0; i < numVals; i++ {
112 switch sliceOf {
113 case reflect.String:
114 slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i]))
115 case reflect.Int:
116 slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i]))
117 case reflect.Int64:
118 slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i]))
119 case reflect.Uint:
120 slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i]))
121 case reflect.Uint64:
122 slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i]))
123 case reflect.Float64:
124 slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i]))
125 case reflect.Bool:
126 slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i]))
127 case reflectTime:
128 slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i]))
129 }
130 }
131 field.Set(slice)
132 return nil
133 }
134
135 func wrapStrictError(err error, isStrict bool) error {
136 if isStrict {
137 return err
138 }
139 return nil
140 }
141
142
143
144
145 func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error {
146 vt := t
147 isPtr := t.Kind() == reflect.Ptr
148 if isPtr {
149 vt = t.Elem()
150 }
151 switch vt.Kind() {
152 case reflect.String:
153 stringVal := key.String()
154 if isPtr {
155 field.Set(reflect.ValueOf(&stringVal))
156 } else if len(stringVal) > 0 {
157 field.SetString(key.String())
158 }
159 case reflect.Bool:
160 boolVal, err := key.Bool()
161 if err != nil {
162 return wrapStrictError(err, isStrict)
163 }
164 if isPtr {
165 field.Set(reflect.ValueOf(&boolVal))
166 } else {
167 field.SetBool(boolVal)
168 }
169 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
170
171 if vt.Name() == "Duration" {
172 durationVal, err := key.Duration()
173 if err != nil {
174 if intVal, err := key.Int64(); err == nil {
175 field.SetInt(intVal)
176 return nil
177 }
178 return wrapStrictError(err, isStrict)
179 }
180 if isPtr {
181 field.Set(reflect.ValueOf(&durationVal))
182 } else if int64(durationVal) > 0 {
183 field.Set(reflect.ValueOf(durationVal))
184 }
185 return nil
186 }
187
188 intVal, err := key.Int64()
189 if err != nil {
190 return wrapStrictError(err, isStrict)
191 }
192 if isPtr {
193 pv := reflect.New(t.Elem())
194 pv.Elem().SetInt(intVal)
195 field.Set(pv)
196 } else {
197 field.SetInt(intVal)
198 }
199
200 case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
201 durationVal, err := key.Duration()
202
203 if err == nil && uint64(durationVal) > 0 {
204 if isPtr {
205 field.Set(reflect.ValueOf(&durationVal))
206 } else {
207 field.Set(reflect.ValueOf(durationVal))
208 }
209 return nil
210 }
211
212 uintVal, err := key.Uint64()
213 if err != nil {
214 return wrapStrictError(err, isStrict)
215 }
216 if isPtr {
217 pv := reflect.New(t.Elem())
218 pv.Elem().SetUint(uintVal)
219 field.Set(pv)
220 } else {
221 field.SetUint(uintVal)
222 }
223
224 case reflect.Float32, reflect.Float64:
225 floatVal, err := key.Float64()
226 if err != nil {
227 return wrapStrictError(err, isStrict)
228 }
229 if isPtr {
230 pv := reflect.New(t.Elem())
231 pv.Elem().SetFloat(floatVal)
232 field.Set(pv)
233 } else {
234 field.SetFloat(floatVal)
235 }
236 case reflectTime:
237 timeVal, err := key.Time()
238 if err != nil {
239 return wrapStrictError(err, isStrict)
240 }
241 if isPtr {
242 field.Set(reflect.ValueOf(&timeVal))
243 } else {
244 field.Set(reflect.ValueOf(timeVal))
245 }
246 case reflect.Slice:
247 return setSliceWithProperType(key, field, delim, allowShadow, isStrict)
248 default:
249 return fmt.Errorf("unsupported type %q", t)
250 }
251 return nil
252 }
253
254 func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool, allowNonUnique bool, extends bool) {
255 opts := strings.SplitN(tag, ",", 5)
256 rawName = opts[0]
257 for _, opt := range opts[1:] {
258 omitEmpty = omitEmpty || (opt == "omitempty")
259 allowShadow = allowShadow || (opt == "allowshadow")
260 allowNonUnique = allowNonUnique || (opt == "nonunique")
261 extends = extends || (opt == "extends")
262 }
263 return rawName, omitEmpty, allowShadow, allowNonUnique, extends
264 }
265
266
267
268 func (s *Section) mapToField(val reflect.Value, isStrict bool, sectionIndex int, sectionName string) error {
269 if val.Kind() == reflect.Ptr {
270 val = val.Elem()
271 }
272 typ := val.Type()
273
274 for i := 0; i < typ.NumField(); i++ {
275 field := val.Field(i)
276 tpField := typ.Field(i)
277
278 tag := tpField.Tag.Get("ini")
279 if tag == "-" {
280 continue
281 }
282
283 rawName, _, allowShadow, allowNonUnique, extends := parseTagOptions(tag)
284 fieldName := s.parseFieldName(tpField.Name, rawName)
285 if len(fieldName) == 0 || !field.CanSet() {
286 continue
287 }
288
289 isStruct := tpField.Type.Kind() == reflect.Struct
290 isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct
291 isAnonymousPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
292 if isAnonymousPtr {
293 field.Set(reflect.New(tpField.Type.Elem()))
294 }
295
296 if extends && (isAnonymousPtr || (isStruct && tpField.Anonymous)) {
297 if isStructPtr && field.IsNil() {
298 field.Set(reflect.New(tpField.Type.Elem()))
299 }
300 fieldSection := s
301 if rawName != "" {
302 sectionName = s.name + s.f.options.ChildSectionDelimiter + rawName
303 if secs, err := s.f.SectionsByName(sectionName); err == nil && sectionIndex < len(secs) {
304 fieldSection = secs[sectionIndex]
305 }
306 }
307 if err := fieldSection.mapToField(field, isStrict, sectionIndex, sectionName); err != nil {
308 return fmt.Errorf("map to field %q: %v", fieldName, err)
309 }
310 } else if isAnonymousPtr || isStruct || isStructPtr {
311 if secs, err := s.f.SectionsByName(fieldName); err == nil {
312 if len(secs) <= sectionIndex {
313 return fmt.Errorf("there are not enough sections (%d <= %d) for the field %q", len(secs), sectionIndex, fieldName)
314 }
315
316
317 if isStructPtr && field.IsNil() {
318 field.Set(reflect.New(tpField.Type.Elem()))
319 }
320 if err = secs[sectionIndex].mapToField(field, isStrict, sectionIndex, fieldName); err != nil {
321 return fmt.Errorf("map to field %q: %v", fieldName, err)
322 }
323 continue
324 }
325 }
326
327
328 if allowNonUnique && tpField.Type.Kind() == reflect.Slice {
329 newField, err := s.mapToSlice(fieldName, field, isStrict)
330 if err != nil {
331 return fmt.Errorf("map to slice %q: %v", fieldName, err)
332 }
333
334 field.Set(newField)
335 continue
336 }
337
338 if key, err := s.GetKey(fieldName); err == nil {
339 delim := parseDelim(tpField.Tag.Get("delim"))
340 if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil {
341 return fmt.Errorf("set field %q: %v", fieldName, err)
342 }
343 }
344 }
345 return nil
346 }
347
348
349
350 func (s *Section) mapToSlice(secName string, val reflect.Value, isStrict bool) (reflect.Value, error) {
351 secs, err := s.f.SectionsByName(secName)
352 if err != nil {
353 return reflect.Value{}, err
354 }
355
356 typ := val.Type().Elem()
357 for i, sec := range secs {
358 elem := reflect.New(typ)
359 if err = sec.mapToField(elem, isStrict, i, sec.name); err != nil {
360 return reflect.Value{}, fmt.Errorf("map to field from section %q: %v", secName, err)
361 }
362
363 val = reflect.Append(val, elem.Elem())
364 }
365 return val, nil
366 }
367
368
369 func (s *Section) mapTo(v interface{}, isStrict bool) error {
370 typ := reflect.TypeOf(v)
371 val := reflect.ValueOf(v)
372 if typ.Kind() == reflect.Ptr {
373 typ = typ.Elem()
374 val = val.Elem()
375 } else {
376 return errors.New("not a pointer to a struct")
377 }
378
379 if typ.Kind() == reflect.Slice {
380 newField, err := s.mapToSlice(s.name, val, isStrict)
381 if err != nil {
382 return err
383 }
384
385 val.Set(newField)
386 return nil
387 }
388
389 return s.mapToField(val, isStrict, 0, s.name)
390 }
391
392
393 func (s *Section) MapTo(v interface{}) error {
394 return s.mapTo(v, false)
395 }
396
397
398
399 func (s *Section) StrictMapTo(v interface{}) error {
400 return s.mapTo(v, true)
401 }
402
403
404 func (f *File) MapTo(v interface{}) error {
405 return f.Section("").MapTo(v)
406 }
407
408
409
410 func (f *File) StrictMapTo(v interface{}) error {
411 return f.Section("").StrictMapTo(v)
412 }
413
414
415 func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
416 cfg, err := Load(source, others...)
417 if err != nil {
418 return err
419 }
420 cfg.NameMapper = mapper
421 return cfg.MapTo(v)
422 }
423
424
425
426 func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
427 cfg, err := Load(source, others...)
428 if err != nil {
429 return err
430 }
431 cfg.NameMapper = mapper
432 return cfg.StrictMapTo(v)
433 }
434
435
436 func MapTo(v, source interface{}, others ...interface{}) error {
437 return MapToWithMapper(v, nil, source, others...)
438 }
439
440
441
442 func StrictMapTo(v, source interface{}, others ...interface{}) error {
443 return StrictMapToWithMapper(v, nil, source, others...)
444 }
445
446
447 func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error {
448 slice := field.Slice(0, field.Len())
449 if field.Len() == 0 {
450 return nil
451 }
452 sliceOf := field.Type().Elem().Kind()
453
454 if allowShadow {
455 var keyWithShadows *Key
456 for i := 0; i < field.Len(); i++ {
457 var val string
458 switch sliceOf {
459 case reflect.String:
460 val = slice.Index(i).String()
461 case reflect.Int, reflect.Int64:
462 val = fmt.Sprint(slice.Index(i).Int())
463 case reflect.Uint, reflect.Uint64:
464 val = fmt.Sprint(slice.Index(i).Uint())
465 case reflect.Float64:
466 val = fmt.Sprint(slice.Index(i).Float())
467 case reflect.Bool:
468 val = fmt.Sprint(slice.Index(i).Bool())
469 case reflectTime:
470 val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339)
471 default:
472 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
473 }
474
475 if i == 0 {
476 keyWithShadows = newKey(key.s, key.name, val)
477 } else {
478 _ = keyWithShadows.AddShadow(val)
479 }
480 }
481 *key = *keyWithShadows
482 return nil
483 }
484
485 var buf bytes.Buffer
486 for i := 0; i < field.Len(); i++ {
487 switch sliceOf {
488 case reflect.String:
489 buf.WriteString(slice.Index(i).String())
490 case reflect.Int, reflect.Int64:
491 buf.WriteString(fmt.Sprint(slice.Index(i).Int()))
492 case reflect.Uint, reflect.Uint64:
493 buf.WriteString(fmt.Sprint(slice.Index(i).Uint()))
494 case reflect.Float64:
495 buf.WriteString(fmt.Sprint(slice.Index(i).Float()))
496 case reflect.Bool:
497 buf.WriteString(fmt.Sprint(slice.Index(i).Bool()))
498 case reflectTime:
499 buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339))
500 default:
501 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
502 }
503 buf.WriteString(delim)
504 }
505 key.SetValue(buf.String()[:buf.Len()-len(delim)])
506 return nil
507 }
508
509
510 func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error {
511 switch t.Kind() {
512 case reflect.String:
513 key.SetValue(field.String())
514 case reflect.Bool:
515 key.SetValue(fmt.Sprint(field.Bool()))
516 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
517 key.SetValue(fmt.Sprint(field.Int()))
518 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
519 key.SetValue(fmt.Sprint(field.Uint()))
520 case reflect.Float32, reflect.Float64:
521 key.SetValue(strconv.FormatFloat(field.Float(), 'f', -1, 64))
522 case reflectTime:
523 key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339)))
524 case reflect.Slice:
525 return reflectSliceWithProperType(key, field, delim, allowShadow)
526 case reflect.Ptr:
527 if !field.IsNil() {
528 return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow)
529 }
530 default:
531 return fmt.Errorf("unsupported type %q", t)
532 }
533 return nil
534 }
535
536
537
538 func isEmptyValue(v reflect.Value) bool {
539 switch v.Kind() {
540 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
541 return v.Len() == 0
542 case reflect.Bool:
543 return !v.Bool()
544 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
545 return v.Int() == 0
546 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
547 return v.Uint() == 0
548 case reflect.Float32, reflect.Float64:
549 return v.Float() == 0
550 case reflect.Interface, reflect.Ptr:
551 return v.IsNil()
552 case reflectTime:
553 t, ok := v.Interface().(time.Time)
554 return ok && t.IsZero()
555 }
556 return false
557 }
558
559
560 type StructReflector interface {
561 ReflectINIStruct(*File) error
562 }
563
564 func (s *Section) reflectFrom(val reflect.Value) error {
565 if val.Kind() == reflect.Ptr {
566 val = val.Elem()
567 }
568
569 if val.Kind() == reflect.Map {
570 return s.reflectFromMap(val)
571 }
572
573 typ := val.Type()
574
575 for i := 0; i < typ.NumField(); i++ {
576 if !val.Field(i).CanInterface() {
577 continue
578 }
579
580 field := val.Field(i)
581 tpField := typ.Field(i)
582
583 tag := tpField.Tag.Get("ini")
584 if tag == "-" {
585 continue
586 }
587
588 rawName, omitEmpty, allowShadow, allowNonUnique, extends := parseTagOptions(tag)
589 if omitEmpty && isEmptyValue(field) {
590 continue
591 }
592
593 if r, ok := field.Interface().(StructReflector); ok {
594 return r.ReflectINIStruct(s.f)
595 }
596
597 fieldName := s.parseFieldName(tpField.Name, rawName)
598 if len(fieldName) == 0 || !field.CanSet() {
599 continue
600 }
601
602 if extends && tpField.Anonymous && (tpField.Type.Kind() == reflect.Ptr || tpField.Type.Kind() == reflect.Struct) {
603 if err := s.reflectFrom(field); err != nil {
604 return fmt.Errorf("reflect from field %q: %v", fieldName, err)
605 }
606 continue
607 }
608
609 if (tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct) ||
610 (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") {
611
612 sec, err := s.f.GetSection(fieldName)
613 if err != nil {
614
615 sec, _ = s.f.NewSection(fieldName)
616 }
617
618
619 if len(sec.Comment) == 0 {
620 sec.Comment = tpField.Tag.Get("comment")
621 }
622
623 if err = sec.reflectFrom(field); err != nil {
624 return fmt.Errorf("reflect from field %q: %v", fieldName, err)
625 }
626 continue
627 }
628
629 if allowNonUnique && tpField.Type.Kind() == reflect.Slice {
630 slice := field.Slice(0, field.Len())
631 if field.Len() == 0 {
632 return nil
633 }
634 sliceOf := field.Type().Elem().Kind()
635
636 for i := 0; i < field.Len(); i++ {
637 if sliceOf != reflect.Struct && sliceOf != reflect.Ptr {
638 return fmt.Errorf("field %q is not a slice of pointer or struct", fieldName)
639 }
640
641 sec, err := s.f.NewSection(fieldName)
642 if err != nil {
643 return err
644 }
645
646
647 if len(sec.Comment) == 0 {
648 sec.Comment = tpField.Tag.Get("comment")
649 }
650
651 if err := sec.reflectFrom(slice.Index(i)); err != nil {
652 return fmt.Errorf("reflect from field %q: %v", fieldName, err)
653 }
654 }
655 continue
656 }
657
658
659 key, err := s.GetKey(fieldName)
660 if err != nil {
661 key, _ = s.NewKey(fieldName, "")
662 }
663
664
665 if len(key.Comment) == 0 {
666 key.Comment = tpField.Tag.Get("comment")
667 }
668
669 delim := parseDelim(tpField.Tag.Get("delim"))
670 if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil {
671 return fmt.Errorf("reflect field %q: %v", fieldName, err)
672 }
673
674 }
675 return nil
676 }
677
678
679
680 func (s *Section) reflectFromMap(val reflect.Value) error {
681 keys := val.MapKeys()
682
683 sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() })
684 for _, k := range keys {
685 if k.Kind() != reflect.String {
686 return fmt.Errorf("invalid key for map, only strings allowed. key %s", k.Kind())
687 }
688 fieldName := k.String()
689 key, err := s.GetKey(fieldName)
690 if err != nil {
691 key, _ = s.NewKey(fieldName, "")
692 }
693 v := val.MapIndex(k)
694 if err = reflectWithProperType(v.Type(), key, v, ",", false); err != nil {
695 return fmt.Errorf("reflect field %q: %v", fieldName, err)
696 }
697 }
698 return nil
699 }
700
701
702 func (s *Section) ReflectFrom(v interface{}) error {
703 typ := reflect.TypeOf(v)
704 val := reflect.ValueOf(v)
705
706 if s.name != DefaultSection && s.f.options.AllowNonUniqueSections &&
707 (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Ptr) {
708
709 s.f.DeleteSection(s.name)
710
711 if typ.Kind() == reflect.Ptr {
712 sec, err := s.f.NewSection(s.name)
713 if err != nil {
714 return err
715 }
716 return sec.reflectFrom(val.Elem())
717 }
718
719 slice := val.Slice(0, val.Len())
720 sliceOf := val.Type().Elem().Kind()
721 if sliceOf != reflect.Ptr {
722 return fmt.Errorf("not a slice of pointers")
723 }
724
725 for i := 0; i < slice.Len(); i++ {
726 sec, err := s.f.NewSection(s.name)
727 if err != nil {
728 return err
729 }
730
731 err = sec.reflectFrom(slice.Index(i))
732 if err != nil {
733 return fmt.Errorf("reflect from %dth field: %v", i, err)
734 }
735 }
736
737 return nil
738 }
739
740 if typ.Kind() == reflect.Ptr {
741 val = val.Elem()
742 } else if typ.Kind() != reflect.Map {
743 return errors.New("not a pointer to a struct")
744 }
745
746 return s.reflectFrom(val)
747 }
748
749
750 func (f *File) ReflectFrom(v interface{}) error {
751 return f.Section("").ReflectFrom(v)
752 }
753
754
755 func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
756 cfg.NameMapper = mapper
757 return cfg.ReflectFrom(v)
758 }
759
760
761 func ReflectFrom(cfg *File, v interface{}) error {
762 return ReflectFromWithMapper(cfg, v, nil)
763 }
764
View as plain text