use build-in functions to quote / unquote

This commit is contained in:
boombuler
2016-09-03 12:02:49 +02:00
parent 699ad316e5
commit b2735d7b5b
2 changed files with 59 additions and 33 deletions

View File

@@ -223,32 +223,47 @@ func Abs(n int) int {
// The returned slice contains at least one string
func SplitCommandArgs(input string) []string {
var result []string
curArg := new(bytes.Buffer)
inQuote := false
escape := false
curArg := new(bytes.Buffer)
for _, r := range input {
if !escape {
switch {
case r == '\\' && inQuote:
escape = true
continue
case r == '"' && inQuote:
inQuote = false
continue
case r == '"' && !inQuote && curArg.Len() == 0:
inQuote = true
continue
case r == ' ' && !inQuote:
result = append(result, curArg.String())
curArg.Reset()
continue
appendResult := func() {
str := curArg.String()
inQuote = false
escape = false
if strings.HasPrefix(str, `"`) && strings.HasSuffix(str, `"`) {
if unquoted, err := strconv.Unquote(str); err == nil {
str = unquoted
}
}
escape = false
curArg.WriteRune(r)
result = append(result, str)
curArg.Reset()
}
result = append(result, curArg.String())
for _, r := range input {
if r == ' ' && !inQuote {
appendResult()
} else {
curArg.WriteRune(r)
if r == '"' && !inQuote {
inQuote = true
} else {
if inQuote && !escape {
if r == '"' {
inQuote = false
}
if r == '\\' {
escape = true
continue
}
}
}
}
escape = false
}
appendResult()
return result
}
@@ -262,17 +277,11 @@ func JoinCommandArgs(args ...string) string {
} else {
buf.WriteRune(' ')
}
if !strings.Contains(arg, " ") {
buf.WriteString(arg)
quoted := strconv.Quote(arg)
if quoted[1:len(quoted)-1] != arg || strings.ContainsRune(arg, ' ') {
buf.WriteString(quoted)
} else {
buf.WriteRune('"')
for _, r := range arg {
if r == '"' || r == '\\' {
buf.WriteRune('\\')
}
buf.WriteRune(r)
}
buf.WriteRune('"')
buf.WriteString(arg)
}
}

View File

@@ -77,10 +77,13 @@ func TestJoinAndSplitCommandArgs(t *testing.T) {
{[]string{`slash\\\ test`}, `"slash\\\\\\ test"`},
{[]string{`path 1`, `path\" 2`}, `"path 1" "path\\\" 2"`},
{[]string{`foo`}, `foo`},
{[]string{`foo\"bar`}, `foo\"bar`},
{[]string{`foo\"bar`}, `"foo\\\"bar"`},
{[]string{``}, ``},
{[]string{`"`}, `"\""`},
{[]string{`a`, ``}, `a `},
{[]string{``, ``, ``, ``}, ` `},
{[]string{"\n"}, `"\n"`},
{[]string{"foo\tbar"}, `"foo\tbar"`},
}
for i, test := range tests {
@@ -89,8 +92,22 @@ func TestJoinAndSplitCommandArgs(t *testing.T) {
}
if result := SplitCommandArgs(test.Wanted); !reflect.DeepEqual(test.Query, result) {
t.Errorf("SplitCommandArgs failed at Test %d\nGot: `%s`", i, result)
t.Errorf("SplitCommandArgs failed at Test %d\nGot: `%q`", i, result)
}
}
splitTests := []struct {
Query string
Wanted []string
}{
{`"hallo""Welt"`, []string{`"hallo""Welt"`}},
{`\"`, []string{`\"`}},
{`"\"`, []string{`"\"`}},
}
for i, test := range splitTests {
if result := SplitCommandArgs(test.Query); !reflect.DeepEqual(test.Wanted, result) {
t.Errorf("SplitCommandArgs failed at Split-Test %d\nGot: `%q`", i, result)
}
}
}