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  }