section.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Copyright 2014 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 ini
  15. import (
  16. "errors"
  17. "fmt"
  18. "strings"
  19. )
  20. // Section represents a config section.
  21. type Section struct {
  22. f *File
  23. Comment string
  24. name string
  25. keys map[string]*Key
  26. keyList []string
  27. keysHash map[string]string
  28. isRawSection bool
  29. rawBody string
  30. }
  31. func newSection(f *File, name string) *Section {
  32. return &Section{
  33. f: f,
  34. name: name,
  35. keys: make(map[string]*Key),
  36. keyList: make([]string, 0, 10),
  37. keysHash: make(map[string]string),
  38. }
  39. }
  40. // Name returns name of Section.
  41. func (s *Section) Name() string {
  42. return s.name
  43. }
  44. // Body returns rawBody of Section if the section was marked as unparseable.
  45. // It still follows the other rules of the INI format surrounding leading/trailing whitespace.
  46. func (s *Section) Body() string {
  47. return strings.TrimSpace(s.rawBody)
  48. }
  49. // NewKey creates a new key to given section.
  50. func (s *Section) NewKey(name, val string) (*Key, error) {
  51. if len(name) == 0 {
  52. return nil, errors.New("error creating new key: empty key name")
  53. } else if s.f.options.Insensitive {
  54. name = strings.ToLower(name)
  55. }
  56. if s.f.BlockMode {
  57. s.f.lock.Lock()
  58. defer s.f.lock.Unlock()
  59. }
  60. if inSlice(name, s.keyList) {
  61. if s.f.options.AllowShadows {
  62. if err := s.keys[name].addShadow(val); err != nil {
  63. return nil, err
  64. }
  65. } else {
  66. s.keys[name].value = val
  67. }
  68. return s.keys[name], nil
  69. }
  70. s.keyList = append(s.keyList, name)
  71. s.keys[name] = newKey(s, name, val)
  72. s.keysHash[name] = val
  73. return s.keys[name], nil
  74. }
  75. // NewBooleanKey creates a new boolean type key to given section.
  76. func (s *Section) NewBooleanKey(name string) (*Key, error) {
  77. key, err := s.NewKey(name, "true")
  78. if err != nil {
  79. return nil, err
  80. }
  81. key.isBooleanType = true
  82. return key, nil
  83. }
  84. // GetKey returns key in section by given name.
  85. func (s *Section) GetKey(name string) (*Key, error) {
  86. // FIXME: change to section level lock?
  87. if s.f.BlockMode {
  88. s.f.lock.RLock()
  89. }
  90. if s.f.options.Insensitive {
  91. name = strings.ToLower(name)
  92. }
  93. key := s.keys[name]
  94. if s.f.BlockMode {
  95. s.f.lock.RUnlock()
  96. }
  97. if key == nil {
  98. // Check if it is a child-section.
  99. sname := s.name
  100. for {
  101. if i := strings.LastIndex(sname, "."); i > -1 {
  102. sname = sname[:i]
  103. sec, err := s.f.GetSection(sname)
  104. if err != nil {
  105. continue
  106. }
  107. return sec.GetKey(name)
  108. } else {
  109. break
  110. }
  111. }
  112. return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name)
  113. }
  114. return key, nil
  115. }
  116. // HasKey returns true if section contains a key with given name.
  117. func (s *Section) HasKey(name string) bool {
  118. key, _ := s.GetKey(name)
  119. return key != nil
  120. }
  121. // Haskey is a backwards-compatible name for HasKey.
  122. func (s *Section) Haskey(name string) bool {
  123. return s.HasKey(name)
  124. }
  125. // HasValue returns true if section contains given raw value.
  126. func (s *Section) HasValue(value string) bool {
  127. if s.f.BlockMode {
  128. s.f.lock.RLock()
  129. defer s.f.lock.RUnlock()
  130. }
  131. for _, k := range s.keys {
  132. if value == k.value {
  133. return true
  134. }
  135. }
  136. return false
  137. }
  138. // Key assumes named Key exists in section and returns a zero-value when not.
  139. func (s *Section) Key(name string) *Key {
  140. key, err := s.GetKey(name)
  141. if err != nil {
  142. // It's OK here because the only possible error is empty key name,
  143. // but if it's empty, this piece of code won't be executed.
  144. key, _ = s.NewKey(name, "")
  145. return key
  146. }
  147. return key
  148. }
  149. // Keys returns list of keys of section.
  150. func (s *Section) Keys() []*Key {
  151. keys := make([]*Key, len(s.keyList))
  152. for i := range s.keyList {
  153. keys[i] = s.Key(s.keyList[i])
  154. }
  155. return keys
  156. }
  157. // ParentKeys returns list of keys of parent section.
  158. func (s *Section) ParentKeys() []*Key {
  159. var parentKeys []*Key
  160. sname := s.name
  161. for {
  162. if i := strings.LastIndex(sname, "."); i > -1 {
  163. sname = sname[:i]
  164. sec, err := s.f.GetSection(sname)
  165. if err != nil {
  166. continue
  167. }
  168. parentKeys = append(parentKeys, sec.Keys()...)
  169. } else {
  170. break
  171. }
  172. }
  173. return parentKeys
  174. }
  175. // KeyStrings returns list of key names of section.
  176. func (s *Section) KeyStrings() []string {
  177. list := make([]string, len(s.keyList))
  178. copy(list, s.keyList)
  179. return list
  180. }
  181. // KeysHash returns keys hash consisting of names and values.
  182. func (s *Section) KeysHash() map[string]string {
  183. if s.f.BlockMode {
  184. s.f.lock.RLock()
  185. defer s.f.lock.RUnlock()
  186. }
  187. hash := map[string]string{}
  188. for key, value := range s.keysHash {
  189. hash[key] = value
  190. }
  191. return hash
  192. }
  193. // DeleteKey deletes a key from section.
  194. func (s *Section) DeleteKey(name string) {
  195. if s.f.BlockMode {
  196. s.f.lock.Lock()
  197. defer s.f.lock.Unlock()
  198. }
  199. for i, k := range s.keyList {
  200. if k == name {
  201. s.keyList = append(s.keyList[:i], s.keyList[i+1:]...)
  202. delete(s.keys, name)
  203. return
  204. }
  205. }
  206. }
  207. // ChildSections returns a list of child sections of current section.
  208. // For example, "[parent.child1]" and "[parent.child12]" are child sections
  209. // of section "[parent]".
  210. func (s *Section) ChildSections() []*Section {
  211. prefix := s.name + "."
  212. children := make([]*Section, 0, 3)
  213. for _, name := range s.f.sectionList {
  214. if strings.HasPrefix(name, prefix) {
  215. children = append(children, s.f.sections[name])
  216. }
  217. }
  218. return children
  219. }