| 11 | ) |
| 12 | |
| 13 | func ExecWords(ln string) ([]string, error) { |
| 14 | ln = strings.TrimSpace(ln) |
| 15 | n := len(ln) |
| 16 | if n == 0 { |
| 17 | return nil, nil |
| 18 | } |
| 19 | |
| 20 | word := "" |
| 21 | esc := false |
| 22 | dQuote := false |
| 23 | bQuote := false |
| 24 | brace := 0 |
| 25 | brack := 0 |
| 26 | redir := false |
| 27 | |
| 28 | var words []string |
| 29 | addWord := func() { |
| 30 | if brace > 0 { // always accum into one token inside brace |
| 31 | return |
| 32 | } |
| 33 | if len(word) > 0 { |
| 34 | words = append(words, word) |
| 35 | word = "" |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | atStart := true |
| 40 | sbrack := (ln[0] == '[') |
| 41 | if sbrack { |
| 42 | word = "[" |
| 43 | addWord() |
| 44 | brack++ |
| 45 | ln = ln[1:] |
| 46 | atStart = false |
| 47 | } |
| 48 | |
| 49 | for _, r := range ln { |
| 50 | quote := dQuote || bQuote |
| 51 | |
| 52 | if redir { |
| 53 | redir = false |
| 54 | if r == '&' { |
| 55 | word += string(r) |
| 56 | addWord() |
| 57 | continue |
| 58 | } |
| 59 | if r == '>' { |
| 60 | word += string(r) |
| 61 | redir = true |
| 62 | continue |
| 63 | } |
| 64 | addWord() |
| 65 | } |
| 66 | |
| 67 | switch { |
| 68 | case esc: |
| 69 | if brace == 0 && unicode.IsSpace(r) { // we will be quoted later anyway |
| 70 | word = word[:len(word)-1] |