leobot

Simple Telegram Logging Bot
git clone git://bsandro.tech/leobot
Log | Files | Refs | README | LICENSE

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 }