You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

toml.go 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. package toml
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "runtime"
  9. "strings"
  10. )
  11. type tomlValue struct {
  12. value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
  13. comment string
  14. commented bool
  15. multiline bool
  16. position Position
  17. }
  18. // Tree is the result of the parsing of a TOML file.
  19. type Tree struct {
  20. values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
  21. comment string
  22. commented bool
  23. inline bool
  24. position Position
  25. }
  26. func newTree() *Tree {
  27. return newTreeWithPosition(Position{})
  28. }
  29. func newTreeWithPosition(pos Position) *Tree {
  30. return &Tree{
  31. values: make(map[string]interface{}),
  32. position: pos,
  33. }
  34. }
  35. // TreeFromMap initializes a new Tree object using the given map.
  36. func TreeFromMap(m map[string]interface{}) (*Tree, error) {
  37. result, err := toTree(m)
  38. if err != nil {
  39. return nil, err
  40. }
  41. return result.(*Tree), nil
  42. }
  43. // Position returns the position of the tree.
  44. func (t *Tree) Position() Position {
  45. return t.position
  46. }
  47. // Has returns a boolean indicating if the given key exists.
  48. func (t *Tree) Has(key string) bool {
  49. if key == "" {
  50. return false
  51. }
  52. return t.HasPath(strings.Split(key, "."))
  53. }
  54. // HasPath returns true if the given path of keys exists, false otherwise.
  55. func (t *Tree) HasPath(keys []string) bool {
  56. return t.GetPath(keys) != nil
  57. }
  58. // Keys returns the keys of the toplevel tree (does not recurse).
  59. func (t *Tree) Keys() []string {
  60. keys := make([]string, len(t.values))
  61. i := 0
  62. for k := range t.values {
  63. keys[i] = k
  64. i++
  65. }
  66. return keys
  67. }
  68. // Get the value at key in the Tree.
  69. // Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
  70. // If you need to retrieve non-bare keys, use GetPath.
  71. // Returns nil if the path does not exist in the tree.
  72. // If keys is of length zero, the current tree is returned.
  73. func (t *Tree) Get(key string) interface{} {
  74. if key == "" {
  75. return t
  76. }
  77. return t.GetPath(strings.Split(key, "."))
  78. }
  79. // GetPath returns the element in the tree indicated by 'keys'.
  80. // If keys is of length zero, the current tree is returned.
  81. func (t *Tree) GetPath(keys []string) interface{} {
  82. if len(keys) == 0 {
  83. return t
  84. }
  85. subtree := t
  86. for _, intermediateKey := range keys[:len(keys)-1] {
  87. value, exists := subtree.values[intermediateKey]
  88. if !exists {
  89. return nil
  90. }
  91. switch node := value.(type) {
  92. case *Tree:
  93. subtree = node
  94. case []*Tree:
  95. // go to most recent element
  96. if len(node) == 0 {
  97. return nil
  98. }
  99. subtree = node[len(node)-1]
  100. default:
  101. return nil // cannot navigate through other node types
  102. }
  103. }
  104. // branch based on final node type
  105. switch node := subtree.values[keys[len(keys)-1]].(type) {
  106. case *tomlValue:
  107. return node.value
  108. default:
  109. return node
  110. }
  111. }
  112. // GetArray returns the value at key in the Tree.
  113. // It returns []string, []int64, etc type if key has homogeneous lists
  114. // Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
  115. // Returns nil if the path does not exist in the tree.
  116. // If keys is of length zero, the current tree is returned.
  117. func (t *Tree) GetArray(key string) interface{} {
  118. if key == "" {
  119. return t
  120. }
  121. return t.GetArrayPath(strings.Split(key, "."))
  122. }
  123. // GetArrayPath returns the element in the tree indicated by 'keys'.
  124. // If keys is of length zero, the current tree is returned.
  125. func (t *Tree) GetArrayPath(keys []string) interface{} {
  126. if len(keys) == 0 {
  127. return t
  128. }
  129. subtree := t
  130. for _, intermediateKey := range keys[:len(keys)-1] {
  131. value, exists := subtree.values[intermediateKey]
  132. if !exists {
  133. return nil
  134. }
  135. switch node := value.(type) {
  136. case *Tree:
  137. subtree = node
  138. case []*Tree:
  139. // go to most recent element
  140. if len(node) == 0 {
  141. return nil
  142. }
  143. subtree = node[len(node)-1]
  144. default:
  145. return nil // cannot navigate through other node types
  146. }
  147. }
  148. // branch based on final node type
  149. switch node := subtree.values[keys[len(keys)-1]].(type) {
  150. case *tomlValue:
  151. switch n := node.value.(type) {
  152. case []interface{}:
  153. return getArray(n)
  154. default:
  155. return node.value
  156. }
  157. default:
  158. return node
  159. }
  160. }
  161. // if homogeneous array, then return slice type object over []interface{}
  162. func getArray(n []interface{}) interface{} {
  163. var s []string
  164. var i64 []int64
  165. var f64 []float64
  166. var bl []bool
  167. for _, value := range n {
  168. switch v := value.(type) {
  169. case string:
  170. s = append(s, v)
  171. case int64:
  172. i64 = append(i64, v)
  173. case float64:
  174. f64 = append(f64, v)
  175. case bool:
  176. bl = append(bl, v)
  177. default:
  178. return n
  179. }
  180. }
  181. if len(s) == len(n) {
  182. return s
  183. } else if len(i64) == len(n) {
  184. return i64
  185. } else if len(f64) == len(n) {
  186. return f64
  187. } else if len(bl) == len(n) {
  188. return bl
  189. }
  190. return n
  191. }
  192. // GetPosition returns the position of the given key.
  193. func (t *Tree) GetPosition(key string) Position {
  194. if key == "" {
  195. return t.position
  196. }
  197. return t.GetPositionPath(strings.Split(key, "."))
  198. }
  199. // SetPositionPath sets the position of element in the tree indicated by 'keys'.
  200. // If keys is of length zero, the current tree position is set.
  201. func (t *Tree) SetPositionPath(keys []string, pos Position) {
  202. if len(keys) == 0 {
  203. t.position = pos
  204. return
  205. }
  206. subtree := t
  207. for _, intermediateKey := range keys[:len(keys)-1] {
  208. value, exists := subtree.values[intermediateKey]
  209. if !exists {
  210. return
  211. }
  212. switch node := value.(type) {
  213. case *Tree:
  214. subtree = node
  215. case []*Tree:
  216. // go to most recent element
  217. if len(node) == 0 {
  218. return
  219. }
  220. subtree = node[len(node)-1]
  221. default:
  222. return
  223. }
  224. }
  225. // branch based on final node type
  226. switch node := subtree.values[keys[len(keys)-1]].(type) {
  227. case *tomlValue:
  228. node.position = pos
  229. return
  230. case *Tree:
  231. node.position = pos
  232. return
  233. case []*Tree:
  234. // go to most recent element
  235. if len(node) == 0 {
  236. return
  237. }
  238. node[len(node)-1].position = pos
  239. return
  240. }
  241. }
  242. // GetPositionPath returns the element in the tree indicated by 'keys'.
  243. // If keys is of length zero, the current tree is returned.
  244. func (t *Tree) GetPositionPath(keys []string) Position {
  245. if len(keys) == 0 {
  246. return t.position
  247. }
  248. subtree := t
  249. for _, intermediateKey := range keys[:len(keys)-1] {
  250. value, exists := subtree.values[intermediateKey]
  251. if !exists {
  252. return Position{0, 0}
  253. }
  254. switch node := value.(type) {
  255. case *Tree:
  256. subtree = node
  257. case []*Tree:
  258. // go to most recent element
  259. if len(node) == 0 {
  260. return Position{0, 0}
  261. }
  262. subtree = node[len(node)-1]
  263. default:
  264. return Position{0, 0}
  265. }
  266. }
  267. // branch based on final node type
  268. switch node := subtree.values[keys[len(keys)-1]].(type) {
  269. case *tomlValue:
  270. return node.position
  271. case *Tree:
  272. return node.position
  273. case []*Tree:
  274. // go to most recent element
  275. if len(node) == 0 {
  276. return Position{0, 0}
  277. }
  278. return node[len(node)-1].position
  279. default:
  280. return Position{0, 0}
  281. }
  282. }
  283. // GetDefault works like Get but with a default value
  284. func (t *Tree) GetDefault(key string, def interface{}) interface{} {
  285. val := t.Get(key)
  286. if val == nil {
  287. return def
  288. }
  289. return val
  290. }
  291. // SetOptions arguments are supplied to the SetWithOptions and SetPathWithOptions functions to modify marshalling behaviour.
  292. // The default values within the struct are valid default options.
  293. type SetOptions struct {
  294. Comment string
  295. Commented bool
  296. Multiline bool
  297. }
  298. // SetWithOptions is the same as Set, but allows you to provide formatting
  299. // instructions to the key, that will be used by Marshal().
  300. func (t *Tree) SetWithOptions(key string, opts SetOptions, value interface{}) {
  301. t.SetPathWithOptions(strings.Split(key, "."), opts, value)
  302. }
  303. // SetPathWithOptions is the same as SetPath, but allows you to provide
  304. // formatting instructions to the key, that will be reused by Marshal().
  305. func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interface{}) {
  306. subtree := t
  307. for i, intermediateKey := range keys[:len(keys)-1] {
  308. nextTree, exists := subtree.values[intermediateKey]
  309. if !exists {
  310. nextTree = newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
  311. subtree.values[intermediateKey] = nextTree // add new element here
  312. }
  313. switch node := nextTree.(type) {
  314. case *Tree:
  315. subtree = node
  316. case []*Tree:
  317. // go to most recent element
  318. if len(node) == 0 {
  319. // create element if it does not exist
  320. node = append(node, newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col}))
  321. subtree.values[intermediateKey] = node
  322. }
  323. subtree = node[len(node)-1]
  324. }
  325. }
  326. var toInsert interface{}
  327. switch v := value.(type) {
  328. case *Tree:
  329. v.comment = opts.Comment
  330. v.commented = opts.Commented
  331. toInsert = value
  332. case []*Tree:
  333. for i := range v {
  334. v[i].commented = opts.Commented
  335. }
  336. toInsert = value
  337. case *tomlValue:
  338. v.comment = opts.Comment
  339. v.commented = opts.Commented
  340. v.multiline = opts.Multiline
  341. toInsert = v
  342. default:
  343. toInsert = &tomlValue{value: value,
  344. comment: opts.Comment,
  345. commented: opts.Commented,
  346. multiline: opts.Multiline,
  347. position: Position{Line: subtree.position.Line + len(subtree.values) + 1, Col: subtree.position.Col}}
  348. }
  349. subtree.values[keys[len(keys)-1]] = toInsert
  350. }
  351. // Set an element in the tree.
  352. // Key is a dot-separated path (e.g. a.b.c).
  353. // Creates all necessary intermediate trees, if needed.
  354. func (t *Tree) Set(key string, value interface{}) {
  355. t.SetWithComment(key, "", false, value)
  356. }
  357. // SetWithComment is the same as Set, but allows you to provide comment
  358. // information to the key, that will be reused by Marshal().
  359. func (t *Tree) SetWithComment(key string, comment string, commented bool, value interface{}) {
  360. t.SetPathWithComment(strings.Split(key, "."), comment, commented, value)
  361. }
  362. // SetPath sets an element in the tree.
  363. // Keys is an array of path elements (e.g. {"a","b","c"}).
  364. // Creates all necessary intermediate trees, if needed.
  365. func (t *Tree) SetPath(keys []string, value interface{}) {
  366. t.SetPathWithComment(keys, "", false, value)
  367. }
  368. // SetPathWithComment is the same as SetPath, but allows you to provide comment
  369. // information to the key, that will be reused by Marshal().
  370. func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool, value interface{}) {
  371. t.SetPathWithOptions(keys, SetOptions{Comment: comment, Commented: commented}, value)
  372. }
  373. // Delete removes a key from the tree.
  374. // Key is a dot-separated path (e.g. a.b.c).
  375. func (t *Tree) Delete(key string) error {
  376. keys, err := parseKey(key)
  377. if err != nil {
  378. return err
  379. }
  380. return t.DeletePath(keys)
  381. }
  382. // DeletePath removes a key from the tree.
  383. // Keys is an array of path elements (e.g. {"a","b","c"}).
  384. func (t *Tree) DeletePath(keys []string) error {
  385. keyLen := len(keys)
  386. if keyLen == 1 {
  387. delete(t.values, keys[0])
  388. return nil
  389. }
  390. tree := t.GetPath(keys[:keyLen-1])
  391. item := keys[keyLen-1]
  392. switch node := tree.(type) {
  393. case *Tree:
  394. delete(node.values, item)
  395. return nil
  396. }
  397. return errors.New("no such key to delete")
  398. }
  399. // createSubTree takes a tree and a key and create the necessary intermediate
  400. // subtrees to create a subtree at that point. In-place.
  401. //
  402. // e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b]
  403. // and tree[a][b][c]
  404. //
  405. // Returns nil on success, error object on failure
  406. func (t *Tree) createSubTree(keys []string, pos Position) error {
  407. subtree := t
  408. for i, intermediateKey := range keys {
  409. nextTree, exists := subtree.values[intermediateKey]
  410. if !exists {
  411. tree := newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
  412. tree.position = pos
  413. tree.inline = subtree.inline
  414. subtree.values[intermediateKey] = tree
  415. nextTree = tree
  416. }
  417. switch node := nextTree.(type) {
  418. case []*Tree:
  419. subtree = node[len(node)-1]
  420. case *Tree:
  421. subtree = node
  422. default:
  423. return fmt.Errorf("unknown type for path %s (%s): %T (%#v)",
  424. strings.Join(keys, "."), intermediateKey, nextTree, nextTree)
  425. }
  426. }
  427. return nil
  428. }
  429. // LoadBytes creates a Tree from a []byte.
  430. func LoadBytes(b []byte) (tree *Tree, err error) {
  431. defer func() {
  432. if r := recover(); r != nil {
  433. if _, ok := r.(runtime.Error); ok {
  434. panic(r)
  435. }
  436. err = errors.New(r.(string))
  437. }
  438. }()
  439. if len(b) >= 4 && (hasUTF32BigEndianBOM4(b) || hasUTF32LittleEndianBOM4(b)) {
  440. b = b[4:]
  441. } else if len(b) >= 3 && hasUTF8BOM3(b) {
  442. b = b[3:]
  443. } else if len(b) >= 2 && (hasUTF16BigEndianBOM2(b) || hasUTF16LittleEndianBOM2(b)) {
  444. b = b[2:]
  445. }
  446. tree = parseToml(lexToml(b))
  447. return
  448. }
  449. func hasUTF16BigEndianBOM2(b []byte) bool {
  450. return b[0] == 0xFE && b[1] == 0xFF
  451. }
  452. func hasUTF16LittleEndianBOM2(b []byte) bool {
  453. return b[0] == 0xFF && b[1] == 0xFE
  454. }
  455. func hasUTF8BOM3(b []byte) bool {
  456. return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
  457. }
  458. func hasUTF32BigEndianBOM4(b []byte) bool {
  459. return b[0] == 0x00 && b[1] == 0x00 && b[2] == 0xFE && b[3] == 0xFF
  460. }
  461. func hasUTF32LittleEndianBOM4(b []byte) bool {
  462. return b[0] == 0xFF && b[1] == 0xFE && b[2] == 0x00 && b[3] == 0x00
  463. }
  464. // LoadReader creates a Tree from any io.Reader.
  465. func LoadReader(reader io.Reader) (tree *Tree, err error) {
  466. inputBytes, err := ioutil.ReadAll(reader)
  467. if err != nil {
  468. return
  469. }
  470. tree, err = LoadBytes(inputBytes)
  471. return
  472. }
  473. // Load creates a Tree from a string.
  474. func Load(content string) (tree *Tree, err error) {
  475. return LoadBytes([]byte(content))
  476. }
  477. // LoadFile creates a Tree from a file.
  478. func LoadFile(path string) (tree *Tree, err error) {
  479. file, err := os.Open(path)
  480. if err != nil {
  481. return nil, err
  482. }
  483. defer file.Close()
  484. return LoadReader(file)
  485. }