|
|
@@ -1,144 +0,0 @@
|
|
|
-package shellquote
|
|
|
-
|
|
|
-import (
|
|
|
- "bytes"
|
|
|
- "errors"
|
|
|
- "strings"
|
|
|
- "unicode/utf8"
|
|
|
-)
|
|
|
-
|
|
|
-var (
|
|
|
- UnterminatedSingleQuoteError = errors.New("Unterminated single-quoted string")
|
|
|
- UnterminatedDoubleQuoteError = errors.New("Unterminated double-quoted string")
|
|
|
- UnterminatedEscapeError = errors.New("Unterminated backslash-escape")
|
|
|
-)
|
|
|
-
|
|
|
-var (
|
|
|
- splitChars = " \n\t"
|
|
|
- singleChar = '\''
|
|
|
- doubleChar = '"'
|
|
|
- escapeChar = '\\'
|
|
|
- doubleEscapeChars = "$`\"\n\\"
|
|
|
-)
|
|
|
-
|
|
|
-// Split splits a string according to /bin/sh's word-splitting rules. It
|
|
|
-// supports backslash-escapes, single-quotes, and double-quotes. Notably it does
|
|
|
-// not support the $'' style of quoting. It also doesn't attempt to perform any
|
|
|
-// other sort of expansion, including brace expansion, shell expansion, or
|
|
|
-// pathname expansion.
|
|
|
-//
|
|
|
-// If the given input has an unterminated quoted string or ends in a
|
|
|
-// backslash-escape, one of UnterminatedSingleQuoteError,
|
|
|
-// UnterminatedDoubleQuoteError, or UnterminatedEscapeError is returned.
|
|
|
-func Split(input string) (words []string, err error) {
|
|
|
- var buf bytes.Buffer
|
|
|
- words = make([]string, 0)
|
|
|
-
|
|
|
- for len(input) > 0 {
|
|
|
- // skip any splitChars at the start
|
|
|
- c, l := utf8.DecodeRuneInString(input)
|
|
|
- if strings.ContainsRune(splitChars, c) {
|
|
|
- input = input[l:]
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- var word string
|
|
|
- word, input, err = splitWord(input, &buf)
|
|
|
- if err != nil {
|
|
|
- return
|
|
|
- }
|
|
|
- words = append(words, word)
|
|
|
- }
|
|
|
- return
|
|
|
-}
|
|
|
-
|
|
|
-func splitWord(input string, buf *bytes.Buffer) (word string, remainder string, err error) {
|
|
|
- buf.Reset()
|
|
|
-
|
|
|
-raw:
|
|
|
- {
|
|
|
- cur := input
|
|
|
- for len(cur) > 0 {
|
|
|
- c, l := utf8.DecodeRuneInString(cur)
|
|
|
- cur = cur[l:]
|
|
|
- if c == singleChar {
|
|
|
- buf.WriteString(input[0 : len(input)-len(cur)-l])
|
|
|
- input = cur
|
|
|
- goto single
|
|
|
- } else if c == doubleChar {
|
|
|
- buf.WriteString(input[0 : len(input)-len(cur)-l])
|
|
|
- input = cur
|
|
|
- goto double
|
|
|
- } else if c == escapeChar {
|
|
|
- buf.WriteString(input[0 : len(input)-len(cur)-l])
|
|
|
- input = cur
|
|
|
- goto escape
|
|
|
- } else if strings.ContainsRune(splitChars, c) {
|
|
|
- buf.WriteString(input[0 : len(input)-len(cur)-l])
|
|
|
- return buf.String(), cur, nil
|
|
|
- }
|
|
|
- }
|
|
|
- if len(input) > 0 {
|
|
|
- buf.WriteString(input)
|
|
|
- input = ""
|
|
|
- }
|
|
|
- goto done
|
|
|
- }
|
|
|
-
|
|
|
-escape:
|
|
|
- {
|
|
|
- if len(input) == 0 {
|
|
|
- return "", "", UnterminatedEscapeError
|
|
|
- }
|
|
|
- c, l := utf8.DecodeRuneInString(input)
|
|
|
- if c == '\n' {
|
|
|
- // a backslash-escaped newline is elided from the output entirely
|
|
|
- } else {
|
|
|
- buf.WriteString(input[:l])
|
|
|
- }
|
|
|
- input = input[l:]
|
|
|
- }
|
|
|
- goto raw
|
|
|
-
|
|
|
-single:
|
|
|
- {
|
|
|
- i := strings.IndexRune(input, singleChar)
|
|
|
- if i == -1 {
|
|
|
- return "", "", UnterminatedSingleQuoteError
|
|
|
- }
|
|
|
- buf.WriteString(input[0:i])
|
|
|
- input = input[i+1:]
|
|
|
- goto raw
|
|
|
- }
|
|
|
-
|
|
|
-double:
|
|
|
- {
|
|
|
- cur := input
|
|
|
- for len(cur) > 0 {
|
|
|
- c, l := utf8.DecodeRuneInString(cur)
|
|
|
- cur = cur[l:]
|
|
|
- if c == doubleChar {
|
|
|
- buf.WriteString(input[0 : len(input)-len(cur)-l])
|
|
|
- input = cur
|
|
|
- goto raw
|
|
|
- } else if c == escapeChar {
|
|
|
- // bash only supports certain escapes in double-quoted strings
|
|
|
- c2, l2 := utf8.DecodeRuneInString(cur)
|
|
|
- cur = cur[l2:]
|
|
|
- if strings.ContainsRune(doubleEscapeChars, c2) {
|
|
|
- buf.WriteString(input[0 : len(input)-len(cur)-l-l2])
|
|
|
- if c2 == '\n' {
|
|
|
- // newline is special, skip the backslash entirely
|
|
|
- } else {
|
|
|
- buf.WriteRune(c2)
|
|
|
- }
|
|
|
- input = cur
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return "", "", UnterminatedDoubleQuoteError
|
|
|
- }
|
|
|
-
|
|
|
-done:
|
|
|
- return buf.String(), input, nil
|
|
|
-}
|