@ -15,6 +15,7 @@
package ini
package ini
import (
import (
"errors"
"fmt"
"fmt"
"strconv"
"strconv"
"strings"
"strings"
@ -29,9 +30,42 @@ type Key struct {
isAutoIncrement bool
isAutoIncrement bool
isBooleanType bool
isBooleanType bool
isShadow bool
shadows [ ] * Key
Comment string
Comment string
}
}
// newKey simply return a key object with given values.
func newKey ( s * Section , name , val string ) * Key {
return & Key {
s : s ,
name : name ,
value : val ,
}
}
func ( k * Key ) addShadow ( val string ) error {
if k . isShadow {
return errors . New ( "cannot add shadow to another shadow key" )
} else if k . isAutoIncrement || k . isBooleanType {
return errors . New ( "cannot add shadow to auto-increment or boolean key" )
}
shadow := newKey ( k . s , k . name , val )
shadow . isShadow = true
k . shadows = append ( k . shadows , shadow )
return nil
}
// AddShadow adds a new shadow key to itself.
func ( k * Key ) AddShadow ( val string ) error {
if ! k . s . f . options . AllowShadows {
return errors . New ( "shadow key is not allowed" )
}
return k . addShadow ( val )
}
// ValueMapper represents a mapping function for values, e.g. os.ExpandEnv
// ValueMapper represents a mapping function for values, e.g. os.ExpandEnv
type ValueMapper func ( string ) string
type ValueMapper func ( string ) string
@ -45,16 +79,29 @@ func (k *Key) Value() string {
return k . value
return k . value
}
}
// String returns string representation of value.
// ValueWithShadows returns raw values of key and its shadows if any.
func ( k * Key ) String ( ) string {
func ( k * Key ) ValueWithShadows ( ) [ ] string {
val := k . value
if len ( k . shadows ) == 0 {
return [ ] string { k . value }
}
vals := make ( [ ] string , len ( k . shadows ) + 1 )
vals [ 0 ] = k . value
for i := range k . shadows {
vals [ i + 1 ] = k . shadows [ i ] . value
}
return vals
}
// transformValue takes a raw value and transforms to its final string.
func ( k * Key ) transformValue ( val string ) string {
if k . s . f . ValueMapper != nil {
if k . s . f . ValueMapper != nil {
val = k . s . f . ValueMapper ( val )
val = k . s . f . ValueMapper ( val )
}
}
if strings . Index ( val , "%" ) == - 1 {
// Fail-fast if no indicate char found for recursive value
if ! strings . Contains ( val , "%" ) {
return val
return val
}
}
for i := 0 ; i < _DEPTH_VALUES ; i ++ {
for i := 0 ; i < _DEPTH_VALUES ; i ++ {
vr := varPattern . FindString ( val )
vr := varPattern . FindString ( val )
if len ( vr ) == 0 {
if len ( vr ) == 0 {
@ -78,6 +125,11 @@ func (k *Key) String() string {
return val
return val
}
}
// String returns string representation of value.
func ( k * Key ) String ( ) string {
return k . transformValue ( k . value )
}
// Validate accepts a validate function which can
// Validate accepts a validate function which can
// return modifed result as key value.
// return modifed result as key value.
func ( k * Key ) Validate ( fn func ( string ) string ) string {
func ( k * Key ) Validate ( fn func ( string ) string ) string {
@ -394,45 +446,65 @@ func (k *Key) Strings(delim string) []string {
vals := strings . Split ( str , delim )
vals := strings . Split ( str , delim )
for i := range vals {
for i := range vals {
// vals[i] = k.transformValue(strings.TrimSpace(vals[i]))
vals [ i ] = strings . TrimSpace ( vals [ i ] )
vals [ i ] = strings . TrimSpace ( vals [ i ] )
}
}
return vals
return vals
}
}
// StringsWithShadows returns list of string divided by given delimiter.
// Shadows will also be appended if any.
func ( k * Key ) StringsWithShadows ( delim string ) [ ] string {
vals := k . ValueWithShadows ( )
results := make ( [ ] string , 0 , len ( vals ) * 2 )
for i := range vals {
if len ( vals ) == 0 {
continue
}
results = append ( results , strings . Split ( vals [ i ] , delim ) ... )
}
for i := range results {
results [ i ] = k . transformValue ( strings . TrimSpace ( results [ i ] ) )
}
return results
}
// Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value.
// Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value.
func ( k * Key ) Float64s ( delim string ) [ ] float64 {
func ( k * Key ) Float64s ( delim string ) [ ] float64 {
vals , _ := k . getFloat64s ( delim , true , false )
vals , _ := k . parse Float64s( k . Strings ( delim ) , true , false )
return vals
return vals
}
}
// Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value.
// Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value.
func ( k * Key ) Ints ( delim string ) [ ] int {
func ( k * Key ) Ints ( delim string ) [ ] int {
vals , _ := k . getInts ( delim , true , false )
vals , _ := k . parse Ints( k . Strings ( delim ) , true , false )
return vals
return vals
}
}
// Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value.
// Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value.
func ( k * Key ) Int64s ( delim string ) [ ] int64 {
func ( k * Key ) Int64s ( delim string ) [ ] int64 {
vals , _ := k . getInt64s ( delim , true , false )
vals , _ := k . parse Int64s( k . Strings ( delim ) , true , false )
return vals
return vals
}
}
// Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value.
// Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value.
func ( k * Key ) Uints ( delim string ) [ ] uint {
func ( k * Key ) Uints ( delim string ) [ ] uint {
vals , _ := k . get Uints( delim , true , false )
vals , _ := k . parse Uints( k . Strings ( delim ) , true , false )
return vals
return vals
}
}
// Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value.
// Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value.
func ( k * Key ) Uint64s ( delim string ) [ ] uint64 {
func ( k * Key ) Uint64s ( delim string ) [ ] uint64 {
vals , _ := k . get Uint64s( delim , true , false )
vals , _ := k . parse Uint64s( k . Strings ( delim ) , true , false )
return vals
return vals
}
}
// TimesFormat parses with given format and returns list of time.Time divided by given delimiter.
// TimesFormat parses with given format and returns list of time.Time divided by given delimiter.
// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC).
// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC).
func ( k * Key ) TimesFormat ( format , delim string ) [ ] time . Time {
func ( k * Key ) TimesFormat ( format , delim string ) [ ] time . Time {
vals , _ := k . get TimesFormat( format , delim , true , false )
vals , _ := k . parse TimesFormat( format , k . Strings ( delim ) , true , false )
return vals
return vals
}
}
@ -445,41 +517,41 @@ func (k *Key) Times(delim string) []time.Time {
// ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then
// ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then
// it will not be included to result list.
// it will not be included to result list.
func ( k * Key ) ValidFloat64s ( delim string ) [ ] float64 {
func ( k * Key ) ValidFloat64s ( delim string ) [ ] float64 {
vals , _ := k . get Float64s( delim , false , false )
vals , _ := k . parse Float64s( k . Strings ( delim ) , false , false )
return vals
return vals
}
}
// ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will
// ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will
// not be included to result list.
// not be included to result list.
func ( k * Key ) ValidInts ( delim string ) [ ] int {
func ( k * Key ) ValidInts ( delim string ) [ ] int {
vals , _ := k . get Ints( delim , false , false )
vals , _ := k . parse Ints( k . Strings ( delim ) , false , false )
return vals
return vals
}
}
// ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer,
// ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer,
// then it will not be included to result list.
// then it will not be included to result list.
func ( k * Key ) ValidInt64s ( delim string ) [ ] int64 {
func ( k * Key ) ValidInt64s ( delim string ) [ ] int64 {
vals , _ := k . get Int64s( delim , false , false )
vals , _ := k . parse Int64s( k . Strings ( delim ) , false , false )
return vals
return vals
}
}
// ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer,
// ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer,
// then it will not be included to result list.
// then it will not be included to result list.
func ( k * Key ) ValidUints ( delim string ) [ ] uint {
func ( k * Key ) ValidUints ( delim string ) [ ] uint {
vals , _ := k . get Uints( delim , false , false )
vals , _ := k . parse Uints( k . Strings ( delim ) , false , false )
return vals
return vals
}
}
// ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned
// ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned
// integer, then it will not be included to result list.
// integer, then it will not be included to result list.
func ( k * Key ) ValidUint64s ( delim string ) [ ] uint64 {
func ( k * Key ) ValidUint64s ( delim string ) [ ] uint64 {
vals , _ := k . get Uint64s( delim , false , false )
vals , _ := k . parse Uint64s( k . Strings ( delim ) , false , false )
return vals
return vals
}
}
// ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter.
// ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter.
func ( k * Key ) ValidTimesFormat ( format , delim string ) [ ] time . Time {
func ( k * Key ) ValidTimesFormat ( format , delim string ) [ ] time . Time {
vals , _ := k . get TimesFormat( format , delim , false , false )
vals , _ := k . parse TimesFormat( format , k . Strings ( delim ) , false , false )
return vals
return vals
}
}
@ -490,33 +562,33 @@ func (k *Key) ValidTimes(delim string) []time.Time {
// StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input.
// StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input.
func ( k * Key ) StrictFloat64s ( delim string ) ( [ ] float64 , error ) {
func ( k * Key ) StrictFloat64s ( delim string ) ( [ ] float64 , error ) {
return k . get Float64s( delim , false , true )
return k . parse Float64s( k . Strings ( delim ) , false , true )
}
}
// StrictInts returns list of int divided by given delimiter or error on first invalid input.
// StrictInts returns list of int divided by given delimiter or error on first invalid input.
func ( k * Key ) StrictInts ( delim string ) ( [ ] int , error ) {
func ( k * Key ) StrictInts ( delim string ) ( [ ] int , error ) {
return k . get Ints( delim , false , true )
return k . parse Ints( k . Strings ( delim ) , false , true )
}
}
// StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input.
// StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input.
func ( k * Key ) StrictInt64s ( delim string ) ( [ ] int64 , error ) {
func ( k * Key ) StrictInt64s ( delim string ) ( [ ] int64 , error ) {
return k . get Int64s( delim , false , true )
return k . parse Int64s( k . Strings ( delim ) , false , true )
}
}
// StrictUints returns list of uint divided by given delimiter or error on first invalid input.
// StrictUints returns list of uint divided by given delimiter or error on first invalid input.
func ( k * Key ) StrictUints ( delim string ) ( [ ] uint , error ) {
func ( k * Key ) StrictUints ( delim string ) ( [ ] uint , error ) {
return k . get Uints( delim , false , true )
return k . parse Uints( k . Strings ( delim ) , false , true )
}
}
// StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input.
// StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input.
func ( k * Key ) StrictUint64s ( delim string ) ( [ ] uint64 , error ) {
func ( k * Key ) StrictUint64s ( delim string ) ( [ ] uint64 , error ) {
return k . get Uint64s( delim , false , true )
return k . parse Uint64s( k . Strings ( delim ) , false , true )
}
}
// StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter
// StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter
// or error on first invalid input.
// or error on first invalid input.
func ( k * Key ) StrictTimesFormat ( format , delim string ) ( [ ] time . Time , error ) {
func ( k * Key ) StrictTimesFormat ( format , delim string ) ( [ ] time . Time , error ) {
return k . get TimesFormat( format , delim , false , true )
return k . parse TimesFormat( format , k . Strings ( delim ) , false , true )
}
}
// StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter
// StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter
@ -525,9 +597,8 @@ func (k *Key) StrictTimes(delim string) ([]time.Time, error) {
return k . StrictTimesFormat ( time . RFC3339 , delim )
return k . StrictTimesFormat ( time . RFC3339 , delim )
}
}
// getFloat64s returns list of float64 divided by given delimiter.
// parseFloat64s transforms strings to float64s.
func ( k * Key ) getFloat64s ( delim string , addInvalid , returnOnInvalid bool ) ( [ ] float64 , error ) {
func ( k * Key ) parseFloat64s ( strs [ ] string , addInvalid , returnOnInvalid bool ) ( [ ] float64 , error ) {
strs := k . Strings ( delim )
vals := make ( [ ] float64 , 0 , len ( strs ) )
vals := make ( [ ] float64 , 0 , len ( strs ) )
for _ , str := range strs {
for _ , str := range strs {
val , err := strconv . ParseFloat ( str , 64 )
val , err := strconv . ParseFloat ( str , 64 )
@ -541,9 +612,8 @@ func (k *Key) getFloat64s(delim string, addInvalid, returnOnInvalid bool) ([]flo
return vals , nil
return vals , nil
}
}
// getInts returns list of int divided by given delimiter.
// parseInts transforms strings to ints.
func ( k * Key ) getInts ( delim string , addInvalid , returnOnInvalid bool ) ( [ ] int , error ) {
func ( k * Key ) parseInts ( strs [ ] string , addInvalid , returnOnInvalid bool ) ( [ ] int , error ) {
strs := k . Strings ( delim )
vals := make ( [ ] int , 0 , len ( strs ) )
vals := make ( [ ] int , 0 , len ( strs ) )
for _ , str := range strs {
for _ , str := range strs {
val , err := strconv . Atoi ( str )
val , err := strconv . Atoi ( str )
@ -557,9 +627,8 @@ func (k *Key) getInts(delim string, addInvalid, returnOnInvalid bool) ([]int, er
return vals , nil
return vals , nil
}
}
// getInt64s returns list of int64 divided by given delimiter.
// parseInt64s transforms strings to int64s.
func ( k * Key ) getInt64s ( delim string , addInvalid , returnOnInvalid bool ) ( [ ] int64 , error ) {
func ( k * Key ) parseInt64s ( strs [ ] string , addInvalid , returnOnInvalid bool ) ( [ ] int64 , error ) {
strs := k . Strings ( delim )
vals := make ( [ ] int64 , 0 , len ( strs ) )
vals := make ( [ ] int64 , 0 , len ( strs ) )
for _ , str := range strs {
for _ , str := range strs {
val , err := strconv . ParseInt ( str , 10 , 64 )
val , err := strconv . ParseInt ( str , 10 , 64 )
@ -573,9 +642,8 @@ func (k *Key) getInt64s(delim string, addInvalid, returnOnInvalid bool) ([]int64
return vals , nil
return vals , nil
}
}
// getUints returns list of uint divided by given delimiter.
// parseUints transforms strings to uints.
func ( k * Key ) getUints ( delim string , addInvalid , returnOnInvalid bool ) ( [ ] uint , error ) {
func ( k * Key ) parseUints ( strs [ ] string , addInvalid , returnOnInvalid bool ) ( [ ] uint , error ) {
strs := k . Strings ( delim )
vals := make ( [ ] uint , 0 , len ( strs ) )
vals := make ( [ ] uint , 0 , len ( strs ) )
for _ , str := range strs {
for _ , str := range strs {
val , err := strconv . ParseUint ( str , 10 , 0 )
val , err := strconv . ParseUint ( str , 10 , 0 )
@ -589,9 +657,8 @@ func (k *Key) getUints(delim string, addInvalid, returnOnInvalid bool) ([]uint,
return vals , nil
return vals , nil
}
}
// getUint64s returns list of uint64 divided by given delimiter.
// parseUint64s transforms strings to uint64s.
func ( k * Key ) getUint64s ( delim string , addInvalid , returnOnInvalid bool ) ( [ ] uint64 , error ) {
func ( k * Key ) parseUint64s ( strs [ ] string , addInvalid , returnOnInvalid bool ) ( [ ] uint64 , error ) {
strs := k . Strings ( delim )
vals := make ( [ ] uint64 , 0 , len ( strs ) )
vals := make ( [ ] uint64 , 0 , len ( strs ) )
for _ , str := range strs {
for _ , str := range strs {
val , err := strconv . ParseUint ( str , 10 , 64 )
val , err := strconv . ParseUint ( str , 10 , 64 )
@ -605,9 +672,8 @@ func (k *Key) getUint64s(delim string, addInvalid, returnOnInvalid bool) ([]uint
return vals , nil
return vals , nil
}
}
// getTimesFormat parses with given format and returns list of time.Time divided by given delimiter.
// parseTimesFormat transforms strings to times in given format.
func ( k * Key ) getTimesFormat ( format , delim string , addInvalid , returnOnInvalid bool ) ( [ ] time . Time , error ) {
func ( k * Key ) parseTimesFormat ( format string , strs [ ] string , addInvalid , returnOnInvalid bool ) ( [ ] time . Time , error ) {
strs := k . Strings ( delim )
vals := make ( [ ] time . Time , 0 , len ( strs ) )
vals := make ( [ ] time . Time , 0 , len ( strs ) )
for _ , str := range strs {
for _ , str := range strs {
val , err := time . Parse ( format , str )
val , err := time . Parse ( format , str )