...

Source file src/gopkg.in/ini.v1/section.go

Documentation: gopkg.in/ini.v1

     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  }
   257  

View as plain text