diff options
Diffstat (limited to 'vendor/github.com/mattn/go-shellwords/shellwords.go')
-rw-r--r-- | vendor/github.com/mattn/go-shellwords/shellwords.go | 166 |
1 files changed, 134 insertions, 32 deletions
diff --git a/vendor/github.com/mattn/go-shellwords/shellwords.go b/vendor/github.com/mattn/go-shellwords/shellwords.go index ef080861a..01afd94d1 100644 --- a/vendor/github.com/mattn/go-shellwords/shellwords.go +++ b/vendor/github.com/mattn/go-shellwords/shellwords.go @@ -1,10 +1,11 @@ package shellwords import ( + "bytes" "errors" "os" - "regexp" "strings" + "unicode" ) var ( @@ -12,8 +13,6 @@ var ( ParseBacktick bool = false ) -var envRe = regexp.MustCompile(`\$({[a-zA-Z0-9_]+}|[a-zA-Z0-9_]+)`) - func isSpace(r rune) bool { switch r { case ' ', '\t', '\r', '\n': @@ -27,13 +26,72 @@ func replaceEnv(getenv func(string) string, s string) string { getenv = os.Getenv } - return envRe.ReplaceAllStringFunc(s, func(s string) string { - s = s[1:] - if s[0] == '{' { - s = s[1 : len(s)-1] + var buf bytes.Buffer + rs := []rune(s) + for i := 0; i < len(rs); i++ { + r := rs[i] + if r == '\\' { + i++ + if i == len(rs) { + break + } + buf.WriteRune(rs[i]) + continue + } else if r == '$' { + i++ + if i == len(rs) { + buf.WriteRune(r) + break + } + if rs[i] == 0x7b { + i++ + p := i + for ; i < len(rs); i++ { + r = rs[i] + if r == '\\' { + i++ + if i == len(rs) { + return s + } + continue + } + if r == 0x7d || (!unicode.IsLetter(r) && r != '_' && !unicode.IsDigit(r)) { + break + } + } + if r != 0x7d { + return s + } + if i > p { + buf.WriteString(getenv(s[p:i])) + } + } else { + p := i + for ; i < len(rs); i++ { + r := rs[i] + if r == '\\' { + i++ + if i == len(rs) { + return s + } + continue + } + if !unicode.IsLetter(r) && r != '_' && !unicode.IsDigit(r) { + break + } + } + if i > p { + buf.WriteString(getenv(s[p:i])) + i-- + } else { + buf.WriteString(s[p:]) + } + } + } else { + buf.WriteRune(r) } - return getenv(s) - }) + } + return buf.String() } type Parser struct { @@ -56,6 +114,14 @@ func NewParser() *Parser { } } +type argType int + +const ( + argNo argType = iota + argSingle + argQuoted +) + func (p *Parser) Parse(line string) ([]string, error) { args := []string{} buf := "" @@ -63,13 +129,16 @@ func (p *Parser) Parse(line string) ([]string, error) { backtick := "" pos := -1 - got := false + got := argNo + i := -1 loop: - for i, r := range line { + for _, r := range line { + i++ if escaped { buf += string(r) escaped = false + got = argSingle continue } @@ -86,21 +155,23 @@ loop: if singleQuoted || doubleQuoted || backQuote || dollarQuote { buf += string(r) backtick += string(r) - } else if got { + } else if got != argNo { if p.ParseEnv { - parser := &Parser{ParseEnv: false, ParseBacktick: false, Position: 0, Dir: p.Dir} - strs, err := parser.Parse(replaceEnv(p.Getenv, buf)) - if err != nil { - return nil, err - } - for _, str := range strs { - args = append(args, str) + if got == argSingle { + parser := &Parser{ParseEnv: false, ParseBacktick: false, Position: 0, Dir: p.Dir} + strs, err := parser.Parse(replaceEnv(p.Getenv, buf)) + if err != nil { + return nil, err + } + args = append(args, strs...) + } else { + args = append(args, replaceEnv(p.Getenv, buf)) } } else { args = append(args, buf) } buf = "" - got = false + got = argNo } continue } @@ -153,7 +224,7 @@ loop: case '"': if !singleQuoted && !dollarQuote { if doubleQuoted { - got = true + got = argQuoted } doubleQuoted = !doubleQuoted continue @@ -161,7 +232,7 @@ loop: case '\'': if !doubleQuoted && !dollarQuote { if singleQuoted { - got = true + got = argSingle } singleQuoted = !singleQuoted continue @@ -171,7 +242,7 @@ loop: if r == '>' && len(buf) > 0 { if c := buf[0]; '0' <= c && c <= '9' { i -= 1 - got = false + got = argNo } } pos = i @@ -179,22 +250,24 @@ loop: } } - got = true + got = argSingle buf += string(r) if backQuote || dollarQuote { backtick += string(r) } } - if got { + if got != argNo { if p.ParseEnv { - parser := &Parser{ParseEnv: false, ParseBacktick: false, Position: 0, Dir: p.Dir} - strs, err := parser.Parse(replaceEnv(p.Getenv, buf)) - if err != nil { - return nil, err - } - for _, str := range strs { - args = append(args, str) + if got == argSingle { + parser := &Parser{ParseEnv: false, ParseBacktick: false, Position: 0, Dir: p.Dir} + strs, err := parser.Parse(replaceEnv(p.Getenv, buf)) + if err != nil { + return nil, err + } + args = append(args, strs...) + } else { + args = append(args, replaceEnv(p.Getenv, buf)) } } else { args = append(args, buf) @@ -210,6 +283,35 @@ loop: return args, nil } +func (p *Parser) ParseWithEnvs(line string) (envs []string, args []string, err error) { + _args, err := p.Parse(line) + if err != nil { + return nil, nil, err + } + envs = []string{} + args = []string{} + parsingEnv := true + for _, arg := range _args { + if parsingEnv && isEnv(arg) { + envs = append(envs, arg) + } else { + if parsingEnv { + parsingEnv = false + } + args = append(args, arg) + } + } + return envs, args, nil +} + +func isEnv(arg string) bool { + return len(strings.Split(arg, "=")) == 2 +} + func Parse(line string) ([]string, error) { return NewParser().Parse(line) } + +func ParseWithEnvs(line string) (envs []string, args []string, err error) { + return NewParser().ParseWithEnvs(line) +} |