1package ini 2 3import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "os" 8 "sync" 9 "time" 10) 11 12// Ini provides parsing and querying of INI format or simple name/value pairs 13// such as a simple config file. 14// A name/value pair format is just an INI with no sections, and properties can 15// be queried using an empty section name. 16type Ini struct { 17 mutex sync.RWMutex 18 m map[string]*Section 19 lm time.Time 20} 21 22// LoadFromFilespec loads an INI file from string containing path and filename. 23func (ini *Ini) LoadFromFilespec(filespec string) error { 24 f, err := os.Open(filespec) 25 if err != nil { 26 return err 27 } 28 return ini.LoadFromFile(f) 29} 30 31// LoadFromFile loads an INI file from `os.File`. 32func (ini *Ini) LoadFromFile(file *os.File) error { 33 34 fi, err := file.Stat() 35 if err != nil { 36 return err 37 } 38 lm := fi.ModTime() 39 40 if err := ini.LoadFromReader(file); err != nil { 41 return err 42 } 43 ini.lm = lm 44 return nil 45} 46 47// LoadFromReader loads an INI file from an `io.Reader`. 48func (ini *Ini) LoadFromReader(reader io.Reader) error { 49 data, err := ioutil.ReadAll(reader) 50 if err != nil { 51 return err 52 } 53 return ini.LoadFromString(string(data)) 54} 55 56// LoadFromString parses an INI from a string . 57func (ini *Ini) LoadFromString(s string) error { 58 m, err := getSections(s) 59 if err != nil { 60 return err 61 } 62 ini.mutex.Lock() 63 ini.m = m 64 ini.lm = time.Now() 65 ini.mutex.Unlock() 66 return nil 67} 68 69// GetLastModified returns the last modified timestamp of the 70// INI contents. 71func (ini *Ini) GetLastModified() time.Time { 72 return ini.lm 73} 74 75// GetSectionNames returns the names of all sections in this INI. 76// Note, the returned section names are a snapshot in time, meaning 77// other goroutines may change the contents of this INI as soon as 78// the method returns. 79func (ini *Ini) GetSectionNames() []string { 80 ini.mutex.RLock() 81 defer ini.mutex.RUnlock() 82 83 arr := make([]string, 0, len(ini.m)) 84 for key := range ini.m { 85 arr = append(arr, key) 86 } 87 return arr 88} 89 90// GetKeys returns the names of all keys in the specified section. 91// Note, the returned key names are a snapshot in time, meaning other 92// goroutines may change the contents of this INI as soon as the 93// method returns. 94func (ini *Ini) GetKeys(sectionName string) ([]string, error) { 95 sec, err := ini.getSection(sectionName) 96 if err != nil { 97 return nil, err 98 } 99 return sec.getKeys(), nil 100} 101 102// getSection returns the named section. 103func (ini *Ini) getSection(sectionName string) (*Section, error) { 104 ini.mutex.RLock() 105 defer ini.mutex.RUnlock() 106 107 sec, ok := ini.m[sectionName] 108 if !ok { 109 return nil, fmt.Errorf("section '%s' not found", sectionName) 110 } 111 return sec, nil 112} 113 114// GetFlattenedKeys returns all section names plus keys as one 115// flattened array. 116func (ini *Ini) GetFlattenedKeys() []string { 117 ini.mutex.RLock() 118 defer ini.mutex.RUnlock() 119 120 arr := make([]string, 0, len(ini.m)*2) 121 for _, section := range ini.m { 122 keys := section.getKeys() 123 for _, key := range keys { 124 name := section.GetName() 125 if name != "" { 126 key = name + "." + key 127 } 128 arr = append(arr, key) 129 } 130 } 131 return arr 132} 133 134// GetProp returns the value of the specified key in the named section. 135func (ini *Ini) GetProp(section string, key string) (val string, ok bool) { 136 sec, err := ini.getSection(section) 137 if err != nil { 138 return val, false 139 } 140 return sec.GetProp(key) 141} 142 143// ToMap returns a flattened map of the section name plus keys mapped 144// to values. 145func (ini *Ini) ToMap() map[string]string { 146 m := make(map[string]string) 147 148 ini.mutex.RLock() 149 defer ini.mutex.RUnlock() 150 151 for _, section := range ini.m { 152 for _, key := range section.getKeys() { 153 val, ok := section.GetProp(key) 154 if ok { 155 name := section.GetName() 156 var mapkey string 157 if name != "" { 158 mapkey = name + "." + key 159 } else { 160 mapkey = key 161 } 162 m[mapkey] = val 163 } 164 } 165 } 166 return m 167} 168