func (in *Ini) Section(secName, subName string) (sec *Section) {
	if len(secName) == 0 {
		return nil
	}
	sec = &Section{
		name: secName,
		sub:  subName,
	}
	secName = strings.ToLower(secName)
	for x := 0; x < len(in.secs); x++ {
		if secName != in.secs[x].nameLower {
			continue
		}
		if subName != in.secs[x].sub {
			continue
		}
		sec.merge(in.secs[x])
	}
	return
}
Section given section and/or subsection name, return the Section object
that match with it.
If section name is empty, it will return nil.
If ini contains duplicate section (or subsection) it will merge all
of its variables into one section.
package ini
import (
	"bytes"
	"fmt"
	"io"
	"os"
	"reflect"
	"strings"
	"time"
	"github.com/shuLhan/share/lib/debug"
	libstrings "github.com/shuLhan/share/lib/strings"
)
const (
	fieldTagName      = "ini"
	fieldTagSeparator = ":"
)
type Ini struct {
	secs []*Section
}
func Open(filename string) (in *Ini, err error) {
	reader := newReader()
	in, err = reader.parseFile(filename)
	if debug.Value >= 3 && err == nil {
		err = in.Write(os.Stdout)
	}
	return
}
func Parse(text []byte) (in *Ini, err error) {
	reader := newReader()
	return reader.Parse(text)
}
func Marshal(v interface{}) (b []byte, err error) {
	rtipe := reflect.TypeOf(v)
	rvalue := reflect.ValueOf(v)
	kind := rtipe.Kind()
	for kind == reflect.Ptr {
		rtipe = rtipe.Elem()
		rvalue = rvalue.Elem()
		kind = rtipe.Kind()
	}
	if kind != reflect.Struct {
		return nil, fmt.Errorf("marshal: expecting struct, got %v", kind)
	}
	in := &Ini{}
	in.marshalStruct(rtipe, rvalue, "", "")
	buf := bytes.NewBuffer(nil)
	err = in.Write(buf)
	if err != nil {
		return nil, err
	}
	b = buf.Bytes()
	return b, nil
}
func (in *Ini) marshalStruct(
	rtipe reflect.Type, rvalue reflect.Value,
	parentSec, parentSub string,
) {
	numField := rtipe.NumField()
	if numField == 0 {
		return
	}
	for x := 0; x < numField; x++ {
		field := rtipe.Field(x)
		fvalue := rvalue.Field(x)
		ftype := field.Type
		kind := ftype.Kind()
		tag := field.Tag.Get(fieldTagName)
		if len(tag) == 0 && kind != reflect.Struct {
			continue
		}
		layout := field.Tag.Get("layout")
		if len(layout) == 0 {
			layout = time.RFC3339
		}
		var sec, sub, key, value string
		tags := strings.Split(tag, fieldTagSeparator)
		switch len(tags) {
		case 0:
			if kind != reflect.Struct {
				continue
			}
		case 1:
			sec = tags[0]
			key = field.Name
		case 2:
			sec = tags[0]
			sub = tags[1]
			key = field.Name
		default:
			sec = tags[0]
			sub = tags[1]
			key = tags[2]
		}
		if len(parentSec) > 0 {
			sec = parentSec
		}
		if len(parentSub) > 0 {
			sub = parentSub
		}
		key = strings.ToLower(key)
		for kind == reflect.Ptr {
			ftype = ftype.Elem()
			kind = ftype.Kind()
			fvalue = fvalue.Elem()
		}
		switch kind {
		case reflect.String:
			in.Set(sec, sub, key, fvalue.String())
		case reflect.Array, reflect.Slice:
			for xx := 0; xx < fvalue.Len(); xx++ {
				item := fvalue.Index(xx)
				for item.Kind() == reflect.Ptr {
					item = item.Elem()
				}
				switch item.Kind() {
				case reflect.Struct:
					vi := item.Interface()
					structIni := &Ini{}
					structIni.marshalStruct(
						reflect.TypeOf(vi),
						reflect.ValueOf(vi), sec, sub)
					in.secs = append(in.secs, structIni.secs...)
				default:
					value = fmt.Sprintf("%v", item)
					in.Add(sec, sub, key, value)
				}
			}
		case reflect.Map:
			iter := fvalue.MapRange()
			for iter.Next() {
				mk := iter.Key()
				mv := iter.Value()
				key = strings.ToLower(fmt.Sprintf("%v", mk))
				value = fmt.Sprintf("%v", mv)
				in.Set(sec, sub, key, value)
			}
		case reflect.Ptr:
			for ftype.Kind() == reflect.Ptr {
				ftype = ftype.Elem()
				fvalue = fvalue.Elem()
			}
			switch ftype.Kind() {
			case reflect.Struct:
				vi := fvalue.Interface()
				t, ok := vi.(time.Time)
				if ok {
					value = t.Format(layout)
					in.Set(sec, sub, key, value)
					continue
				}
				in.marshalStruct(reflect.TypeOf(vi), reflect.ValueOf(vi), sec, sub)
			}
		case reflect.Struct:
			vi := fvalue.Interface()
			t, ok := vi.(time.Time)
			if ok {
				value = t.Format(layout)
				in.Set(sec, sub, key, value)
				continue
			}
			in.marshalStruct(reflect.TypeOf(vi), reflect.ValueOf(vi), sec, sub)
		case reflect.Invalid, reflect.Chan, reflect.Func,
			reflect.UnsafePointer, reflect.Interface:
		default:
			value = fmt.Sprintf("%v", fvalue)
			in.Set(sec, sub, key, value)
		}
	}
}
func Unmarshal(b []byte, v interface{}) (err error) {
	ini, err := Parse(b)
	if err != nil {
		return err
	}
	return ini.Unmarshal(v)
}
func (in *Ini) Unmarshal(v interface{}) (err error) {
	rtipe := reflect.TypeOf(v)
	rvalue := reflect.ValueOf(v)
	kind := rtipe.Kind()
	for kind != reflect.Ptr {
		return fmt.Errorf("ini: Unmarshal: expecting pointer to struct, got %v", kind)
	}
	rtipe = rtipe.Elem()
	rvalue = rvalue.Elem()
	kind = rtipe.Kind()
	if kind != reflect.Struct {
		return fmt.Errorf("ini: Unmarshal: expecting pointer to struct, got %v", kind)
	}
	tagField := unpackStruct(rtipe, rvalue)
	in.unmarshal(tagField, rtipe, rvalue)
	return nil
}
func (in *Ini) Add(secName, subName, key, value string) bool {
	if len(secName) == 0 || len(key) == 0 {
		return false
	}
	secName = strings.ToLower(secName)
	sec := in.getSection(secName, subName)
	if sec != nil {
		return sec.add(key, value)
	}
	sec = newSection(secName, subName)
	v := &variable{
		mode:     lineModeValue,
		key:      key,
		keyLower: strings.ToLower(key),
		value:    value,
	}
	sec.vars = append(sec.vars, v)
	in.secs = append(in.secs, sec)
	return true
}