|
@@ -29,17 +29,85 @@ func ProcessWord(word string, env []string) (string, error) {
|
|
pos: 0,
|
|
pos: 0,
|
|
}
|
|
}
|
|
sw.scanner.Init(strings.NewReader(word))
|
|
sw.scanner.Init(strings.NewReader(word))
|
|
- return sw.process()
|
|
|
|
|
|
+ word, _, err := sw.process()
|
|
|
|
+ return word, err
|
|
}
|
|
}
|
|
|
|
|
|
-func (sw *shellWord) process() (string, error) {
|
|
|
|
|
|
+// ProcessWords will use the 'env' list of environment variables,
|
|
|
|
+// and replace any env var references in 'word' then it will also
|
|
|
|
+// return a slice of strings which represents the 'word'
|
|
|
|
+// split up based on spaces - taking into account quotes. Note that
|
|
|
|
+// this splitting is done **after** the env var substitutions are done.
|
|
|
|
+// Note, each one is trimmed to remove leading and trailing spaces (unless
|
|
|
|
+// they are quoted", but ProcessWord retains spaces between words.
|
|
|
|
+func ProcessWords(word string, env []string) ([]string, error) {
|
|
|
|
+ sw := &shellWord{
|
|
|
|
+ word: word,
|
|
|
|
+ envs: env,
|
|
|
|
+ pos: 0,
|
|
|
|
+ }
|
|
|
|
+ sw.scanner.Init(strings.NewReader(word))
|
|
|
|
+ _, words, err := sw.process()
|
|
|
|
+ return words, err
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (sw *shellWord) process() (string, []string, error) {
|
|
return sw.processStopOn(scanner.EOF)
|
|
return sw.processStopOn(scanner.EOF)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+type wordsStruct struct {
|
|
|
|
+ word string
|
|
|
|
+ words []string
|
|
|
|
+ inWord bool
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (w *wordsStruct) addChar(ch rune) {
|
|
|
|
+ if unicode.IsSpace(ch) && w.inWord {
|
|
|
|
+ if len(w.word) != 0 {
|
|
|
|
+ w.words = append(w.words, w.word)
|
|
|
|
+ w.word = ""
|
|
|
|
+ w.inWord = false
|
|
|
|
+ }
|
|
|
|
+ } else if !unicode.IsSpace(ch) {
|
|
|
|
+ w.addRawChar(ch)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (w *wordsStruct) addRawChar(ch rune) {
|
|
|
|
+ w.word += string(ch)
|
|
|
|
+ w.inWord = true
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (w *wordsStruct) addString(str string) {
|
|
|
|
+ var scan scanner.Scanner
|
|
|
|
+ scan.Init(strings.NewReader(str))
|
|
|
|
+ for scan.Peek() != scanner.EOF {
|
|
|
|
+ w.addChar(scan.Next())
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (w *wordsStruct) addRawString(str string) {
|
|
|
|
+ w.word += str
|
|
|
|
+ w.inWord = true
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (w *wordsStruct) getWords() []string {
|
|
|
|
+ if len(w.word) > 0 {
|
|
|
|
+ w.words = append(w.words, w.word)
|
|
|
|
+
|
|
|
|
+ // Just in case we're called again by mistake
|
|
|
|
+ w.word = ""
|
|
|
|
+ w.inWord = false
|
|
|
|
+ }
|
|
|
|
+ return w.words
|
|
|
|
+}
|
|
|
|
+
|
|
// Process the word, starting at 'pos', and stop when we get to the
|
|
// Process the word, starting at 'pos', and stop when we get to the
|
|
// end of the word or the 'stopChar' character
|
|
// end of the word or the 'stopChar' character
|
|
-func (sw *shellWord) processStopOn(stopChar rune) (string, error) {
|
|
|
|
|
|
+func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
|
|
var result string
|
|
var result string
|
|
|
|
+ var words wordsStruct
|
|
|
|
+
|
|
var charFuncMapping = map[rune]func() (string, error){
|
|
var charFuncMapping = map[rune]func() (string, error){
|
|
'\'': sw.processSingleQuote,
|
|
'\'': sw.processSingleQuote,
|
|
'"': sw.processDoubleQuote,
|
|
'"': sw.processDoubleQuote,
|
|
@@ -57,9 +125,15 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, error) {
|
|
// Call special processing func for certain chars
|
|
// Call special processing func for certain chars
|
|
tmp, err := fn()
|
|
tmp, err := fn()
|
|
if err != nil {
|
|
if err != nil {
|
|
- return "", err
|
|
|
|
|
|
+ return "", []string{}, err
|
|
}
|
|
}
|
|
result += tmp
|
|
result += tmp
|
|
|
|
+
|
|
|
|
+ if ch == rune('$') {
|
|
|
|
+ words.addString(tmp)
|
|
|
|
+ } else {
|
|
|
|
+ words.addRawString(tmp)
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
// Not special, just add it to the result
|
|
// Not special, just add it to the result
|
|
ch = sw.scanner.Next()
|
|
ch = sw.scanner.Next()
|
|
@@ -73,13 +147,16 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, error) {
|
|
break
|
|
break
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ words.addRawChar(ch)
|
|
|
|
+ } else {
|
|
|
|
+ words.addChar(ch)
|
|
}
|
|
}
|
|
|
|
|
|
result += string(ch)
|
|
result += string(ch)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- return result, nil
|
|
|
|
|
|
+ return result, words.getWords(), nil
|
|
}
|
|
}
|
|
|
|
|
|
func (sw *shellWord) processSingleQuote() (string, error) {
|
|
func (sw *shellWord) processSingleQuote() (string, error) {
|
|
@@ -160,7 +237,7 @@ func (sw *shellWord) processDollar() (string, error) {
|
|
sw.scanner.Next() // skip over :
|
|
sw.scanner.Next() // skip over :
|
|
modifier := sw.scanner.Next()
|
|
modifier := sw.scanner.Next()
|
|
|
|
|
|
- word, err := sw.processStopOn('}')
|
|
|
|
|
|
+ word, _, err := sw.processStopOn('}')
|
|
if err != nil {
|
|
if err != nil {
|
|
return "", err
|
|
return "", err
|
|
}
|
|
}
|