119 lines
2.4 KiB
Go
119 lines
2.4 KiB
Go
package parser
|
|
|
|
import (
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
// splitCommand takes a single line of text and parses out the cmd and args,
|
|
// which are used for dispatching to more exact parsing functions.
|
|
func splitCommand(line string) (string, []string, string, error) {
|
|
var args string
|
|
var flags []string
|
|
|
|
// Make sure we get the same results irrespective of leading/trailing spaces
|
|
cmdline := reWhitespace.Split(strings.TrimSpace(line), 2)
|
|
cmd := strings.ToLower(cmdline[0])
|
|
|
|
if len(cmdline) == 2 {
|
|
var err error
|
|
args, flags, err = extractBuilderFlags(cmdline[1])
|
|
if err != nil {
|
|
return "", nil, "", err
|
|
}
|
|
}
|
|
|
|
return cmd, flags, strings.TrimSpace(args), nil
|
|
}
|
|
|
|
func extractBuilderFlags(line string) (string, []string, error) {
|
|
// Parses the BuilderFlags and returns the remaining part of the line
|
|
|
|
const (
|
|
inSpaces = iota // looking for start of a word
|
|
inWord
|
|
inQuote
|
|
)
|
|
|
|
words := []string{}
|
|
phase := inSpaces
|
|
word := ""
|
|
quote := '\000'
|
|
blankOK := false
|
|
var ch rune
|
|
|
|
for pos := 0; pos <= len(line); pos++ {
|
|
if pos != len(line) {
|
|
ch = rune(line[pos])
|
|
}
|
|
|
|
if phase == inSpaces { // Looking for start of word
|
|
if pos == len(line) { // end of input
|
|
break
|
|
}
|
|
if unicode.IsSpace(ch) { // skip spaces
|
|
continue
|
|
}
|
|
|
|
// Only keep going if the next word starts with --
|
|
if ch != '-' || pos+1 == len(line) || rune(line[pos+1]) != '-' {
|
|
return line[pos:], words, nil
|
|
}
|
|
|
|
phase = inWord // found something with "--", fall through
|
|
}
|
|
if (phase == inWord || phase == inQuote) && (pos == len(line)) {
|
|
if word != "--" && (blankOK || len(word) > 0) {
|
|
words = append(words, word)
|
|
}
|
|
break
|
|
}
|
|
if phase == inWord {
|
|
if unicode.IsSpace(ch) {
|
|
phase = inSpaces
|
|
if word == "--" {
|
|
return line[pos:], words, nil
|
|
}
|
|
if blankOK || len(word) > 0 {
|
|
words = append(words, word)
|
|
}
|
|
word = ""
|
|
blankOK = false
|
|
continue
|
|
}
|
|
if ch == '\'' || ch == '"' {
|
|
quote = ch
|
|
blankOK = true
|
|
phase = inQuote
|
|
continue
|
|
}
|
|
if ch == '\\' {
|
|
if pos+1 == len(line) {
|
|
continue // just skip \ at end
|
|
}
|
|
pos++
|
|
ch = rune(line[pos])
|
|
}
|
|
word += string(ch)
|
|
continue
|
|
}
|
|
if phase == inQuote {
|
|
if ch == quote {
|
|
phase = inWord
|
|
continue
|
|
}
|
|
if ch == '\\' {
|
|
if pos+1 == len(line) {
|
|
phase = inWord
|
|
continue // just skip \ at end
|
|
}
|
|
pos++
|
|
ch = rune(line[pos])
|
|
}
|
|
word += string(ch)
|
|
}
|
|
}
|
|
|
|
return "", words, nil
|
|
}
|