@@ 0,0 1,32 @@
+package ini
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "strings"
+)
+
+type Tree map[string]map[string]string
+
+func Parse(r io.Reader) (Tree, error) {
+ t := make(Tree)
+ var section string
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ s := strings.TrimSpace(scanner.Text())
+ switch {
+ case len(s) > 0 && s[0] == ';': // comment
+ continue
+ case len(s) > 1 && s[0] == '[' && s[len(s)-1] == ']': // section header
+ section = s[1 : len(s)-1]
+ t[section] = make(map[string]string)
+ case strings.Index(s, "=") != -1: // key-value pair
+ if t[section] == nil {
+ return nil, errors.New("need section header before key-value pair")
+ }
+ t[section][s[:strings.Index(s, "=")]] = s[strings.Index(s, "=")+1:]
+ }
+ }
+ return t, scanner.Err()
+}
No newline at end of file
@@ 0,0 1,57 @@
+package ini
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var tests = []struct {
+ input string
+ want Tree
+ wantError bool
+}{
+ {"", make(Tree), false},
+ {"; comment", make(Tree), false},
+ {" ", make(Tree), false},
+ {"[] ", func() Tree { t := make(Tree, 1); t[""] = make(map[string]string); return t }(), false},
+ {"=", nil, true},
+ {"; =", make(Tree), true},
+ {"[section]", func() Tree { t := make(Tree); t["section"] = make(map[string]string); return t }(), false},
+ {"[person]\nname=John", func() Tree {
+ t := make(Tree)
+ p := make(map[string]string)
+ p["name"] = "John"
+ t["person"] = p
+ return t
+ }(), false},
+ {`[dmr]
+first name=Dennis
+last name=Ritchie
+
+[ken]
+first name=Kenneth
+last name=Thompson`, func() Tree {
+ t := make(Tree)
+ dmr := make(map[string]string)
+ dmr["first name"] = "Dennis"
+ dmr["last name"] = "Ritchie"
+ t["dmr"] = dmr
+ ken := make(map[string]string)
+ ken["first name"] = "Kenneth"
+ ken["last name"] = "Thompson"
+ t["ken"] = ken
+ return t
+ }(), false},
+}
+
+func TestParse(t *testing.T) {
+ for i, tc := range tests {
+ r := strings.NewReader(tc.input)
+ got, gotErr := Parse(r)
+ if !reflect.DeepEqual(got, tc.want) {
+ t.Errorf("%d: got %v, wanted %v; error: %v", i, got, tc.want, gotErr)
+ }
+ _ = gotErr
+ }
+}