summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/kballard/go-shellquote/quote.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/kballard/go-shellquote/quote.go')
-rw-r--r--vendor/github.com/kballard/go-shellquote/quote.go102
1 files changed, 102 insertions, 0 deletions
diff --git a/vendor/github.com/kballard/go-shellquote/quote.go b/vendor/github.com/kballard/go-shellquote/quote.go
new file mode 100644
index 00000000..72a8cb38
--- /dev/null
+++ b/vendor/github.com/kballard/go-shellquote/quote.go
@@ -0,0 +1,102 @@
+package shellquote
+
+import (
+ "bytes"
+ "strings"
+ "unicode/utf8"
+)
+
+// Join quotes each argument and joins them with a space.
+// If passed to /bin/sh, the resulting string will be split back into the
+// original arguments.
+func Join(args ...string) string {
+ var buf bytes.Buffer
+ for i, arg := range args {
+ if i != 0 {
+ buf.WriteByte(' ')
+ }
+ quote(arg, &buf)
+ }
+ return buf.String()
+}
+
+const (
+ specialChars = "\\'\"`${[|&;<>()*?!"
+ extraSpecialChars = " \t\n"
+ prefixChars = "~"
+)
+
+func quote(word string, buf *bytes.Buffer) {
+ // We want to try to produce a "nice" output. As such, we will
+ // backslash-escape most characters, but if we encounter a space, or if we
+ // encounter an extra-special char (which doesn't work with
+ // backslash-escaping) we switch over to quoting the whole word. We do this
+ // with a space because it's typically easier for people to read multi-word
+ // arguments when quoted with a space rather than with ugly backslashes
+ // everywhere.
+ origLen := buf.Len()
+
+ if len(word) == 0 {
+ // oops, no content
+ buf.WriteString("''")
+ return
+ }
+
+ cur, prev := word, word
+ atStart := true
+ for len(cur) > 0 {
+ c, l := utf8.DecodeRuneInString(cur)
+ cur = cur[l:]
+ if strings.ContainsRune(specialChars, c) || (atStart && strings.ContainsRune(prefixChars, c)) {
+ // copy the non-special chars up to this point
+ if len(cur) < len(prev) {
+ buf.WriteString(prev[0 : len(prev)-len(cur)-l])
+ }
+ buf.WriteByte('\\')
+ buf.WriteRune(c)
+ prev = cur
+ } else if strings.ContainsRune(extraSpecialChars, c) {
+ // start over in quote mode
+ buf.Truncate(origLen)
+ goto quote
+ }
+ atStart = false
+ }
+ if len(prev) > 0 {
+ buf.WriteString(prev)
+ }
+ return
+
+quote:
+ // quote mode
+ // Use single-quotes, but if we find a single-quote in the word, we need
+ // to terminate the string, emit an escaped quote, and start the string up
+ // again
+ inQuote := false
+ for len(word) > 0 {
+ i := strings.IndexRune(word, '\'')
+ if i == -1 {
+ break
+ }
+ if i > 0 {
+ if !inQuote {
+ buf.WriteByte('\'')
+ inQuote = true
+ }
+ buf.WriteString(word[0:i])
+ }
+ word = word[i+1:]
+ if inQuote {
+ buf.WriteByte('\'')
+ inQuote = false
+ }
+ buf.WriteString("\\'")
+ }
+ if len(word) > 0 {
+ if !inQuote {
+ buf.WriteByte('\'')
+ }
+ buf.WriteString(word)
+ buf.WriteByte('\'')
+ }
+}