168 lines
3.7 KiB
Go
168 lines
3.7 KiB
Go
package ini
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Ini provides parsing and querying of INI format or simple name/value pairs
|
|
// such as a simple config file.
|
|
// A name/value pair format is just an INI with no sections, and properties can
|
|
// be queried using an empty section name.
|
|
type Ini struct {
|
|
mutex sync.RWMutex
|
|
m map[string]*Section
|
|
lm time.Time
|
|
}
|
|
|
|
// LoadFromFilespec loads an INI file from string containing path and filename.
|
|
func (ini *Ini) LoadFromFilespec(filespec string) error {
|
|
f, err := os.Open(filespec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return ini.LoadFromFile(f)
|
|
}
|
|
|
|
// LoadFromFile loads an INI file from `os.File`.
|
|
func (ini *Ini) LoadFromFile(file *os.File) error {
|
|
|
|
fi, err := file.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lm := fi.ModTime()
|
|
|
|
if err := ini.LoadFromReader(file); err != nil {
|
|
return err
|
|
}
|
|
ini.lm = lm
|
|
return nil
|
|
}
|
|
|
|
// LoadFromReader loads an INI file from an `io.Reader`.
|
|
func (ini *Ini) LoadFromReader(reader io.Reader) error {
|
|
data, err := ioutil.ReadAll(reader)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return ini.LoadFromString(string(data))
|
|
}
|
|
|
|
// LoadFromString parses an INI from a string .
|
|
func (ini *Ini) LoadFromString(s string) error {
|
|
m, err := getSections(s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ini.mutex.Lock()
|
|
ini.m = m
|
|
ini.lm = time.Now()
|
|
ini.mutex.Unlock()
|
|
return nil
|
|
}
|
|
|
|
// GetLastModified returns the last modified timestamp of the
|
|
// INI contents.
|
|
func (ini *Ini) GetLastModified() time.Time {
|
|
return ini.lm
|
|
}
|
|
|
|
// GetSectionNames returns the names of all sections in this INI.
|
|
// Note, the returned section names are a snapshot in time, meaning
|
|
// other goroutines may change the contents of this INI as soon as
|
|
// the method returns.
|
|
func (ini *Ini) GetSectionNames() []string {
|
|
ini.mutex.RLock()
|
|
defer ini.mutex.RUnlock()
|
|
|
|
arr := make([]string, 0, len(ini.m))
|
|
for key := range ini.m {
|
|
arr = append(arr, key)
|
|
}
|
|
return arr
|
|
}
|
|
|
|
// GetKeys returns the names of all keys in the specified section.
|
|
// Note, the returned key names are a snapshot in time, meaning other
|
|
// goroutines may change the contents of this INI as soon as the
|
|
// method returns.
|
|
func (ini *Ini) GetKeys(sectionName string) ([]string, error) {
|
|
sec, err := ini.getSection(sectionName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return sec.getKeys(), nil
|
|
}
|
|
|
|
// getSection returns the named section.
|
|
func (ini *Ini) getSection(sectionName string) (*Section, error) {
|
|
ini.mutex.RLock()
|
|
defer ini.mutex.RUnlock()
|
|
|
|
sec, ok := ini.m[sectionName]
|
|
if !ok {
|
|
return nil, fmt.Errorf("section '%s' not found", sectionName)
|
|
}
|
|
return sec, nil
|
|
}
|
|
|
|
// GetFlattenedKeys returns all section names plus keys as one
|
|
// flattened array.
|
|
func (ini *Ini) GetFlattenedKeys() []string {
|
|
ini.mutex.RLock()
|
|
defer ini.mutex.RUnlock()
|
|
|
|
arr := make([]string, 0, len(ini.m)*2)
|
|
for _, section := range ini.m {
|
|
keys := section.getKeys()
|
|
for _, key := range keys {
|
|
name := section.GetName()
|
|
if name != "" {
|
|
key = name + "." + key
|
|
}
|
|
arr = append(arr, key)
|
|
}
|
|
}
|
|
return arr
|
|
}
|
|
|
|
// GetProp returns the value of the specified key in the named section.
|
|
func (ini *Ini) GetProp(section string, key string) (val string, ok bool) {
|
|
sec, err := ini.getSection(section)
|
|
if err != nil {
|
|
return val, false
|
|
}
|
|
return sec.GetProp(key)
|
|
}
|
|
|
|
// ToMap returns a flattened map of the section name plus keys mapped
|
|
// to values.
|
|
func (ini *Ini) ToMap() map[string]string {
|
|
m := make(map[string]string)
|
|
|
|
ini.mutex.RLock()
|
|
defer ini.mutex.RUnlock()
|
|
|
|
for _, section := range ini.m {
|
|
for _, key := range section.getKeys() {
|
|
val, ok := section.GetProp(key)
|
|
if ok {
|
|
name := section.GetName()
|
|
var mapkey string
|
|
if name != "" {
|
|
mapkey = name + "." + key
|
|
} else {
|
|
mapkey = key
|
|
}
|
|
m[mapkey] = val
|
|
}
|
|
}
|
|
}
|
|
return m
|
|
}
|