aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2019-05-25 05:09:04 +0700
committerShulhan <ms@kilabit.info>2019-05-25 05:24:25 +0700
commitb986ada275d7682feee761d678f0d79a6c43f75d (patch)
treeacb8726f8bb71e47e4a45fd5594fd8c1901995de
parent3df89617c363d3dc89b3afdd59c11324fd0174c5 (diff)
downloadpakakeh.go-b986ada275d7682feee761d678f0d79a6c43f75d.tar.xz
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.
-rw-r--r--lib/ini/ini.go61
-rw-r--r--lib/ini/ini_example_test.go43
-rw-r--r--lib/ini/section.go27
3 files changed, 131 insertions, 0 deletions
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
@@ -242,6 +242,67 @@ func (in *Ini) Gets(section, subsection, key string) (out []string) {
}
//
+// 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
@@ -173,6 +173,33 @@ func (sec *Section) AddComment(comment string) {
}
//
+// 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.
//
// If key is empty, no variable will be removed, and it will return true.