]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: rewrite Windows makeCmdLine to use []byte
authorIan Lance Taylor <iant@golang.org>
Tue, 6 Oct 2020 23:31:00 +0000 (16:31 -0700)
committerIan Lance Taylor <iant@golang.org>
Wed, 7 Oct 2020 16:33:31 +0000 (16:33 +0000)
It's faster to append to a []byte and only convert to string at the
end then it is to build up a string by concatenating characters.

Fixes #41825

Change-Id: I45ddf77dcc62726c919f0533c95d483cee8ba366
Reviewed-on: https://go-review.googlesource.com/c/go/+/259978
Trust: Ian Lance Taylor <iant@golang.org>
Trust: Alex Brainman <alex.brainman@gmail.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
src/syscall/exec_windows.go

index 8d6141c0ca6f3914ddb222d8126136739fcedcc7..500321ef0d5a886a2124cbe452d52dc8246bde3a 100644 (file)
@@ -24,74 +24,87 @@ var ForkLock sync.RWMutex
 // - finally, s is wrapped with double quotes (arg -> "arg"),
 //   but only if there is space or tab inside s.
 func EscapeArg(s string) string {
+       for i := 0; i < len(s); i++ {
+               switch s[i] {
+               case '"', '\\', ' ', '\t':
+                       // Some escaping required.
+                       b := make([]byte, 0, len(s)+2)
+                       b = appendEscapeArg(b, s)
+                       return string(b)
+               }
+       }
+       return s
+}
+
+// appendEscapeArg escapes the string s, as per escapeArg,
+// appends the result to b, and returns the updated slice.
+func appendEscapeArg(b []byte, s string) []byte {
        if len(s) == 0 {
-               return "\"\""
+               return append(b, `""`...)
        }
-       n := len(s)
+
+       needsBackslash := false
        hasSpace := false
        for i := 0; i < len(s); i++ {
                switch s[i] {
                case '"', '\\':
-                       n++
+                       needsBackslash = true
                case ' ', '\t':
                        hasSpace = true
                }
        }
-       if hasSpace {
-               n += 2
+
+       if !needsBackslash && !hasSpace {
+               // No special handling required; normal case.
+               return append(b, s...)
        }
-       if n == len(s) {
-               return s
+       if !needsBackslash {
+               // hasSpace is true, so we need to quote the string.
+               b = append(b, '"')
+               b = append(b, s...)
+               return append(b, '"')
        }
 
-       qs := make([]byte, n)
-       j := 0
        if hasSpace {
-               qs[j] = '"'
-               j++
+               b = append(b, '"')
        }
        slashes := 0
        for i := 0; i < len(s); i++ {
-               switch s[i] {
+               c := s[i]
+               switch c {
                default:
                        slashes = 0
-                       qs[j] = s[i]
                case '\\':
                        slashes++
-                       qs[j] = s[i]
                case '"':
                        for ; slashes > 0; slashes-- {
-                               qs[j] = '\\'
-                               j++
+                               b = append(b, '\\')
                        }
-                       qs[j] = '\\'
-                       j++
-                       qs[j] = s[i]
+                       b = append(b, '\\')
                }
-               j++
+               b = append(b, c)
        }
        if hasSpace {
                for ; slashes > 0; slashes-- {
-                       qs[j] = '\\'
-                       j++
+                       b = append(b, '\\')
                }
-               qs[j] = '"'
-               j++
+               b = append(b, '"')
        }
-       return string(qs[:j])
+
+       return b
 }
 
 // makeCmdLine builds a command line out of args by escaping "special"
 // characters and joining the arguments with spaces.
 func makeCmdLine(args []string) string {
-       var s string
+       var b []byte
        for _, v := range args {
-               if s != "" {
-                       s += " "
+               if len(b) > 0 {
+                       b = append(b, ' ')
                }
-               s += EscapeArg(v)
+               b = appendEscapeArg(b, v)
        }
-       return s
+       return string(b)
 }
 
 // createEnvBlock converts an array of environment strings into