github.com/gsquire/gb@v0.4.4-0.20161112235727-3982dc872064/internal/importer/util.go (about) 1 package importer 2 3 import ( 4 "errors" 5 "unicode" 6 ) 7 8 // splitQuoted splits the string s around each instance of one or more consecutive 9 // white space characters while taking into account quotes and escaping, and 10 // returns an array of substrings of s or an empty list if s contains only white space. 11 // Single quotes and double quotes are recognized to prevent splitting within the 12 // quoted region, and are removed from the resulting substrings. If a quote in s 13 // isn't closed err will be set and r will have the unclosed argument as the 14 // last element. The backslash is used for escaping. 15 // 16 // For example, the following string: 17 // 18 // a b:"c d" 'e''f' "g\"" 19 // 20 // Would be parsed as: 21 // 22 // []string{"a", "b:c d", "ef", `g"`} 23 // 24 func splitQuoted(s string) (r []string, err error) { 25 var args []string 26 arg := make([]rune, len(s)) 27 escaped := false 28 quoted := false 29 quote := '\x00' 30 i := 0 31 for _, rune := range s { 32 switch { 33 case escaped: 34 escaped = false 35 case rune == '\\': 36 escaped = true 37 continue 38 case quote != '\x00': 39 if rune == quote { 40 quote = '\x00' 41 continue 42 } 43 case rune == '"' || rune == '\'': 44 quoted = true 45 quote = rune 46 continue 47 case unicode.IsSpace(rune): 48 if quoted || i > 0 { 49 quoted = false 50 args = append(args, string(arg[:i])) 51 i = 0 52 } 53 continue 54 } 55 arg[i] = rune 56 i++ 57 } 58 if quoted || i > 0 { 59 args = append(args, string(arg[:i])) 60 } 61 if quote != 0 { 62 err = errors.New("unclosed quote") 63 } else if escaped { 64 err = errors.New("unfinished escaping") 65 } 66 return args, err 67 }