diff options
| -rw-r--r-- | simpleconf.go | 168 | 
1 files changed, 168 insertions, 0 deletions
| diff --git a/simpleconf.go b/simpleconf.go new file mode 100644 index 0000000..777cd53 --- /dev/null +++ b/simpleconf.go @@ -0,0 +1,168 @@ +package simpleconf + +import ( +	"bufio" +	"errors" +	"fmt" +	"io" +	"os" +	"strconv" +	"strings" +) + +type Config map[string]Section +type Section map[string]string + +func (c Config) addSection(section Section, name string) { +	if section != nil { +		c[name] = section +	} +} + +func Load(r io.Reader) (config Config, outerr error) { +	config = make(Config) +	scanner := bufio.NewScanner(r) + +	var section Section +	var sectName string + +	for l := 1; scanner.Scan(); l++ { +		line := strings.TrimSpace(scanner.Text()) +		if len(line) == 0 { +			continue +		} + +		switch line[0] { +		case ';', '#': +			continue +		case '[': +			parts := strings.SplitN(line, "[", 2) +			parts = strings.SplitN(parts[1], "]", 2) + +			if len(parts) != 2 { +				return nil, fmt.Errorf("Missing closing ']' in section header at line %d", l) +			} +			if len(parts[1]) != 0 { +				return nil, fmt.Errorf("More data after closing ']' at line %d", l) +			} + +			config.addSection(section, sectName) +			section = make(Section) +		default: +			parts := strings.SplitN(line, "=", 2) +			if len(parts) != 2 { +				return nil, fmt.Errorf("Couldn't neither find a comment, a section header nor a key-value pair at line %d", l) +			} + +			key := strings.TrimSpace(parts[0]) +			val := strings.TrimSpace(parts[1]) +			if len(key) == 0 { +				return nil, fmt.Errorf("Empty key at line %d", l) +			} + +			if section == nil { +				return nil, fmt.Errorf("Found key-value pair, but no section at line %d", l) +			} + +			section[key] = val +		} +	} + +	config.addSection(section, sectName) + +	outerr = scanner.Err() +	return +} + +var ( +	NotFound = errors.New("Section or key not found.") +	NotBool  = errors.New("Could not interpret value as bool.") +) + +func (c Config) GetString(section, key string) (string, error) { +	s, ok := c[section] +	if !ok { +		return "", NotFound +	} +	rv, ok := s[key] +	if !ok { +		return "", NotFound +	} +	return rv, nil +} + +func (c Config) GetStringDefault(d, section, key string) (string, error) { +	rv, err := c.GetString(section, key) +	if err == NotFound { +		return d, nil +	} +	return rv, err +} + +func (c Config) GetInt(section, key string) (int64, error) { +	s, err := c.GetString(section, key) +	if err != nil { +		return 0, err +	} +	return strconv.ParseInt(s, 10, 64) +} + +func (c Config) GetIntDefault(d int64, section, key string) (int64, error) { +	rv, err := c.GetInt(section, key) +	if err == NotFound { +		return d, nil +	} +	return rv, err +} + +func (c Config) GetFloat(section, key string) (float64, error) { +	s, err := c.GetString(section, key) +	if err != nil { +		return 0, err +	} +	return strconv.ParseFloat(s, 64) +} + +func (c Config) GetFloatDefault(d float64, section, key string) (float64, error) { +	rv, err := c.GetFloat(section, key) +	if err == NotFound { +		return d, nil +	} +	return rv, err +} + +func (c Config) GetBool(section, key string) (bool, error) { +	s, err := c.GetString(section, key) +	if err != nil { +		return false, err +	} +	switch strings.ToLower(s) { +	case "true", "on", "yes", "y", "1": +		return true, nil +	case "false", "off", "no", "n", "0": +		return false, nil +	default: +		return false, NotBool +	} +} + +func (c Config) GetBoolDefault(d bool, section, key string) (bool, error) { +	rv, err := c.GetBool(section, key) +	if err == NotFound { +		return d, nil +	} +	return rv, err +} + +func (c Config) GetFile(flag int, perm os.FileMode, section, key string) (*os.File, error) { +	s, err := c.GetString(section, key) +	if err != nil { +		return nil, err +	} + +	return os.OpenFile(s, flag, perm) +} + +func (c Config) GetFileReadonly(section, key string) (*os.File, error) { +	return c.GetFile(os.O_RDONLY, 0, section, key) +} | 
