github.com/ladydascalie/elvish@v0.0.0-20170703214355-2964dd3ece7f/parse/quote.go (about) 1 package parse 2 3 import ( 4 "bytes" 5 "unicode" 6 ) 7 8 var QuotingStyles = []struct { 9 Type PrimaryType 10 Quoter string 11 }{ 12 {SingleQuoted, "'"}, 13 {DoubleQuoted, "\""}, 14 } 15 16 // Quote returns a representation of s in elvish syntax. Bareword is tried 17 // first, then single quoted string and finally double quoted string. 18 func Quote(s string) string { 19 s, _ = QuoteAs(s, Bareword) 20 return s 21 } 22 23 // QuoteAs returns a representation of s in elvish syntax, using the syntax 24 // specified by q, which must be one of Bareword, SingleQuoted, or 25 // DoubleQuoted. It returns the quoted string and the actual quoting. 26 func QuoteAs(s string, q PrimaryType) (string, PrimaryType) { 27 if q == DoubleQuoted { 28 // Everything can be quoted using double quotes, return directly. 29 return quoteDouble(s), DoubleQuoted 30 } 31 if s == "" { 32 return "''", SingleQuoted 33 } 34 35 // Keep track of whether it is a valid bareword. 36 bare := s[0] != '~' 37 for _, r := range s { 38 if !unicode.IsPrint(r) { 39 // Contains unprintable character; force double quote. 40 return quoteDouble(s), DoubleQuoted 41 } 42 if !allowedInBareword(r, false) { 43 bare = false 44 } 45 } 46 47 if q == Bareword && bare { 48 return s, Bareword 49 } 50 return quoteSingle(s), SingleQuoted 51 } 52 53 func quoteSingle(s string) string { 54 var buf bytes.Buffer 55 buf.WriteByte('\'') 56 for _, r := range s { 57 buf.WriteRune(r) 58 if r == '\'' { 59 buf.WriteByte('\'') 60 } 61 } 62 buf.WriteByte('\'') 63 return buf.String() 64 } 65 66 func rtohex(r rune, w int) []byte { 67 bytes := make([]byte, w) 68 for i := w - 1; i >= 0; i-- { 69 d := byte(r % 16) 70 r /= 16 71 if d <= 9 { 72 bytes[i] = '0' + d 73 } else { 74 bytes[i] = 'a' + d - 10 75 } 76 } 77 return bytes 78 } 79 80 func quoteDouble(s string) string { 81 var buf bytes.Buffer 82 buf.WriteByte('"') 83 for _, r := range s { 84 if e, ok := doubleUnescape[r]; ok { 85 // Takes care of " and \ as well. 86 buf.WriteByte('\\') 87 buf.WriteRune(e) 88 } else if !unicode.IsPrint(r) { 89 buf.WriteByte('\\') 90 if r <= 0xff { 91 buf.WriteByte('x') 92 buf.Write(rtohex(r, 2)) 93 } else if r <= 0xffff { 94 buf.WriteByte('u') 95 buf.Write(rtohex(r, 4)) 96 } else { 97 buf.WriteByte('U') 98 buf.Write(rtohex(r, 8)) 99 } 100 } else { 101 buf.WriteRune(r) 102 } 103 } 104 buf.WriteByte('"') 105 return buf.String() 106 }