-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathquote.go
78 lines (73 loc) · 1.56 KB
/
quote.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package luautil
import (
"strconv"
"strings"
"unicode/utf8"
)
// Quote returns a double-quoted lua string literal representing s. The
// returned string uses lua escape sequences (\t, \n, \123, \u0100) for
// control characters and non-printable characters as defined by
// IsPrint.
func Quote(s string) string {
b := &strings.Builder{}
b.Grow(3*len(s)/2)
quoteWith(b, s, '"')
return b.String()
}
func convert(char int) string {
if char < 10 {
return "00" + strconv.Itoa(char)
} else if char < 100 {
return "0" + strconv.Itoa(char)
}
return strconv.Itoa(char)
}
func quoteWith(b *strings.Builder, s string, quote byte) {
b.WriteByte(quote)
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
width = 1
if r >= utf8.RuneSelf {
r, width = utf8.DecodeRuneInString(s)
}
if width == 1 && r == utf8.RuneError {
b.WriteRune('\\')
b.WriteString(convert(int(s[0])))
continue
}
appendEscapedRune(b, r, quote)
}
b.WriteByte(quote)
}
func appendEscapedRune(b *strings.Builder, r rune, quote byte) {
var runeTmp [utf8.UTFMax]byte
if r == rune(quote) || r == '\\' { // always backslashed
b.WriteRune('\\')
b.WriteRune(r)
return
}
if strconv.IsPrint(r) {
n := utf8.EncodeRune(runeTmp[:], r)
b.Write(runeTmp[:n])
return
}
switch r {
case '\a':
b.WriteString(`\a`)
case '\b':
b.WriteString(`\b`)
case '\f':
b.WriteString(`\f`)
case '\n':
b.WriteString(`\n`)
case '\r':
b.WriteString(`\r`)
case '\t':
b.WriteString(`\t`)
case '\v':
b.WriteString(`\v`)
default:
b.WriteRune('\\')
b.WriteString(convert(int(r)))
}
}