github.com/bir3/gocompiler@v0.9.2202/src/cmd/internal/quoted/quoted.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package quoted provides string manipulation utilities. 6 package quoted 7 8 import ( 9 "fmt" 10 "strings" 11 "unicode" 12 ) 13 14 func isSpaceByte(c byte) bool { 15 return c == ' ' || c == '\t' || c == '\n' || c == '\r' 16 } 17 18 // Split splits s into a list of fields, 19 // allowing single or double quotes around elements. 20 // There is no unescaping or other processing within 21 // quoted fields. 22 // 23 // Keep in sync with cmd/dist/quoted.go 24 func Split(s string) ([]string, error) { 25 // Split fields allowing '' or "" around elements. 26 // Quotes further inside the string do not count. 27 var f []string 28 for len(s) > 0 { 29 for len(s) > 0 && isSpaceByte(s[0]) { 30 s = s[1:] 31 } 32 if len(s) == 0 { 33 break 34 } 35 // Accepted quoted string. No unescaping inside. 36 if s[0] == '"' || s[0] == '\'' { 37 quote := s[0] 38 s = s[1:] 39 i := 0 40 for i < len(s) && s[i] != quote { 41 i++ 42 } 43 if i >= len(s) { 44 return nil, fmt.Errorf("unterminated %c string", quote) 45 } 46 f = append(f, s[:i]) 47 s = s[i+1:] 48 continue 49 } 50 i := 0 51 for i < len(s) && !isSpaceByte(s[i]) { 52 i++ 53 } 54 f = append(f, s[:i]) 55 s = s[i:] 56 } 57 return f, nil 58 } 59 60 // Join joins a list of arguments into a string that can be parsed 61 // with Split. Arguments are quoted only if necessary; arguments 62 // without spaces or quotes are kept as-is. No argument may contain both 63 // single and double quotes. 64 func Join(args []string) (string, error) { 65 var buf []byte 66 for i, arg := range args { 67 if i > 0 { 68 buf = append(buf, ' ') 69 } 70 var sawSpace, sawSingleQuote, sawDoubleQuote bool 71 for _, c := range arg { 72 switch { 73 case c > unicode.MaxASCII: 74 continue 75 case isSpaceByte(byte(c)): 76 sawSpace = true 77 case c == '\'': 78 sawSingleQuote = true 79 case c == '"': 80 sawDoubleQuote = true 81 } 82 } 83 switch { 84 case !sawSpace && !sawSingleQuote && !sawDoubleQuote: 85 buf = append(buf, arg...) 86 87 case !sawSingleQuote: 88 buf = append(buf, '\'') 89 buf = append(buf, arg...) 90 buf = append(buf, '\'') 91 92 case !sawDoubleQuote: 93 buf = append(buf, '"') 94 buf = append(buf, arg...) 95 buf = append(buf, '"') 96 97 default: 98 return "", fmt.Errorf("argument %q contains both single and double quotes and cannot be quoted", arg) 99 } 100 } 101 return string(buf), nil 102 } 103 104 // A Flag parses a list of string arguments encoded with Join. 105 // It is useful for flags like cmd/link's -extldflags. 106 type Flag []string 107 108 109 func (f *Flag) Set(v string) error { 110 fs, err := Split(v) 111 if err != nil { 112 return err 113 } 114 *f = fs[:len(fs):len(fs)] 115 return nil 116 } 117 118 func (f *Flag) String() string { 119 if f == nil { 120 return "" 121 } 122 s, err := Join(*f) 123 if err != nil { 124 return strings.Join(*f, " ") 125 } 126 return s 127 }