func (in *Ini) UnsetAll(secName, subName, key string) {
	if len(secName) == 0 || len(key) == 0 {
		return
	}
	secName = strings.ToLower(secName)
	sec := in.getSection(secName, subName)
	if sec == nil {
		return
	}
	sec.unsetAll(key)
}
UnsetAll remove all variables in section and/or subsection that match
with the key.
If key found it will return true, otherwise it will return false.
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
}
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
}
func (in *Ini) Set(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 {
		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
	}
	key = strings.ToLower(key)
	return sec.set(key, value)
}
func (in *Ini) Unset(secName, subName, key string) bool {
	if len(secName) == 0 || len(key) == 0 {
		return false
	}
	secName = strings.ToLower(secName)
	sec := in.getSection(secName, subName)
	if sec == nil {
		return false
	}
	return sec.unset(key)
}