Skip to content

Commit

Permalink
expand: support character escapes in Format
Browse files Browse the repository at this point in the history
Fixes mvdan#338.
  • Loading branch information
mvdan committed Jan 1, 2019
1 parent 53ab58a commit b4690b0
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 0 deletions.
44 changes: 44 additions & 0 deletions expand/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,24 @@ func Format(cfg *Config, format string, args []string) (string, int, error) {
initialArgs := len(args)

for i := 0; i < len(format); i++ {
// readDigits reads from 0 to max digits, either octal or
// hexadecimal.
readDigits := func(max int, hex bool) string {
j := 0
for ; j < max; j++ {
c := format[i+j]
if (c >= '0' && c <= '9') ||
(hex && c >= 'a' && c <= 'f') ||
(hex && c >= 'A' && c <= 'F') {
// valid octal or hex char
} else {
break
}
}
digits := format[i : i+j]
i += j - 1 // -1 since the outer loop does i++
return digits
}
c := format[i]
switch {
case c == '\\': // escaped
Expand All @@ -217,6 +235,32 @@ func Format(cfg *Config, format string, args []string) (string, int, error) {
buf.WriteByte('\v')
case '\\', '\'', '"', '?': // just the character
buf.WriteByte(c)
case '0', '1', '2', '3', '4', '5', '6', '7':
digits := readDigits(3, false)
// if digits don't fit in 8 bits, 0xff via strconv
n, _ := strconv.ParseUint(digits, 8, 8)
buf.WriteByte(byte(n))
case 'x', 'u', 'U':
i++
max := 2
if c == 'u' {
max = 4
} else if c == 'U' {
max = 8
}
digits := readDigits(max, true)
if len(digits) > 0 {
// can't error
n, _ := strconv.ParseUint(digits, 16, 32)
if c == 'x' {
// always as a single byte
buf.WriteByte(byte(n))
} else {
buf.WriteRune(rune(n))
}
break
}
fallthrough
default: // no escape sequence
buf.WriteByte('\\')
buf.WriteByte(c)
Expand Down
4 changes: 4 additions & 0 deletions interp/interp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ var fileCases = []struct {
{`a=$"foo\nbar"; echo "$a"`, "foo\\nbar\n"},
{`echo $'\a\b\e\E\f\v'`, "\a\b\x1b\x1b\f\v\n"},
{`echo $'\\\'\"\?'`, "\\'\"?\n"},
{`echo $'\1\45\12345\777\9'`, "\x01%S45\xff\\9\n"},
{`echo $'\x\xf\x09\xAB'`, "\\x\x0f\x09\xab\n"},
{`echo $'\u\uf\u09\uABCD\u00051234'`, "\\u\u000f\u0009\uabcd\u00051234\n"},
{`echo $'\U\Uf\U09\UABCD\U00051234'`, "\\U\u000f\u0009\uabcd\U00051234\n"},

// escaped chars
{"echo a\\b", "ab\n"},
Expand Down

0 comments on commit b4690b0

Please sign in to comment.