63b82c43 by astaxie

support section

if iniconf.String("demo.key1") != "asta" {
+		t.Fatal("get demo.key1 error")
+	}
+	if iniconf.String("demo.key2") != "xie" {
+		t.Fatal("get demo.key2 error")
+	}
1 parent ba5e393e
...@@ -13,10 +13,14 @@ import ( ...@@ -13,10 +13,14 @@ import (
13 ) 13 )
14 14
15 var ( 15 var (
16 bComment = []byte{'#'} 16 DEFAULT_SECTION = "DEFAULT"
17 bEmpty = []byte{} 17 bComment = []byte{'#'}
18 bEqual = []byte{'='} 18 alterComment = []byte{';'}
19 bDQuote = []byte{'"'} 19 bEmpty = []byte{}
20 bEqual = []byte{'='}
21 bDQuote = []byte{'"'}
22 sectionStart = []byte{'['}
23 sectionEnd = []byte{']'}
20 ) 24 )
21 25
22 type IniConfig struct { 26 type IniConfig struct {
...@@ -32,9 +36,9 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) { ...@@ -32,9 +36,9 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) {
32 36
33 cfg := &IniConfigContainer{ 37 cfg := &IniConfigContainer{
34 file.Name(), 38 file.Name(),
35 make(map[int][]string), 39 make(map[string]map[string]string),
40 make(map[string]string),
36 make(map[string]string), 41 make(map[string]string),
37 make(map[string]int64),
38 sync.RWMutex{}, 42 sync.RWMutex{},
39 } 43 }
40 cfg.Lock() 44 cfg.Lock()
...@@ -43,8 +47,8 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) { ...@@ -43,8 +47,8 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) {
43 47
44 var comment bytes.Buffer 48 var comment bytes.Buffer
45 buf := bufio.NewReader(file) 49 buf := bufio.NewReader(file)
46 50 section := DEFAULT_SECTION
47 for nComment, off := 0, int64(1); ; { 51 for {
48 line, _, err := buf.ReadLine() 52 line, _, err := buf.ReadLine()
49 if err == io.EOF { 53 if err == io.EOF {
50 break 54 break
...@@ -52,8 +56,7 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) { ...@@ -52,8 +56,7 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) {
52 if bytes.Equal(line, bEmpty) { 56 if bytes.Equal(line, bEmpty) {
53 continue 57 continue
54 } 58 }
55 59 line = bytes.TrimSpace(line)
56 off += int64(len(line))
57 60
58 if bytes.HasPrefix(line, bComment) { 61 if bytes.HasPrefix(line, bComment) {
59 line = bytes.TrimLeft(line, "#") 62 line = bytes.TrimLeft(line, "#")
...@@ -62,63 +65,94 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) { ...@@ -62,63 +65,94 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) {
62 comment.WriteByte('\n') 65 comment.WriteByte('\n')
63 continue 66 continue
64 } 67 }
65 if comment.Len() != 0 { 68 if bytes.HasPrefix(line, alterComment) {
66 cfg.comment[nComment] = []string{comment.String()} 69 line = bytes.TrimLeft(line, ";")
67 comment.Reset() 70 line = bytes.TrimLeftFunc(line, unicode.IsSpace)
68 nComment++ 71 comment.Write(line)
72 comment.WriteByte('\n')
73 continue
69 } 74 }
70 75 if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) {
71 val := bytes.SplitN(line, bEqual, 2) 76 section = string(line[1 : len(line)-1])
72 if bytes.HasPrefix([]byte(strings.TrimSpace(string(val[1]))), bDQuote) { 77 if comment.Len() > 0 {
73 val[1] = bytes.Trim([]byte(strings.TrimSpace(string(val[1]))), `"`) 78 cfg.sectionComment[section] = comment.String()
79 comment.Reset()
80 }
81 if _, ok := cfg.data[section]; !ok {
82 cfg.data[section] = make(map[string]string)
83 }
84 } else {
85 if _, ok := cfg.data[section]; !ok {
86 cfg.data[section] = make(map[string]string)
87 }
88 keyval := bytes.SplitN(line, bEqual, 2)
89 val := bytes.TrimSpace(keyval[1])
90 if bytes.HasPrefix(val, bDQuote) {
91 val = bytes.Trim(val, `"`)
92 }
93
94 key := string(bytes.TrimSpace(keyval[0]))
95 cfg.data[section][key] = string(val)
96 if comment.Len() > 0 {
97 cfg.keycomment[section+"."+key] = comment.String()
98 comment.Reset()
99 }
74 } 100 }
75 101
76 key := strings.TrimSpace(string(val[0]))
77 cfg.comment[nComment-1] = append(cfg.comment[nComment-1], key)
78 cfg.data[key] = strings.TrimSpace(string(val[1]))
79 cfg.offset[key] = off
80 } 102 }
81 return cfg, nil 103 return cfg, nil
82 } 104 }
83 105
84 // A Config represents the configuration. 106 // A Config represents the configuration.
85 type IniConfigContainer struct { 107 type IniConfigContainer struct {
86 filename string 108 filename string
87 comment map[int][]string // id: []{comment, key...}; id 1 is for main comment. 109 data map[string]map[string]string //section=> key:val
88 data map[string]string // key: value 110 sectionComment map[string]string //sction : comment
89 offset map[string]int64 // key: offset; for editing. 111 keycomment map[string]string // id: []{comment, key...}; id 1 is for main comment.
90 sync.RWMutex 112 sync.RWMutex
91 } 113 }
92 114
93 // Bool returns the boolean value for a given key. 115 // Bool returns the boolean value for a given key.
94 func (c *IniConfigContainer) Bool(key string) (bool, error) { 116 func (c *IniConfigContainer) Bool(key string) (bool, error) {
95 return strconv.ParseBool(c.data[key]) 117 return strconv.ParseBool(c.getdata(key))
96 } 118 }
97 119
98 // Int returns the integer value for a given key. 120 // Int returns the integer value for a given key.
99 func (c *IniConfigContainer) Int(key string) (int, error) { 121 func (c *IniConfigContainer) Int(key string) (int, error) {
100 return strconv.Atoi(c.data[key]) 122 return strconv.Atoi(c.getdata(key))
101 } 123 }
102 124
103 func (c *IniConfigContainer) Int64(key string) (int64, error) { 125 func (c *IniConfigContainer) Int64(key string) (int64, error) {
104 return strconv.ParseInt(c.data[key], 10, 64) 126 return strconv.ParseInt(c.getdata(key), 10, 64)
105 } 127 }
106 128
107 // Float returns the float value for a given key. 129 // Float returns the float value for a given key.
108 func (c *IniConfigContainer) Float(key string) (float64, error) { 130 func (c *IniConfigContainer) Float(key string) (float64, error) {
109 return strconv.ParseFloat(c.data[key], 64) 131 return strconv.ParseFloat(c.getdata(key), 64)
110 } 132 }
111 133
112 // String returns the string value for a given key. 134 // String returns the string value for a given key.
113 func (c *IniConfigContainer) String(key string) string { 135 func (c *IniConfigContainer) String(key string) string {
114 return c.data[key] 136 return c.getdata(key)
115 } 137 }
116 138
117 // WriteValue writes a new value for key. 139 // WriteValue writes a new value for key.
118 func (c *IniConfigContainer) Set(key, value string) error { 140 func (c *IniConfigContainer) Set(key, value string) error {
119 c.Lock() 141 c.Lock()
120 defer c.Unlock() 142 defer c.Unlock()
121 c.data[key] = value 143 if len(key) == 0 {
144 return errors.New("key is empty")
145 }
146 var section, k string
147 sectionkey := strings.Split(key, ".")
148 if len(sectionkey) >= 2 {
149 section = sectionkey[0]
150 k = sectionkey[1]
151 } else {
152 section = DEFAULT_SECTION
153 k = sectionkey[0]
154 }
155 c.data[section][k] = value
122 return nil 156 return nil
123 } 157 }
124 158
...@@ -129,6 +163,30 @@ func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) { ...@@ -129,6 +163,30 @@ func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) {
129 return v, errors.New("key not find") 163 return v, errors.New("key not find")
130 } 164 }
131 165
166 //section.key or key
167 func (c *IniConfigContainer) getdata(key string) string {
168 c.RLock()
169 defer c.RUnlock()
170 if len(key) == 0 {
171 return ""
172 }
173 var section, k string
174 sectionkey := strings.Split(key, ".")
175 if len(sectionkey) >= 2 {
176 section = sectionkey[0]
177 k = sectionkey[1]
178 } else {
179 section = DEFAULT_SECTION
180 k = sectionkey[0]
181 }
182 if v, ok := c.data[section]; ok {
183 if vv, o := v[k]; o {
184 return vv
185 }
186 }
187 return ""
188 }
189
132 func init() { 190 func init() {
133 Register("ini", &IniConfig{}) 191 Register("ini", &IniConfig{})
134 } 192 }
......
...@@ -6,6 +6,8 @@ import ( ...@@ -6,6 +6,8 @@ import (
6 ) 6 )
7 7
8 var inicontext = ` 8 var inicontext = `
9 ;comment one
10 #comment two
9 appname = beeapi 11 appname = beeapi
10 httpport = 8080 12 httpport = 8080
11 mysqlport = 3600 13 mysqlport = 3600
...@@ -13,6 +15,9 @@ PI = 3.1415976 ...@@ -13,6 +15,9 @@ PI = 3.1415976
13 runmode = "dev" 15 runmode = "dev"
14 autorender = false 16 autorender = false
15 copyrequestbody = true 17 copyrequestbody = true
18 [demo]
19 key1="asta"
20 key2 = "xie"
16 ` 21 `
17 22
18 func TestIni(t *testing.T) { 23 func TestIni(t *testing.T) {
...@@ -63,4 +68,10 @@ func TestIni(t *testing.T) { ...@@ -63,4 +68,10 @@ func TestIni(t *testing.T) {
63 if iniconf.String("name") != "astaxie" { 68 if iniconf.String("name") != "astaxie" {
64 t.Fatal("get name error") 69 t.Fatal("get name error")
65 } 70 }
71 if iniconf.String("demo.key1") != "asta" {
72 t.Fatal("get demo.key1 error")
73 }
74 if iniconf.String("demo.key2") != "xie" {
75 t.Fatal("get demo.key2 error")
76 }
66 } 77 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!