Skip to content

Commit b4690b0

Browse files
committed
expand: support character escapes in Format
Fixes mvdan#338.
1 parent 53ab58a commit b4690b0

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

expand/expand.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,24 @@ func Format(cfg *Config, format string, args []string) (string, int, error) {
194194
initialArgs := len(args)
195195

196196
for i := 0; i < len(format); i++ {
197+
// readDigits reads from 0 to max digits, either octal or
198+
// hexadecimal.
199+
readDigits := func(max int, hex bool) string {
200+
j := 0
201+
for ; j < max; j++ {
202+
c := format[i+j]
203+
if (c >= '0' && c <= '9') ||
204+
(hex && c >= 'a' && c <= 'f') ||
205+
(hex && c >= 'A' && c <= 'F') {
206+
// valid octal or hex char
207+
} else {
208+
break
209+
}
210+
}
211+
digits := format[i : i+j]
212+
i += j - 1 // -1 since the outer loop does i++
213+
return digits
214+
}
197215
c := format[i]
198216
switch {
199217
case c == '\\': // escaped
@@ -217,6 +235,32 @@ func Format(cfg *Config, format string, args []string) (string, int, error) {
217235
buf.WriteByte('\v')
218236
case '\\', '\'', '"', '?': // just the character
219237
buf.WriteByte(c)
238+
case '0', '1', '2', '3', '4', '5', '6', '7':
239+
digits := readDigits(3, false)
240+
// if digits don't fit in 8 bits, 0xff via strconv
241+
n, _ := strconv.ParseUint(digits, 8, 8)
242+
buf.WriteByte(byte(n))
243+
case 'x', 'u', 'U':
244+
i++
245+
max := 2
246+
if c == 'u' {
247+
max = 4
248+
} else if c == 'U' {
249+
max = 8
250+
}
251+
digits := readDigits(max, true)
252+
if len(digits) > 0 {
253+
// can't error
254+
n, _ := strconv.ParseUint(digits, 16, 32)
255+
if c == 'x' {
256+
// always as a single byte
257+
buf.WriteByte(byte(n))
258+
} else {
259+
buf.WriteRune(rune(n))
260+
}
261+
break
262+
}
263+
fallthrough
220264
default: // no escape sequence
221265
buf.WriteByte('\\')
222266
buf.WriteByte(c)

interp/interp_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ var fileCases = []struct {
233233
{`a=$"foo\nbar"; echo "$a"`, "foo\\nbar\n"},
234234
{`echo $'\a\b\e\E\f\v'`, "\a\b\x1b\x1b\f\v\n"},
235235
{`echo $'\\\'\"\?'`, "\\'\"?\n"},
236+
{`echo $'\1\45\12345\777\9'`, "\x01%S45\xff\\9\n"},
237+
{`echo $'\x\xf\x09\xAB'`, "\\x\x0f\x09\xab\n"},
238+
{`echo $'\u\uf\u09\uABCD\u00051234'`, "\\u\u000f\u0009\uabcd\u00051234\n"},
239+
{`echo $'\U\Uf\U09\UABCD\U00051234'`, "\\U\u000f\u0009\uabcd\U00051234\n"},
236240

237241
// escaped chars
238242
{"echo a\\b", "ab\n"},

0 commit comments

Comments
 (0)