55 lines
1.5 KiB
Go
55 lines
1.5 KiB
Go
package windows
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
var ErrInvalidCommandLineArgument = errors.New("Windows command-line argument contains NUL or invalid UTF-8")
|
|
|
|
// BuildCommandLine constructs the lpCommandLine string for an explicit
|
|
// lpApplicationName. It implements the CommandLineToArgvW-compatible escaping
|
|
// convention: quotes are escaped by a preceding run of backslashes and trailing
|
|
// backslashes inside a quoted argument are doubled.
|
|
func BuildCommandLine(arguments []string) (string, error) {
|
|
if len(arguments) == 0 {
|
|
return "", nil
|
|
}
|
|
quoted := make([]string, len(arguments))
|
|
for index, argument := range arguments {
|
|
if strings.IndexByte(argument, 0) >= 0 || !utf8.ValidString(argument) {
|
|
return "", ErrInvalidCommandLineArgument
|
|
}
|
|
quoted[index] = quoteArgument(argument)
|
|
}
|
|
return strings.Join(quoted, " "), nil
|
|
}
|
|
|
|
func quoteArgument(argument string) string {
|
|
if argument != "" && !strings.ContainsAny(argument, " \t\n\v\"") {
|
|
return argument
|
|
}
|
|
var output strings.Builder
|
|
output.Grow(len(argument) + 2)
|
|
output.WriteByte('"')
|
|
backslashes := 0
|
|
for _, character := range argument {
|
|
switch character {
|
|
case '\\':
|
|
backslashes++
|
|
case '"':
|
|
output.WriteString(strings.Repeat("\\", backslashes*2+1))
|
|
output.WriteRune(character)
|
|
backslashes = 0
|
|
default:
|
|
output.WriteString(strings.Repeat("\\", backslashes))
|
|
output.WriteRune(character)
|
|
backslashes = 0
|
|
}
|
|
}
|
|
output.WriteString(strings.Repeat("\\", backslashes*2))
|
|
output.WriteByte('"')
|
|
return output.String()
|
|
}
|