conf.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. // Copyright 2013 Unknwon
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. // Package goconfig is a fully functional and comments-support configuration file(.ini) parser.
  15. package goconfig
  16. import (
  17. "fmt"
  18. "regexp"
  19. "runtime"
  20. "strconv"
  21. "strings"
  22. "sync"
  23. )
  24. const (
  25. // Default section name.
  26. DEFAULT_SECTION = "DEFAULT"
  27. // Maximum allowed depth when recursively substituing variable names.
  28. _DEPTH_VALUES = 200
  29. )
  30. type ParseError int
  31. const (
  32. ERR_SECTION_NOT_FOUND ParseError = iota + 1
  33. ERR_KEY_NOT_FOUND
  34. ERR_BLANK_SECTION_NAME
  35. ERR_COULD_NOT_PARSE
  36. )
  37. var LineBreak = "\n"
  38. // Variable regexp pattern: %(variable)s
  39. var varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`)
  40. func init() {
  41. if runtime.GOOS == "windows" {
  42. LineBreak = "\r\n"
  43. }
  44. }
  45. // A ConfigFile represents a INI formar configuration file.
  46. type ConfigFile struct {
  47. lock sync.RWMutex // Go map is not safe.
  48. fileNames []string // Support mutil-files.
  49. data map[string]map[string]string // Section -> key : value
  50. // Lists can keep sections and keys in order.
  51. sectionList []string // Section name list.
  52. keyList map[string][]string // Section -> Key name list
  53. sectionComments map[string]string // Sections comments.
  54. keyComments map[string]map[string]string // Keys comments.
  55. BlockMode bool // Indicates whether use lock or not.
  56. }
  57. // newConfigFile creates an empty configuration representation.
  58. func newConfigFile(fileNames []string) *ConfigFile {
  59. c := new(ConfigFile)
  60. c.fileNames = fileNames
  61. c.data = make(map[string]map[string]string)
  62. c.keyList = make(map[string][]string)
  63. c.sectionComments = make(map[string]string)
  64. c.keyComments = make(map[string]map[string]string)
  65. c.BlockMode = true
  66. return c
  67. }
  68. // SetValue adds a new section-key-value to the configuration.
  69. // It returns true if the key and value were inserted,
  70. // or returns false if the value was overwritten.
  71. // If the section does not exist in advance, it will be created.
  72. func (c *ConfigFile) SetValue(section, key, value string) bool {
  73. // Blank section name represents DEFAULT section.
  74. if len(section) == 0 {
  75. section = DEFAULT_SECTION
  76. }
  77. if len(key) == 0 {
  78. return false
  79. }
  80. if c.BlockMode {
  81. c.lock.Lock()
  82. defer c.lock.Unlock()
  83. }
  84. // Check if section exists.
  85. if _, ok := c.data[section]; !ok {
  86. // Execute add operation.
  87. c.data[section] = make(map[string]string)
  88. // Append section to list.
  89. c.sectionList = append(c.sectionList, section)
  90. }
  91. // Check if key exists.
  92. _, ok := c.data[section][key]
  93. c.data[section][key] = value
  94. if !ok {
  95. // If not exists, append to key list.
  96. c.keyList[section] = append(c.keyList[section], key)
  97. }
  98. return !ok
  99. }
  100. // DeleteKey deletes the key in given section.
  101. // It returns true if the key was deleted,
  102. // or returns false if the section or key didn't exist.
  103. func (c *ConfigFile) DeleteKey(section, key string) bool {
  104. // Blank section name represents DEFAULT section.
  105. if len(section) == 0 {
  106. section = DEFAULT_SECTION
  107. }
  108. if c.BlockMode {
  109. c.lock.Lock()
  110. defer c.lock.Unlock()
  111. }
  112. // Check if section exists.
  113. if _, ok := c.data[section]; !ok {
  114. return false
  115. }
  116. // Check if key exists.
  117. if _, ok := c.data[section][key]; ok {
  118. delete(c.data[section], key)
  119. // Remove comments of key.
  120. c.SetKeyComments(section, key, "")
  121. // Get index of key.
  122. i := 0
  123. for _, keyName := range c.keyList[section] {
  124. if keyName == key {
  125. break
  126. }
  127. i++
  128. }
  129. // Remove from key list.
  130. c.keyList[section] = append(c.keyList[section][:i], c.keyList[section][i+1:]...)
  131. return true
  132. }
  133. return false
  134. }
  135. // GetValue returns the value of key available in the given section.
  136. // If the value needs to be unfolded
  137. // (see e.g. %(google)s example in the GoConfig_test.go),
  138. // then String does this unfolding automatically, up to
  139. // _DEPTH_VALUES number of iterations.
  140. // It returns an error and empty string value if the section does not exist,
  141. // or key does not exist in DEFAULT and current sections.
  142. func (c *ConfigFile) GetValue(section, key string) (string, error) {
  143. if c.BlockMode {
  144. c.lock.RLock()
  145. defer c.lock.RUnlock()
  146. }
  147. // Blank section name represents DEFAULT section.
  148. if len(section) == 0 {
  149. section = DEFAULT_SECTION
  150. }
  151. // Check if section exists
  152. if _, ok := c.data[section]; !ok {
  153. // Section does not exist.
  154. return "", getError{ERR_SECTION_NOT_FOUND, section}
  155. }
  156. // Section exists.
  157. // Check if key exists or empty value.
  158. value, ok := c.data[section][key]
  159. if !ok {
  160. // Check if it is a sub-section.
  161. if i := strings.LastIndex(section, "."); i > -1 {
  162. return c.GetValue(section[:i], key)
  163. }
  164. // Return empty value.
  165. return "", getError{ERR_KEY_NOT_FOUND, key}
  166. }
  167. // Key exists.
  168. var i int
  169. for i = 0; i < _DEPTH_VALUES; i++ {
  170. vr := varPattern.FindString(value)
  171. if len(vr) == 0 {
  172. break
  173. }
  174. // Take off leading '%(' and trailing ')s'.
  175. noption := strings.TrimLeft(vr, "%(")
  176. noption = strings.TrimRight(noption, ")s")
  177. // Search variable in default section.
  178. nvalue, err := c.GetValue(DEFAULT_SECTION, noption)
  179. if err != nil && section != DEFAULT_SECTION {
  180. // Search in the same section.
  181. if _, ok := c.data[section][noption]; ok {
  182. nvalue = c.data[section][noption]
  183. }
  184. }
  185. // Substitute by new value and take off leading '%(' and trailing ')s'.
  186. value = strings.Replace(value, vr, nvalue, -1)
  187. }
  188. return value, nil
  189. }
  190. // Bool returns bool type value.
  191. func (c *ConfigFile) Bool(section, key string) (bool, error) {
  192. value, err := c.GetValue(section, key)
  193. if err != nil {
  194. return false, err
  195. }
  196. return strconv.ParseBool(value)
  197. }
  198. // Float64 returns float64 type value.
  199. func (c *ConfigFile) Float64(section, key string) (float64, error) {
  200. value, err := c.GetValue(section, key)
  201. if err != nil {
  202. return 0.0, err
  203. }
  204. return strconv.ParseFloat(value, 64)
  205. }
  206. // Int returns int type value.
  207. func (c *ConfigFile) Int(section, key string) (int, error) {
  208. value, err := c.GetValue(section, key)
  209. if err != nil {
  210. return 0, err
  211. }
  212. return strconv.Atoi(value)
  213. }
  214. // Int64 returns int64 type value.
  215. func (c *ConfigFile) Int64(section, key string) (int64, error) {
  216. value, err := c.GetValue(section, key)
  217. if err != nil {
  218. return 0, err
  219. }
  220. return strconv.ParseInt(value, 10, 64)
  221. }
  222. // MustValue always returns value without error.
  223. // It returns empty string if error occurs, or the default value if given.
  224. func (c *ConfigFile) MustValue(section, key string, defaultVal ...string) string {
  225. val, err := c.GetValue(section, key)
  226. if len(defaultVal) > 0 && (err != nil || len(val) == 0) {
  227. return defaultVal[0]
  228. }
  229. return val
  230. }
  231. // MustValue always returns value without error,
  232. // It returns empty string if error occurs, or the default value if given,
  233. // and a bool value indicates whether default value is returned.
  234. func (c *ConfigFile) MustValueSet(section, key string, defaultVal ...string) (string, bool) {
  235. val, err := c.GetValue(section, key)
  236. if len(defaultVal) > 0 && (err != nil || len(val) == 0) {
  237. c.SetValue(section, key, defaultVal[0])
  238. return defaultVal[0], true
  239. }
  240. return val, false
  241. }
  242. // MustValueRange always returns value without error,
  243. // it returns default value if error occurs or doesn't fit into range.
  244. func (c *ConfigFile) MustValueRange(section, key, defaultVal string, candidates []string) string {
  245. val, err := c.GetValue(section, key)
  246. if err != nil || len(val) == 0 {
  247. return defaultVal
  248. }
  249. for _, cand := range candidates {
  250. if val == cand {
  251. return val
  252. }
  253. }
  254. return defaultVal
  255. }
  256. // MustValueArray always returns value array without error,
  257. // it returns empty array if error occurs, split by delimiter otherwise.
  258. func (c *ConfigFile) MustValueArray(section, key, delim string) []string {
  259. val, err := c.GetValue(section, key)
  260. if err != nil || len(val) == 0 {
  261. return []string{}
  262. }
  263. vals := strings.Split(val, delim)
  264. for i := range vals {
  265. vals[i] = strings.TrimSpace(vals[i])
  266. }
  267. return vals
  268. }
  269. // MustBool always returns value without error,
  270. // it returns false if error occurs.
  271. func (c *ConfigFile) MustBool(section, key string, defaultVal ...bool) bool {
  272. val, err := c.Bool(section, key)
  273. if len(defaultVal) > 0 && err != nil {
  274. return defaultVal[0]
  275. }
  276. return val
  277. }
  278. // MustFloat64 always returns value without error,
  279. // it returns 0.0 if error occurs.
  280. func (c *ConfigFile) MustFloat64(section, key string, defaultVal ...float64) float64 {
  281. value, err := c.Float64(section, key)
  282. if len(defaultVal) > 0 && err != nil {
  283. return defaultVal[0]
  284. }
  285. return value
  286. }
  287. // MustInt always returns value without error,
  288. // it returns 0 if error occurs.
  289. func (c *ConfigFile) MustInt(section, key string, defaultVal ...int) int {
  290. value, err := c.Int(section, key)
  291. if len(defaultVal) > 0 && err != nil {
  292. return defaultVal[0]
  293. }
  294. return value
  295. }
  296. // MustInt64 always returns value without error,
  297. // it returns 0 if error occurs.
  298. func (c *ConfigFile) MustInt64(section, key string, defaultVal ...int64) int64 {
  299. value, err := c.Int64(section, key)
  300. if len(defaultVal) > 0 && err != nil {
  301. return defaultVal[0]
  302. }
  303. return value
  304. }
  305. // GetSectionList returns the list of all sections
  306. // in the same order in the file.
  307. func (c *ConfigFile) GetSectionList() []string {
  308. list := make([]string, len(c.sectionList))
  309. copy(list, c.sectionList)
  310. return list
  311. }
  312. // GetKeyList returns the list of all keys in give section
  313. // in the same order in the file.
  314. // It returns nil if given section does not exist.
  315. func (c *ConfigFile) GetKeyList(section string) []string {
  316. // Blank section name represents DEFAULT section.
  317. if len(section) == 0 {
  318. section = DEFAULT_SECTION
  319. }
  320. if c.BlockMode {
  321. c.lock.RLock()
  322. defer c.lock.RUnlock()
  323. }
  324. // Check if section exists.
  325. if _, ok := c.data[section]; !ok {
  326. return nil
  327. }
  328. // Non-default section has a blank key as section keeper.
  329. offset := 1
  330. if section == DEFAULT_SECTION {
  331. offset = 0
  332. }
  333. list := make([]string, len(c.keyList[section])-offset)
  334. copy(list, c.keyList[section][offset:])
  335. return list
  336. }
  337. // DeleteSection deletes the entire section by given name.
  338. // It returns true if the section was deleted, and false if the section didn't exist.
  339. func (c *ConfigFile) DeleteSection(section string) bool {
  340. // Blank section name represents DEFAULT section.
  341. if len(section) == 0 {
  342. section = DEFAULT_SECTION
  343. }
  344. if c.BlockMode {
  345. c.lock.Lock()
  346. defer c.lock.Unlock()
  347. }
  348. // Check if section exists.
  349. if _, ok := c.data[section]; !ok {
  350. return false
  351. }
  352. delete(c.data, section)
  353. // Remove comments of section.
  354. c.SetSectionComments(section, "")
  355. // Get index of section.
  356. i := 0
  357. for _, secName := range c.sectionList {
  358. if secName == section {
  359. break
  360. }
  361. i++
  362. }
  363. // Remove from section and key list.
  364. c.sectionList = append(c.sectionList[:i], c.sectionList[i+1:]...)
  365. delete(c.keyList, section)
  366. return true
  367. }
  368. // GetSection returns key-value pairs in given section.
  369. // It section does not exist, returns nil and error.
  370. func (c *ConfigFile) GetSection(section string) (map[string]string, error) {
  371. // Blank section name represents DEFAULT section.
  372. if len(section) == 0 {
  373. section = DEFAULT_SECTION
  374. }
  375. if c.BlockMode {
  376. c.lock.Lock()
  377. defer c.lock.Unlock()
  378. }
  379. // Check if section exists.
  380. if _, ok := c.data[section]; !ok {
  381. // Section does not exist.
  382. return nil, getError{ERR_SECTION_NOT_FOUND, section}
  383. }
  384. // Remove pre-defined key.
  385. secMap := c.data[section]
  386. delete(c.data[section], " ")
  387. // Section exists.
  388. return secMap, nil
  389. }
  390. // SetSectionComments adds new section comments to the configuration.
  391. // If comments are empty(0 length), it will remove its section comments!
  392. // It returns true if the comments were inserted or removed,
  393. // or returns false if the comments were overwritten.
  394. func (c *ConfigFile) SetSectionComments(section, comments string) bool {
  395. // Blank section name represents DEFAULT section.
  396. if len(section) == 0 {
  397. section = DEFAULT_SECTION
  398. }
  399. if len(comments) == 0 {
  400. if _, ok := c.sectionComments[section]; ok {
  401. delete(c.sectionComments, section)
  402. }
  403. // Not exists can be seen as remove.
  404. return true
  405. }
  406. // Check if comments exists.
  407. _, ok := c.sectionComments[section]
  408. if comments[0] != '#' && comments[0] != ';' {
  409. comments = "; " + comments
  410. }
  411. c.sectionComments[section] = comments
  412. return !ok
  413. }
  414. // SetKeyComments adds new section-key comments to the configuration.
  415. // If comments are empty(0 length), it will remove its section-key comments!
  416. // It returns true if the comments were inserted or removed,
  417. // or returns false if the comments were overwritten.
  418. // If the section does not exist in advance, it is created.
  419. func (c *ConfigFile) SetKeyComments(section, key, comments string) bool {
  420. // Blank section name represents DEFAULT section.
  421. if len(section) == 0 {
  422. section = DEFAULT_SECTION
  423. }
  424. // Check if section exists.
  425. if _, ok := c.keyComments[section]; ok {
  426. if len(comments) == 0 {
  427. if _, ok := c.keyComments[section][key]; ok {
  428. delete(c.keyComments[section], key)
  429. }
  430. // Not exists can be seen as remove.
  431. return true
  432. }
  433. } else {
  434. if len(comments) == 0 {
  435. // Not exists can be seen as remove.
  436. return true
  437. } else {
  438. // Execute add operation.
  439. c.keyComments[section] = make(map[string]string)
  440. }
  441. }
  442. // Check if key exists.
  443. _, ok := c.keyComments[section][key]
  444. if comments[0] != '#' && comments[0] != ';' {
  445. comments = "; " + comments
  446. }
  447. c.keyComments[section][key] = comments
  448. return !ok
  449. }
  450. // GetSectionComments returns the comments in the given section.
  451. // It returns an empty string(0 length) if the comments do not exist.
  452. func (c *ConfigFile) GetSectionComments(section string) (comments string) {
  453. // Blank section name represents DEFAULT section.
  454. if len(section) == 0 {
  455. section = DEFAULT_SECTION
  456. }
  457. return c.sectionComments[section]
  458. }
  459. // GetKeyComments returns the comments of key in the given section.
  460. // It returns an empty string(0 length) if the comments do not exist.
  461. func (c *ConfigFile) GetKeyComments(section, key string) (comments string) {
  462. // Blank section name represents DEFAULT section.
  463. if len(section) == 0 {
  464. section = DEFAULT_SECTION
  465. }
  466. if _, ok := c.keyComments[section]; ok {
  467. return c.keyComments[section][key]
  468. }
  469. return ""
  470. }
  471. // getError occurs when get value in configuration file with invalid parameter.
  472. type getError struct {
  473. Reason ParseError
  474. Name string
  475. }
  476. // Error implements Error interface.
  477. func (err getError) Error() string {
  478. switch err.Reason {
  479. case ERR_SECTION_NOT_FOUND:
  480. return fmt.Sprintf("section '%s' not found", err.Name)
  481. case ERR_KEY_NOT_FOUND:
  482. return fmt.Sprintf("key '%s' not found", err.Name)
  483. }
  484. return "invalid get error"
  485. }