Add initial import of KNI project
[kni/installer.git] / vendor / github.com / aws / aws-sdk-go / internal / ini / literal_tokens.go
1 package ini
2
3 import (
4         "fmt"
5         "strconv"
6         "strings"
7 )
8
9 var (
10         runesTrue  = []rune("true")
11         runesFalse = []rune("false")
12 )
13
14 var literalValues = [][]rune{
15         runesTrue,
16         runesFalse,
17 }
18
19 func isBoolValue(b []rune) bool {
20         for _, lv := range literalValues {
21                 if isLitValue(lv, b) {
22                         return true
23                 }
24         }
25         return false
26 }
27
28 func isLitValue(want, have []rune) bool {
29         if len(have) < len(want) {
30                 return false
31         }
32
33         for i := 0; i < len(want); i++ {
34                 if want[i] != have[i] {
35                         return false
36                 }
37         }
38
39         return true
40 }
41
42 // isNumberValue will return whether not the leading characters in
43 // a byte slice is a number. A number is delimited by whitespace or
44 // the newline token.
45 //
46 // A number is defined to be in a binary, octal, decimal (int | float), hex format,
47 // or in scientific notation.
48 func isNumberValue(b []rune) bool {
49         negativeIndex := 0
50         helper := numberHelper{}
51         needDigit := false
52
53         for i := 0; i < len(b); i++ {
54                 negativeIndex++
55
56                 switch b[i] {
57                 case '-':
58                         if helper.IsNegative() || negativeIndex != 1 {
59                                 return false
60                         }
61                         helper.Determine(b[i])
62                         needDigit = true
63                         continue
64                 case 'e', 'E':
65                         if err := helper.Determine(b[i]); err != nil {
66                                 return false
67                         }
68                         negativeIndex = 0
69                         needDigit = true
70                         continue
71                 case 'b':
72                         if helper.numberFormat == hex {
73                                 break
74                         }
75                         fallthrough
76                 case 'o', 'x':
77                         needDigit = true
78                         if i == 0 {
79                                 return false
80                         }
81
82                         fallthrough
83                 case '.':
84                         if err := helper.Determine(b[i]); err != nil {
85                                 return false
86                         }
87                         needDigit = true
88                         continue
89                 }
90
91                 if i > 0 && (isNewline(b[i:]) || isWhitespace(b[i])) {
92                         return !needDigit
93                 }
94
95                 if !helper.CorrectByte(b[i]) {
96                         return false
97                 }
98                 needDigit = false
99         }
100
101         return !needDigit
102 }
103
104 func isValid(b []rune) (bool, int, error) {
105         if len(b) == 0 {
106                 // TODO: should probably return an error
107                 return false, 0, nil
108         }
109
110         return isValidRune(b[0]), 1, nil
111 }
112
113 func isValidRune(r rune) bool {
114         return r != ':' && r != '=' && r != '[' && r != ']' && r != ' ' && r != '\n'
115 }
116
117 // ValueType is an enum that will signify what type
118 // the Value is
119 type ValueType int
120
121 func (v ValueType) String() string {
122         switch v {
123         case NoneType:
124                 return "NONE"
125         case DecimalType:
126                 return "FLOAT"
127         case IntegerType:
128                 return "INT"
129         case StringType:
130                 return "STRING"
131         case BoolType:
132                 return "BOOL"
133         }
134
135         return ""
136 }
137
138 // ValueType enums
139 const (
140         NoneType = ValueType(iota)
141         DecimalType
142         IntegerType
143         StringType
144         QuotedStringType
145         BoolType
146 )
147
148 // Value is a union container
149 type Value struct {
150         Type ValueType
151         raw  []rune
152
153         integer int64
154         decimal float64
155         boolean bool
156         str     string
157 }
158
159 func newValue(t ValueType, base int, raw []rune) (Value, error) {
160         v := Value{
161                 Type: t,
162                 raw:  raw,
163         }
164         var err error
165
166         switch t {
167         case DecimalType:
168                 v.decimal, err = strconv.ParseFloat(string(raw), 64)
169         case IntegerType:
170                 if base != 10 {
171                         raw = raw[2:]
172                 }
173
174                 v.integer, err = strconv.ParseInt(string(raw), base, 64)
175         case StringType:
176                 v.str = string(raw)
177         case QuotedStringType:
178                 v.str = string(raw[1 : len(raw)-1])
179         case BoolType:
180                 v.boolean = runeCompare(v.raw, runesTrue)
181         }
182
183         // issue 2253
184         //
185         // if the value trying to be parsed is too large, then we will use
186         // the 'StringType' and raw value instead.
187         if nerr, ok := err.(*strconv.NumError); ok && nerr.Err == strconv.ErrRange {
188                 v.Type = StringType
189                 v.str = string(raw)
190                 err = nil
191         }
192
193         return v, err
194 }
195
196 // Append will append values and change the type to a string
197 // type.
198 func (v *Value) Append(tok Token) {
199         r := tok.Raw()
200         if v.Type != QuotedStringType {
201                 v.Type = StringType
202                 r = tok.raw[1 : len(tok.raw)-1]
203         }
204         if tok.Type() != TokenLit {
205                 v.raw = append(v.raw, tok.Raw()...)
206         } else {
207                 v.raw = append(v.raw, r...)
208         }
209 }
210
211 func (v Value) String() string {
212         switch v.Type {
213         case DecimalType:
214                 return fmt.Sprintf("decimal: %f", v.decimal)
215         case IntegerType:
216                 return fmt.Sprintf("integer: %d", v.integer)
217         case StringType:
218                 return fmt.Sprintf("string: %s", string(v.raw))
219         case QuotedStringType:
220                 return fmt.Sprintf("quoted string: %s", string(v.raw))
221         case BoolType:
222                 return fmt.Sprintf("bool: %t", v.boolean)
223         default:
224                 return "union not set"
225         }
226 }
227
228 func newLitToken(b []rune) (Token, int, error) {
229         n := 0
230         var err error
231
232         token := Token{}
233         if b[0] == '"' {
234                 n, err = getStringValue(b)
235                 if err != nil {
236                         return token, n, err
237                 }
238
239                 token = newToken(TokenLit, b[:n], QuotedStringType)
240         } else if isNumberValue(b) {
241                 var base int
242                 base, n, err = getNumericalValue(b)
243                 if err != nil {
244                         return token, 0, err
245                 }
246
247                 value := b[:n]
248                 vType := IntegerType
249                 if contains(value, '.') || hasExponent(value) {
250                         vType = DecimalType
251                 }
252                 token = newToken(TokenLit, value, vType)
253                 token.base = base
254         } else if isBoolValue(b) {
255                 n, err = getBoolValue(b)
256
257                 token = newToken(TokenLit, b[:n], BoolType)
258         } else {
259                 n, err = getValue(b)
260                 token = newToken(TokenLit, b[:n], StringType)
261         }
262
263         return token, n, err
264 }
265
266 // IntValue returns an integer value
267 func (v Value) IntValue() int64 {
268         return v.integer
269 }
270
271 // FloatValue returns a float value
272 func (v Value) FloatValue() float64 {
273         return v.decimal
274 }
275
276 // BoolValue returns a bool value
277 func (v Value) BoolValue() bool {
278         return v.boolean
279 }
280
281 func isTrimmable(r rune) bool {
282         switch r {
283         case '\n', ' ':
284                 return true
285         }
286         return false
287 }
288
289 // StringValue returns the string value
290 func (v Value) StringValue() string {
291         switch v.Type {
292         case StringType:
293                 return strings.TrimFunc(string(v.raw), isTrimmable)
294         case QuotedStringType:
295                 // preserve all characters in the quotes
296                 return string(removeEscapedCharacters(v.raw[1 : len(v.raw)-1]))
297         default:
298                 return strings.TrimFunc(string(v.raw), isTrimmable)
299         }
300 }
301
302 func contains(runes []rune, c rune) bool {
303         for i := 0; i < len(runes); i++ {
304                 if runes[i] == c {
305                         return true
306                 }
307         }
308
309         return false
310 }
311
312 func runeCompare(v1 []rune, v2 []rune) bool {
313         if len(v1) != len(v2) {
314                 return false
315         }
316
317         for i := 0; i < len(v1); i++ {
318                 if v1[i] != v2[i] {
319                         return false
320                 }
321         }
322
323         return true
324 }