github.com/gotranspile/cxgo@v0.3.7/quote.go (about) 1 package cxgo 2 3 import ( 4 "strconv" 5 "unicode/utf8" 6 ) 7 8 const lowerhex = "0123456789abcdef" 9 10 func quoteWith(s string, quote byte) string { 11 return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote)) 12 } 13 14 func appendQuotedWith(buf []byte, s string, quote byte) []byte { 15 // Often called with big strings, so preallocate. If there's quoting, 16 // this is conservative but still helps a lot. 17 if cap(buf)-len(buf) < len(s) { 18 nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1) 19 copy(nBuf, buf) 20 buf = nBuf 21 } 22 buf = append(buf, quote) 23 for width := 0; len(s) > 0; s = s[width:] { 24 r := rune(s[0]) 25 width = 1 26 if r >= utf8.RuneSelf { 27 r, width = utf8.DecodeRuneInString(s) 28 } 29 if width == 1 && r == utf8.RuneError { 30 buf = append(buf, `\x`...) 31 buf = append(buf, lowerhex[s[0]>>4]) 32 buf = append(buf, lowerhex[s[0]&0xF]) 33 continue 34 } 35 buf = appendEscapedRune(buf, r, quote) 36 } 37 buf = append(buf, quote) 38 return buf 39 } 40 41 func appendEscapedRune(buf []byte, r rune, quote byte) []byte { 42 var runeTmp [utf8.UTFMax]byte 43 if r == rune(quote) || r == '\\' { // always backslashed 44 buf = append(buf, '\\') 45 buf = append(buf, byte(r)) 46 return buf 47 } 48 if strconv.IsPrint(r) { 49 n := utf8.EncodeRune(runeTmp[:], r) 50 buf = append(buf, runeTmp[:n]...) 51 return buf 52 } 53 switch r { 54 case '\a': 55 buf = append(buf, `\a`...) 56 case '\b': 57 buf = append(buf, `\b`...) 58 case '\f': 59 buf = append(buf, `\f`...) 60 case '\n': 61 buf = append(buf, `\n`...) 62 case '\r': 63 buf = append(buf, `\r`...) 64 case '\t': 65 buf = append(buf, `\t`...) 66 case '\v': 67 buf = append(buf, `\v`...) 68 default: 69 switch { 70 case r < ' ': 71 buf = append(buf, `\x`...) 72 buf = append(buf, lowerhex[byte(r)>>4]) 73 buf = append(buf, lowerhex[byte(r)&0xF]) 74 case r > utf8.MaxRune: 75 r = 0xFFFD 76 fallthrough 77 case r < 0x10000: 78 buf = append(buf, `\u`...) 79 for s := 12; s >= 0; s -= 4 { 80 buf = append(buf, lowerhex[r>>uint(s)&0xF]) 81 } 82 default: 83 buf = append(buf, `\U`...) 84 for s := 28; s >= 0; s -= 4 { 85 buf = append(buf, lowerhex[r>>uint(s)&0xF]) 86 } 87 } 88 } 89 return buf 90 }