helpers/shell_escape.go (113 lines of code) (raw):
package helpers
// https://github.com/zimbatm/direnv/blob/master/shell.go
import (
"bytes"
"encoding/hex"
"strings"
)
/*
* Escaping
*/
const (
ACK = 6
TAB = 9
LF = 10
CR = 13
US = 31
SPACE = 32
AMPERSTAND = 38
SINGLE_QUOTE = 39
PLUS = 43
NINE = 57
QUESTION = 63
LOWERCASE_Z = 90
OPEN_BRACKET = 91
BACKSLASH = 92
UNDERSCORE = 95
CLOSE_BRACKET = 93
BACKTICK = 96
TILDA = 126
DEL = 127
)
// ShellEscape is taken from https://github.com/solidsnack/shell-escape/blob/master/Text/ShellEscape/Bash.hs
/*
A Bash escaped string. The strings are wrapped in @$\'...\'@ if any
bytes within them must be escaped; otherwise, they are left as is.
Newlines and other control characters are represented as ANSI escape
sequences. High bytes are represented as hex codes. Thus Bash escaped
strings will always fit on one line and never contain non-ASCII bytes.
*/
func ShellEscape(str string) string {
if str == "" {
return "''"
}
in := []byte(str)
out := bytes.NewBuffer(make([]byte, 0, len(str)*2))
i := 0
l := len(in)
escape := false
hex := func(char byte) {
escape = true
data := []byte{BACKSLASH, 'x', 0, 0}
hex.Encode(data[2:], []byte{char})
out.Write(data)
}
backslash := func(char byte) {
escape = true
out.Write([]byte{BACKSLASH, char})
}
escaped := func(str string) {
escape = true
out.WriteString(str)
}
quoted := func(char byte) {
escape = true
out.WriteByte(char)
}
literal := func(char byte) {
out.WriteByte(char)
}
for i < l {
char := in[i]
switch {
case char == TAB:
escaped(`\t`)
case char == LF:
escaped(`\n`)
case char == CR:
escaped(`\r`)
case char <= US:
hex(char)
case char <= AMPERSTAND:
quoted(char)
case char == SINGLE_QUOTE:
backslash(char)
case char <= PLUS:
quoted(char)
case char <= NINE:
literal(char)
case char <= QUESTION:
quoted(char)
case char <= LOWERCASE_Z:
literal(char)
case char == OPEN_BRACKET:
quoted(char)
case char == BACKSLASH:
backslash(char)
case char <= CLOSE_BRACKET:
quoted(char)
case char == UNDERSCORE:
literal(char)
case char <= BACKTICK:
quoted(char)
case char <= LOWERCASE_Z:
literal(char)
case char <= TILDA:
quoted(char)
case char == DEL:
hex(char)
default:
hex(char)
}
i++
}
outStr := out.String()
if escape {
outStr = "$'" + outStr + "'"
}
return outStr
}
func ToBackslash(path string) string {
return strings.Replace(path, "/", "\\", -1)
}
func ToSlash(path string) string {
return strings.Replace(path, "\\", "/", -1)
}