1
0
mirror of https://github.com/astaxie/beego.git synced 2024-06-28 10:24:14 +00:00

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")
+	}
This commit is contained in:
astaxie 2013-11-27 23:55:26 +08:00
parent ba5e393e99
commit 63b82c438d
2 changed files with 102 additions and 33 deletions

View File

@ -13,10 +13,14 @@ import (
) )
var ( var (
bComment = []byte{'#'} DEFAULT_SECTION = "DEFAULT"
bEmpty = []byte{} bComment = []byte{'#'}
bEqual = []byte{'='} alterComment = []byte{';'}
bDQuote = []byte{'"'} bEmpty = []byte{}
bEqual = []byte{'='}
bDQuote = []byte{'"'}
sectionStart = []byte{'['}
sectionEnd = []byte{']'}
) )
type IniConfig struct { type IniConfig struct {
@ -32,9 +36,9 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) {
cfg := &IniConfigContainer{ cfg := &IniConfigContainer{
file.Name(), file.Name(),
make(map[int][]string), make(map[string]map[string]string),
make(map[string]string),
make(map[string]string), make(map[string]string),
make(map[string]int64),
sync.RWMutex{}, sync.RWMutex{},
} }
cfg.Lock() cfg.Lock()
@ -43,8 +47,8 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) {
var comment bytes.Buffer var comment bytes.Buffer
buf := bufio.NewReader(file) buf := bufio.NewReader(file)
section := DEFAULT_SECTION
for nComment, off := 0, int64(1); ; { for {
line, _, err := buf.ReadLine() line, _, err := buf.ReadLine()
if err == io.EOF { if err == io.EOF {
break break
@ -52,8 +56,7 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) {
if bytes.Equal(line, bEmpty) { if bytes.Equal(line, bEmpty) {
continue continue
} }
line = bytes.TrimSpace(line)
off += int64(len(line))
if bytes.HasPrefix(line, bComment) { if bytes.HasPrefix(line, bComment) {
line = bytes.TrimLeft(line, "#") line = bytes.TrimLeft(line, "#")
@ -62,63 +65,94 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) {
comment.WriteByte('\n') comment.WriteByte('\n')
continue continue
} }
if comment.Len() != 0 { if bytes.HasPrefix(line, alterComment) {
cfg.comment[nComment] = []string{comment.String()} line = bytes.TrimLeft(line, ";")
comment.Reset() line = bytes.TrimLeftFunc(line, unicode.IsSpace)
nComment++ comment.Write(line)
comment.WriteByte('\n')
continue
}
if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) {
section = string(line[1 : len(line)-1])
if comment.Len() > 0 {
cfg.sectionComment[section] = comment.String()
comment.Reset()
}
if _, ok := cfg.data[section]; !ok {
cfg.data[section] = make(map[string]string)
}
} else {
if _, ok := cfg.data[section]; !ok {
cfg.data[section] = make(map[string]string)
}
keyval := bytes.SplitN(line, bEqual, 2)
val := bytes.TrimSpace(keyval[1])
if bytes.HasPrefix(val, bDQuote) {
val = bytes.Trim(val, `"`)
}
key := string(bytes.TrimSpace(keyval[0]))
cfg.data[section][key] = string(val)
if comment.Len() > 0 {
cfg.keycomment[section+"."+key] = comment.String()
comment.Reset()
}
} }
val := bytes.SplitN(line, bEqual, 2)
if bytes.HasPrefix([]byte(strings.TrimSpace(string(val[1]))), bDQuote) {
val[1] = bytes.Trim([]byte(strings.TrimSpace(string(val[1]))), `"`)
}
key := strings.TrimSpace(string(val[0]))
cfg.comment[nComment-1] = append(cfg.comment[nComment-1], key)
cfg.data[key] = strings.TrimSpace(string(val[1]))
cfg.offset[key] = off
} }
return cfg, nil return cfg, nil
} }
// A Config represents the configuration. // A Config represents the configuration.
type IniConfigContainer struct { type IniConfigContainer struct {
filename string filename string
comment map[int][]string // id: []{comment, key...}; id 1 is for main comment. data map[string]map[string]string //section=> key:val
data map[string]string // key: value sectionComment map[string]string //sction : comment
offset map[string]int64 // key: offset; for editing. keycomment map[string]string // id: []{comment, key...}; id 1 is for main comment.
sync.RWMutex sync.RWMutex
} }
// Bool returns the boolean value for a given key. // Bool returns the boolean value for a given key.
func (c *IniConfigContainer) Bool(key string) (bool, error) { func (c *IniConfigContainer) Bool(key string) (bool, error) {
return strconv.ParseBool(c.data[key]) return strconv.ParseBool(c.getdata(key))
} }
// Int returns the integer value for a given key. // Int returns the integer value for a given key.
func (c *IniConfigContainer) Int(key string) (int, error) { func (c *IniConfigContainer) Int(key string) (int, error) {
return strconv.Atoi(c.data[key]) return strconv.Atoi(c.getdata(key))
} }
func (c *IniConfigContainer) Int64(key string) (int64, error) { func (c *IniConfigContainer) Int64(key string) (int64, error) {
return strconv.ParseInt(c.data[key], 10, 64) return strconv.ParseInt(c.getdata(key), 10, 64)
} }
// Float returns the float value for a given key. // Float returns the float value for a given key.
func (c *IniConfigContainer) Float(key string) (float64, error) { func (c *IniConfigContainer) Float(key string) (float64, error) {
return strconv.ParseFloat(c.data[key], 64) return strconv.ParseFloat(c.getdata(key), 64)
} }
// String returns the string value for a given key. // String returns the string value for a given key.
func (c *IniConfigContainer) String(key string) string { func (c *IniConfigContainer) String(key string) string {
return c.data[key] return c.getdata(key)
} }
// WriteValue writes a new value for key. // WriteValue writes a new value for key.
func (c *IniConfigContainer) Set(key, value string) error { func (c *IniConfigContainer) Set(key, value string) error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
c.data[key] = value if len(key) == 0 {
return errors.New("key is empty")
}
var section, k string
sectionkey := strings.Split(key, ".")
if len(sectionkey) >= 2 {
section = sectionkey[0]
k = sectionkey[1]
} else {
section = DEFAULT_SECTION
k = sectionkey[0]
}
c.data[section][k] = value
return nil return nil
} }
@ -129,6 +163,30 @@ func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) {
return v, errors.New("key not find") return v, errors.New("key not find")
} }
//section.key or key
func (c *IniConfigContainer) getdata(key string) string {
c.RLock()
defer c.RUnlock()
if len(key) == 0 {
return ""
}
var section, k string
sectionkey := strings.Split(key, ".")
if len(sectionkey) >= 2 {
section = sectionkey[0]
k = sectionkey[1]
} else {
section = DEFAULT_SECTION
k = sectionkey[0]
}
if v, ok := c.data[section]; ok {
if vv, o := v[k]; o {
return vv
}
}
return ""
}
func init() { func init() {
Register("ini", &IniConfig{}) Register("ini", &IniConfig{})
} }

View File

@ -6,6 +6,8 @@ import (
) )
var inicontext = ` var inicontext = `
;comment one
#comment two
appname = beeapi appname = beeapi
httpport = 8080 httpport = 8080
mysqlport = 3600 mysqlport = 3600
@ -13,6 +15,9 @@ PI = 3.1415976
runmode = "dev" runmode = "dev"
autorender = false autorender = false
copyrequestbody = true copyrequestbody = true
[demo]
key1="asta"
key2 = "xie"
` `
func TestIni(t *testing.T) { func TestIni(t *testing.T) {
@ -63,4 +68,10 @@ func TestIni(t *testing.T) {
if iniconf.String("name") != "astaxie" { if iniconf.String("name") != "astaxie" {
t.Fatal("get name error") t.Fatal("get name error")
} }
if iniconf.String("demo.key1") != "asta" {
t.Fatal("get demo.key1 error")
}
if iniconf.String("demo.key2") != "xie" {
t.Fatal("get demo.key2 error")
}
} }