Repository navigation
Expand file tree
/
Copy pathparse.go
More file actions
101 lines (88 loc) · 1.82 KB
/
Copy pathparse.go
File metadata and controls
101 lines (88 loc) · 1.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package gosh
import (
"fmt"
"strings"
)
// SplitArgs splits a single command line into argv-style tokens.
//
// Gosh executes programs directly instead of through a shell. Shell control
// operators are therefore rejected here so routed CLI commands stay explicit.
func SplitArgs(input string) ([]string, error) {
runes := []rune(strings.TrimSpace(input))
var args []string
var current strings.Builder
var quote rune
argStarted := false
flush := func() {
if argStarted {
args = append(args, current.String())
current.Reset()
argStarted = false
}
}
for i := 0; i < len(runes); i++ {
ch := runes[i]
if ch == '\\' {
if i+1 >= len(runes) {
current.WriteRune('\\')
argStarted = true
continue
}
next := runes[i+1]
if quote != 0 {
if next == quote || next == '\\' {
current.WriteRune(next)
argStarted = true
i++
continue
}
current.WriteRune('\\')
argStarted = true
continue
}
if isEscapableDirectArgRune(next) {
current.WriteRune(next)
argStarted = true
i++
continue
}
current.WriteRune('\\')
argStarted = true
continue
}
if quote != 0 {
if ch == quote {
quote = 0
continue
}
current.WriteRune(ch)
argStarted = true
continue
}
switch ch {
case '\'', '"':
quote = ch
argStarted = true
case ' ', '\t', '\n', '\r':
flush()
case '|', ';', '&', '<', '>', '`':
return nil, fmt.Errorf("shell operator %q is not supported by direct command routing", ch)
default:
current.WriteRune(ch)
argStarted = true
}
}
if quote != 0 {
return nil, fmt.Errorf("unterminated quote")
}
flush()
return args, nil
}
func isEscapableDirectArgRune(ch rune) bool {
switch ch {
case '\'', '"', '\\', ' ', '\t', '\n', '\r', '|', ';', '&', '<', '>', '`':
return true
default:
return false
}
}