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