package ini import ( "fmt" ) type elementType int type elementByte []byte const ( section elementType = 1 << iota variable elementType = 1 << iota ) type element struct { t elementType key elementByte val elementByte quoted bool } func newElement() *element { return &element{quoted: false} } func (e *element) setType(t elementType) { e.t = t } func (e *element) trim() { e.key.trim() e.quoted = e.val.trim() } func (e *element) String() string { switch e.t { case section: return fmt.Sprintf( "section: %s", e.key, ) case variable: if e.val.len() == 0 { return fmt.Sprintf( "variable: %s -> true", e.val, ) } if e.quoted { return fmt.Sprintf( "variable: %s -> '\"%s\"'", e.key, e.val, ) } return fmt.Sprintf( "variable: %s -> '%s'", e.key, e.val, ) default: return "unknown element" } } func (e *elementByte) add(v ...interface{}) bool { b := i2byte(v) if len(b) == 0 { return false } *e = append(*e, b...) return true } func (e *elementByte) len() int { return len(*e) } func (e *elementByte) lastByteMatching(c byte) int { if n := e.len(); n != 0 && (*e)[n-1] == c { return n - 1 } return -1 } func (e *elementByte) firstByteMatching(c byte) int { if n := e.len(); n != 0 && (*e)[0] == c { return 0 } return -1 } func (e *elementByte) removeFirstByteMatching(c byte) bool { if n := e.firstByteMatching(c); n == 0 { *e = (*e)[1:] return true } return false } func (e *elementByte) removeLastByteMatching(c byte) bool { if n := e.lastByteMatching(c); n >= 0 { *e = (*e)[0:n] return true } return false } func (e *elementByte) trim() (quoted bool) { for b := e.removeFirstByteMatching(' '); b == true; b = e.removeFirstByteMatching(' ') { // remove leading whitespaces } for b := e.removeLastByteMatching(' '); b == true; b = e.removeLastByteMatching(' ') { // remove trailing whitespaces } if f := e.firstByteMatching('"'); f == 0 { if l := e.lastByteMatching('"'); l >= 0 { *e = (*e)[1:] *e = (*e)[0 : l-1] return true } } return false } func i2byte(v ...interface{}) []byte { var b []byte for _, i := range v { switch i.(type) { case byte, int8: b = append(b, i.(byte)) case int: if i.(int) < 256 { b = append(b, byte(i.(int))) } case int16: if i.(int16) < 256 { b = append(b, byte(i.(int16))) } case int32: if i.(int32) < 256 { b = append(b, byte(i.(int32))) } case int64: if i.(int64) < 256 { b = append(b, byte(i.(int64))) } case []byte: b = append(b, i.([]byte)...) case string: b = append(b, i2byte([]byte(i.(string)))...) case []interface{}: for _, ii := range i.([]interface{}) { b = append(b, i2byte(ii)...) } } } return b }