From b986ada275d7682feee761d678f0d79a6c43f75d Mon Sep 17 00:00:00 2001 From: Shulhan Date: Sat, 25 May 2019 05:09:04 +0700 Subject: ini: add method to prune INI variables Pruning the INI variables means removing the empty lines, the comments, and merge section and subsection that have the same name into one group. --- lib/ini/ini.go | 61 +++++++++++++++++++++++++++++++++++++++++++++ lib/ini/ini_example_test.go | 43 ++++++++++++++++++++++++++++++++ lib/ini/section.go | 27 ++++++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/lib/ini/ini.go b/lib/ini/ini.go index 69fe21e1..01807d5b 100644 --- a/lib/ini/ini.go +++ b/lib/ini/ini.go @@ -241,6 +241,67 @@ func (in *Ini) Gets(section, subsection, key string) (out []string) { return } +// +// Prune remove all empty lines, comments, and merge all section and +// subsection with the same name into one group. +// +func (in *Ini) Prune() { + newSecs := make([]*Section, 0, len(in.secs)) + + for _, sec := range in.secs { + if sec.mode == varModeEmpty { + continue + } + newSec := &Section{ + mode: varModeSection, + Name: sec.Name, + NameLower: sec.NameLower, + } + if len(sec.Sub) > 0 { + newSec.mode |= varModeSubsection + newSec.Sub = sec.Sub + } + for _, v := range sec.Vars { + if v.mode == varModeEmpty || v.mode == varModeComment { + continue + } + + newValue := v.Value + if len(v.Value) == 0 { + newValue = "true" + } + + newSec.AddUniqValue(v.Key, newValue) + } + newSecs = mergeSection(newSecs, newSec) + } + + in.secs = newSecs +} + +// +// mergeSection merge a section (and subsection) into slice. +// +func mergeSection(secs []*Section, newSec *Section) []*Section { + for x := 0; x < len(secs); x++ { + if secs[x].NameLower != newSec.NameLower { + continue + } + if secs[x].Sub != newSec.Sub { + continue + } + for _, v := range newSec.Vars { + if v.mode == varModeEmpty || v.mode == varModeComment { + continue + } + secs[x].AddUniqValue(v.KeyLower, v.Value) + } + return secs + } + secs = append(secs, newSec) + return secs +} + // // Save the current parsed Ini into file `filename`. It will overwrite the // destination file if it's exist. diff --git a/lib/ini/ini_example_test.go b/lib/ini/ini_example_test.go index 67c8966f..8ea5efbd 100644 --- a/lib/ini/ini_example_test.go +++ b/lib/ini/ini_example_test.go @@ -63,3 +63,46 @@ key=value3 // section::key2 = [true false] // section:sub:key = [value1 value2 value3] } + +func ExampleIni_Prune() { + input := []byte(` +[section] +key=value1 # comment +key2= ; another comment + +[section "sub"] +key=value1 + +; here is comment on section +[section] +key=value2 +key2=false + +[section "sub"] +key=value2 +key=value1 +`) + + in, err := Parse(input) + if err != nil { + log.Fatal(err) + } + + in.Prune() + + for _, sec := range in.secs { + fmt.Printf("%s", sec) + for _, v := range sec.Vars { + fmt.Printf("%s", v) + } + } + // Output: + // [section] + // key = value1 + // key2 = true + // key = value2 + // key2 = false + // [section "sub"] + // key = value2 + // key = value1 +} diff --git a/lib/ini/section.go b/lib/ini/section.go index bc09cc23..3ac2f542 100644 --- a/lib/ini/section.go +++ b/lib/ini/section.go @@ -172,6 +172,33 @@ func (sec *Section) AddComment(comment string) { sec.add(v) } +// +// AddUniqValue add a new variable with uniq value to section. +// If variable with the same key and value found, that variable will be moved +// to end of list, to make the last declared variable still at the end of +// list. +// +func (sec *Section) AddUniqValue(key, value string) { + keyLower := strings.ToLower(key) + for x := 0; x < len(sec.Vars); x++ { + if sec.Vars[x].KeyLower == keyLower { + if sec.Vars[x].Value == value { + tmp := sec.Vars[x] + sec.Vars = append(sec.Vars[:x], sec.Vars[x+1:]...) + sec.Vars = append(sec.Vars, tmp) + return + } + } + } + v := &Variable{ + mode: varModeValue, + Key: key, + KeyLower: keyLower, + Value: value, + } + sec.Vars = append(sec.Vars, v) +} + // // Unset remove the variable with name `key` on current section. // -- cgit v1.3