ini.go (8051B)
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 provides INI file read and write functionality in Go. 16 package ini 17 18 import ( 19 "os" 20 "regexp" 21 "runtime" 22 "strings" 23 ) 24 25 const ( 26 // Maximum allowed depth when recursively substituing variable names. 27 depthValues = 99 28 ) 29 30 var ( 31 // DefaultSection is the name of default section. You can use this var or the string literal. 32 // In most of cases, an empty string is all you need to access the section. 33 DefaultSection = "DEFAULT" 34 35 // LineBreak is the delimiter to determine or compose a new line. 36 // This variable will be changed to "\r\n" automatically on Windows at package init time. 37 LineBreak = "\n" 38 39 // Variable regexp pattern: %(variable)s 40 varPattern = regexp.MustCompile(`%\(([^)]+)\)s`) 41 42 // DefaultHeader explicitly writes default section header. 43 DefaultHeader = false 44 45 // PrettySection indicates whether to put a line between sections. 46 PrettySection = true 47 // PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output 48 // or reduce all possible spaces for compact format. 49 PrettyFormat = true 50 // PrettyEqual places spaces around "=" sign even when PrettyFormat is false. 51 PrettyEqual = false 52 // DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. 53 DefaultFormatLeft = "" 54 // DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. 55 DefaultFormatRight = "" 56 ) 57 58 var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test") 59 60 func init() { 61 if runtime.GOOS == "windows" && !inTest { 62 LineBreak = "\r\n" 63 } 64 } 65 66 // LoadOptions contains all customized options used for load data source(s). 67 type LoadOptions struct { 68 // Loose indicates whether the parser should ignore nonexistent files or return error. 69 Loose bool 70 // Insensitive indicates whether the parser forces all section and key names to lowercase. 71 Insensitive bool 72 // InsensitiveSections indicates whether the parser forces all section to lowercase. 73 InsensitiveSections bool 74 // InsensitiveKeys indicates whether the parser forces all key names to lowercase. 75 InsensitiveKeys bool 76 // IgnoreContinuation indicates whether to ignore continuation lines while parsing. 77 IgnoreContinuation bool 78 // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. 79 IgnoreInlineComment bool 80 // SkipUnrecognizableLines indicates whether to skip unrecognizable lines that do not conform to key/value pairs. 81 SkipUnrecognizableLines bool 82 // ShortCircuit indicates whether to ignore other configuration sources after loaded the first available configuration source. 83 ShortCircuit bool 84 // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. 85 // This type of keys are mostly used in my.cnf. 86 AllowBooleanKeys bool 87 // AllowShadows indicates whether to keep track of keys with same name under same section. 88 AllowShadows bool 89 // AllowNestedValues indicates whether to allow AWS-like nested values. 90 // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values 91 AllowNestedValues bool 92 // AllowPythonMultilineValues indicates whether to allow Python-like multi-line values. 93 // Docs: https://docs.python.org/3/library/configparser.html#supported-ini-file-structure 94 // Relevant quote: Values can also span multiple lines, as long as they are indented deeper 95 // than the first line of the value. 96 AllowPythonMultilineValues bool 97 // SpaceBeforeInlineComment indicates whether to allow comment symbols (\# and \;) inside value. 98 // Docs: https://docs.python.org/2/library/configparser.html 99 // Quote: Comments may appear on their own in an otherwise empty line, or may be entered in lines holding values or section names. 100 // In the latter case, they need to be preceded by a whitespace character to be recognized as a comment. 101 SpaceBeforeInlineComment bool 102 // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format 103 // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" 104 UnescapeValueDoubleQuotes bool 105 // UnescapeValueCommentSymbols indicates to unescape comment symbols (\# and \;) inside value to regular format 106 // when value is NOT surrounded by any quotes. 107 // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. 108 UnescapeValueCommentSymbols bool 109 // UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise 110 // conform to key/value pairs. Specify the names of those blocks here. 111 UnparseableSections []string 112 // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:". 113 KeyValueDelimiters string 114 // KeyValueDelimiterOnWrite is the delimiter that are used to separate key and value output. By default, it is "=". 115 KeyValueDelimiterOnWrite string 116 // ChildSectionDelimiter is the delimiter that is used to separate child sections. By default, it is ".". 117 ChildSectionDelimiter string 118 // PreserveSurroundedQuote indicates whether to preserve surrounded quote (single and double quotes). 119 PreserveSurroundedQuote bool 120 // DebugFunc is called to collect debug information (currently only useful to debug parsing Python-style multiline values). 121 DebugFunc DebugFunc 122 // ReaderBufferSize is the buffer size of the reader in bytes. 123 ReaderBufferSize int 124 // AllowNonUniqueSections indicates whether to allow sections with the same name multiple times. 125 AllowNonUniqueSections bool 126 // AllowDuplicateShadowValues indicates whether values for shadowed keys should be deduplicated. 127 AllowDuplicateShadowValues bool 128 } 129 130 // DebugFunc is the type of function called to log parse events. 131 type DebugFunc func(message string) 132 133 // LoadSources allows caller to apply customized options for loading from data source(s). 134 func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { 135 sources := make([]dataSource, len(others)+1) 136 sources[0], err = parseDataSource(source) 137 if err != nil { 138 return nil, err 139 } 140 for i := range others { 141 sources[i+1], err = parseDataSource(others[i]) 142 if err != nil { 143 return nil, err 144 } 145 } 146 f := newFile(sources, opts) 147 if err = f.Reload(); err != nil { 148 return nil, err 149 } 150 return f, nil 151 } 152 153 // Load loads and parses from INI data sources. 154 // Arguments can be mixed of file name with string type, or raw data in []byte. 155 // It will return error if list contains nonexistent files. 156 func Load(source interface{}, others ...interface{}) (*File, error) { 157 return LoadSources(LoadOptions{}, source, others...) 158 } 159 160 // LooseLoad has exactly same functionality as Load function 161 // except it ignores nonexistent files instead of returning error. 162 func LooseLoad(source interface{}, others ...interface{}) (*File, error) { 163 return LoadSources(LoadOptions{Loose: true}, source, others...) 164 } 165 166 // InsensitiveLoad has exactly same functionality as Load function 167 // except it forces all section and key names to be lowercased. 168 func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { 169 return LoadSources(LoadOptions{Insensitive: true}, source, others...) 170 } 171 172 // ShadowLoad has exactly same functionality as Load function 173 // except it allows have shadow keys. 174 func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { 175 return LoadSources(LoadOptions{AllowShadows: true}, source, others...) 176 }