1// +build go1.6 2 3// Copyright 2014 Unknwon 4// 5// Licensed under the Apache License, Version 2.0 (the "License"): you may 6// not use this file except in compliance with the License. You may obtain 7// a copy of the License at 8// 9// http://www.apache.org/licenses/LICENSE-2.0 10// 11// Unless required by applicable law or agreed to in writing, software 12// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14// License for the specific language governing permissions and limitations 15// under the License. 16 17// Package ini provides INI file read and write functionality in Go. 18package ini 19 20import ( 21 "os" 22 "regexp" 23 "runtime" 24 "strings" 25) 26 27const ( 28 // DefaultSection is the name of default section. You can use this constant or the string literal. 29 // In most of cases, an empty string is all you need to access the section. 30 DefaultSection = "DEFAULT" 31 32 // Maximum allowed depth when recursively substituing variable names. 33 depthValues = 99 34) 35 36var ( 37 // LineBreak is the delimiter to determine or compose a new line. 38 // This variable will be changed to "\r\n" automatically on Windows at package init time. 39 LineBreak = "\n" 40 41 // Variable regexp pattern: %(variable)s 42 varPattern = regexp.MustCompile(`%\(([^)]+)\)s`) 43 44 // DefaultHeader explicitly writes default section header. 45 DefaultHeader = false 46 47 // PrettySection indicates whether to put a line between sections. 48 PrettySection = true 49 // PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output 50 // or reduce all possible spaces for compact format. 51 PrettyFormat = true 52 // PrettyEqual places spaces around "=" sign even when PrettyFormat is false. 53 PrettyEqual = false 54 // DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. 55 DefaultFormatLeft = "" 56 // DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. 57 DefaultFormatRight = "" 58) 59 60var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test") 61 62func init() { 63 if runtime.GOOS == "windows" && !inTest { 64 LineBreak = "\r\n" 65 } 66} 67 68// LoadOptions contains all customized options used for load data source(s). 69type LoadOptions struct { 70 // Loose indicates whether the parser should ignore nonexistent files or return error. 71 Loose bool 72 // Insensitive indicates whether the parser forces all section and key names to lowercase. 73 Insensitive bool 74 // InsensitiveSections indicates whether the parser forces all section to lowercase. 75 InsensitiveSections bool 76 // InsensitiveKeys indicates whether the parser forces all key names to lowercase. 77 InsensitiveKeys bool 78 // IgnoreContinuation indicates whether to ignore continuation lines while parsing. 79 IgnoreContinuation bool 80 // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. 81 IgnoreInlineComment bool 82 // SkipUnrecognizableLines indicates whether to skip unrecognizable lines that do not conform to key/value pairs. 83 SkipUnrecognizableLines bool 84 // ShortCircuit indicates whether to ignore other configuration sources after loaded the first available configuration source. 85 ShortCircuit bool 86 // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. 87 // This type of keys are mostly used in my.cnf. 88 AllowBooleanKeys bool 89 // AllowShadows indicates whether to keep track of keys with same name under same section. 90 AllowShadows bool 91 // AllowNestedValues indicates whether to allow AWS-like nested values. 92 // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values 93 AllowNestedValues bool 94 // AllowPythonMultilineValues indicates whether to allow Python-like multi-line values. 95 // Docs: https://docs.python.org/3/library/configparser.html#supported-ini-file-structure 96 // Relevant quote: Values can also span multiple lines, as long as they are indented deeper 97 // than the first line of the value. 98 AllowPythonMultilineValues bool 99 // SpaceBeforeInlineComment indicates whether to allow comment symbols (\# and \;) inside value. 100 // Docs: https://docs.python.org/2/library/configparser.html 101 // Quote: Comments may appear on their own in an otherwise empty line, or may be entered in lines holding values or section names. 102 // In the latter case, they need to be preceded by a whitespace character to be recognized as a comment. 103 SpaceBeforeInlineComment bool 104 // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format 105 // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" 106 UnescapeValueDoubleQuotes bool 107 // UnescapeValueCommentSymbols indicates to unescape comment symbols (\# and \;) inside value to regular format 108 // when value is NOT surrounded by any quotes. 109 // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. 110 UnescapeValueCommentSymbols bool 111 // UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise 112 // conform to key/value pairs. Specify the names of those blocks here. 113 UnparseableSections []string 114 // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:". 115 KeyValueDelimiters string 116 // KeyValueDelimiterOnWrite is the delimiter that are used to separate key and value output. By default, it is "=". 117 KeyValueDelimiterOnWrite string 118 // ChildSectionDelimiter is the delimiter that is used to separate child sections. By default, it is ".". 119 ChildSectionDelimiter string 120 // PreserveSurroundedQuote indicates whether to preserve surrounded quote (single and double quotes). 121 PreserveSurroundedQuote bool 122 // DebugFunc is called to collect debug information (currently only useful to debug parsing Python-style multiline values). 123 DebugFunc DebugFunc 124 // ReaderBufferSize is the buffer size of the reader in bytes. 125 ReaderBufferSize int 126 // AllowNonUniqueSections indicates whether to allow sections with the same name multiple times. 127 AllowNonUniqueSections bool 128} 129 130// DebugFunc is the type of function called to log parse events. 131type DebugFunc func(message string) 132 133// LoadSources allows caller to apply customized options for loading from data source(s). 134func 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. 156func 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. 162func 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. 168func 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. 174func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { 175 return LoadSources(LoadOptions{AllowShadows: true}, source, others...) 176} 177