diff --git a/middleware/commands.go b/middleware/commands.go index c9a4733e0..6daa4eb9e 100644 --- a/middleware/commands.go +++ b/middleware/commands.go @@ -2,6 +2,7 @@ package middleware import ( "errors" + "fmt" "runtime" "strings" "unicode" @@ -46,7 +47,7 @@ func SplitCommandAndArgs(command string) (cmd string, args []string, err error) // // Loosely based off the rules here: http://stackoverflow.com/a/4094897/1048862 // True parsing is much, much trickier. -func parseWindowsCommand(cmd string) []string { +func parseWindowsCommand2(cmd string) []string { var parts []string var part string var quoted bool @@ -97,3 +98,60 @@ func parseWindowsCommand(cmd string) []string { return parts } + +func parseWindowsCommand(cmd string) []string { + var parts []string + var part string + var inQuotes bool + var wasBackslash bool + + prefix := "DEBUG:" + + fmt.Println(prefix, "Parsing cmd:", cmd) + + for i, ch := range cmd { + fmt.Println(" ", prefix, "Looking at char:", string(ch), "at index", string(i)) + + if ch == '\\' { + wasBackslash = true + // put it in the part - for now we don't know if it's escaping char or path separator + part += string(ch) + continue + } + + if ch == '"' { + if wasBackslash { + // remove the backslash from the part and add the escaped quote instead + part = part[:len(part)-1] + part += string(ch) + wasBackslash = false + continue + } else { + // normal escaping quotes + fmt.Println(" ", prefix, "and it's a quote") + inQuotes = !inQuotes + continue + + } + } + + if unicode.IsSpace(ch) && !inQuotes && len(part) > 0 { + fmt.Println(" ", prefix, "and it's a space outside quotes") + parts = append(parts, part) + part = "" + wasBackslash = false + continue + } + + wasBackslash = false + part += string(ch) + } + + if len(part) > 0 { + parts = append(parts, part) + part = "" + } + + fmt.Println(prefix, strings.Join(parts, ",")) + return parts +} diff --git a/middleware/commands_test.go b/middleware/commands_test.go index 5274a9e33..0a2587788 100644 --- a/middleware/commands_test.go +++ b/middleware/commands_test.go @@ -7,7 +7,7 @@ import ( ) func TestParseWindowsCommand(t *testing.T) { - for i, test := range []struct { + tests := []struct { input string expected []string }{ @@ -51,25 +51,54 @@ func TestParseWindowsCommand(t *testing.T) { input: `mkdir "C:\ space"`, expected: []string{`mkdir`, `C:\ space`}, }, - { // 10 - input: `\\"`, - expected: []string{`\`}, + // 10 + { + input: `mkdir \\?\C:\Users`, + expected: []string{`mkdir`, `\\?\C:\Users`}, }, - { // 11 - input: `"\\\""`, - expected: []string{`\"`}, + // 11 + { + input: `mkdir "\\?\C:\Program Files"`, + expected: []string{`mkdir`, `\\?\C:\Program Files`}, }, - } { + } + var nTests int + for i, test := range tests { + fmt.Printf("====== Test %d ======\n", i) actual := parseWindowsCommand(test.input) if len(actual) != len(test.expected) { + fmt.Printf("Test %d: Expected %d parts, got %d: %#v", i, len(test.expected), len(actual), actual) + fmt.Println() t.Errorf("Test %d: Expected %d parts, got %d: %#v", i, len(test.expected), len(actual), actual) continue } for j := 0; j < len(actual); j++ { if expectedPart, actualPart := test.expected[j], actual[j]; expectedPart != actualPart { + fmt.Printf("Test %d: Expected: %v Actual: %v (index %d)", i, expectedPart, actualPart, j) + fmt.Println() t.Errorf("Test %d: Expected: %v Actual: %v (index %d)", i, expectedPart, actualPart, j) } } + nTests += 1 + } + + for _, test := range tests { + fmt.Printf("====== Test %d ======\n", nTests) + actual := parseWindowsCommand2(test.input) + if len(actual) != len(test.expected) { + fmt.Printf("Test %d: Expected %d parts, got %d: %#v", nTests, len(test.expected), len(actual), actual) + fmt.Println() + t.Errorf("Test %d: Expected %d parts, got %d: %#v", nTests, len(test.expected), len(actual), actual) + continue + } + for j := 0; j < len(actual); j++ { + if expectedPart, actualPart := test.expected[j], actual[j]; expectedPart != actualPart { + fmt.Printf("Test %d: Expected: %v Actual: %v (index %d)", nTests, expectedPart, actualPart, j) + fmt.Println() + t.Errorf("Test %d: Expected: %v Actual: %v (index %d)", nTests, expectedPart, actualPart, j) + } + } + nTests += 1 } }