OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [strconv/] [quote.go] - Blame information for rev 867

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
package strconv
6
 
7
import (
8
        "bytes"
9
        "strings"
10
        "unicode"
11
        "unicode/utf8"
12
)
13
 
14
const lowerhex = "0123456789abcdef"
15
 
16
func quoteWith(s string, quote byte, ASCIIonly bool) string {
17
        var buf bytes.Buffer
18
        buf.WriteByte(quote)
19
        for width := 0; len(s) > 0; s = s[width:] {
20
                r := rune(s[0])
21
                width = 1
22
                if r >= utf8.RuneSelf {
23
                        r, width = utf8.DecodeRuneInString(s)
24
                }
25
                if width == 1 && r == utf8.RuneError {
26
                        buf.WriteString(`\x`)
27
                        buf.WriteByte(lowerhex[s[0]>>4])
28
                        buf.WriteByte(lowerhex[s[0]&0xF])
29
                        continue
30
                }
31
                if r == rune(quote) || r == '\\' { // always backslashed
32
                        buf.WriteByte('\\')
33
                        buf.WriteByte(byte(r))
34
                        continue
35
                }
36
                if ASCIIonly {
37
                        if r <= unicode.MaxASCII && unicode.IsPrint(r) {
38
                                buf.WriteRune(r)
39
                                continue
40
                        }
41
                } else if unicode.IsPrint(r) {
42
                        buf.WriteRune(r)
43
                        continue
44
                }
45
                switch r {
46
                case '\a':
47
                        buf.WriteString(`\a`)
48
                case '\b':
49
                        buf.WriteString(`\b`)
50
                case '\f':
51
                        buf.WriteString(`\f`)
52
                case '\n':
53
                        buf.WriteString(`\n`)
54
                case '\r':
55
                        buf.WriteString(`\r`)
56
                case '\t':
57
                        buf.WriteString(`\t`)
58
                case '\v':
59
                        buf.WriteString(`\v`)
60
                default:
61
                        switch {
62
                        case r < ' ':
63
                                buf.WriteString(`\x`)
64
                                buf.WriteByte(lowerhex[s[0]>>4])
65
                                buf.WriteByte(lowerhex[s[0]&0xF])
66
                        case r > unicode.MaxRune:
67
                                r = 0xFFFD
68
                                fallthrough
69
                        case r < 0x10000:
70
                                buf.WriteString(`\u`)
71
                                for s := 12; s >= 0; s -= 4 {
72
                                        buf.WriteByte(lowerhex[r>>uint(s)&0xF])
73
                                }
74
                        default:
75
                                buf.WriteString(`\U`)
76
                                for s := 28; s >= 0; s -= 4 {
77
                                        buf.WriteByte(lowerhex[r>>uint(s)&0xF])
78
                                }
79
                        }
80
                }
81
        }
82
        buf.WriteByte(quote)
83
        return buf.String()
84
 
85
}
86
 
87
// Quote returns a double-quoted Go string literal representing s.  The
88
// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
89
// control characters and non-printable characters as defined by
90
// unicode.IsPrint.
91
func Quote(s string) string {
92
        return quoteWith(s, '"', false)
93
}
94
 
95
// AppendQuote appends a double-quoted Go string literal representing s,
96
// as generated by Quote, to dst and returns the extended buffer.
97
func AppendQuote(dst []byte, s string) []byte {
98
        return append(dst, Quote(s)...)
99
}
100
 
101
// QuoteToASCII returns a double-quoted Go string literal representing s.
102
// The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
103
// non-ASCII characters and non-printable characters as defined by
104
// unicode.IsPrint.
105
func QuoteToASCII(s string) string {
106
        return quoteWith(s, '"', true)
107
}
108
 
109
// AppendQuoteToASCII appends a double-quoted Go string literal representing s,
110
// as generated by QuoteToASCII, to dst and returns the extended buffer.
111
func AppendQuoteToASCII(dst []byte, s string) []byte {
112
        return append(dst, QuoteToASCII(s)...)
113
}
114
 
115
// QuoteRune returns a single-quoted Go character literal representing the
116
// rune.  The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
117
// for control characters and non-printable characters as defined by
118
// unicode.IsPrint.
119
func QuoteRune(r rune) string {
120
        // TODO: avoid the allocation here.
121
        return quoteWith(string(r), '\'', false)
122
}
123
 
124
// AppendQuoteRune appends a single-quoted Go character literal representing the rune,
125
// as generated by QuoteRune, to dst and returns the extended buffer.
126
func AppendQuoteRune(dst []byte, r rune) []byte {
127
        return append(dst, QuoteRune(r)...)
128
}
129
 
130
// QuoteRuneToASCII returns a single-quoted Go character literal representing
131
// the rune.  The returned string uses Go escape sequences (\t, \n, \xFF,
132
// \u0100) for non-ASCII characters and non-printable characters as defined
133
// by unicode.IsPrint.
134
func QuoteRuneToASCII(r rune) string {
135
        // TODO: avoid the allocation here.
136
        return quoteWith(string(r), '\'', true)
137
}
138
 
139
// AppendQuoteRune appends a single-quoted Go character literal representing the rune,
140
// as generated by QuoteRuneToASCII, to dst and returns the extended buffer.
141
func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
142
        return append(dst, QuoteRuneToASCII(r)...)
143
}
144
 
145
// CanBackquote returns whether the string s would be
146
// a valid Go string literal if enclosed in backquotes.
147
func CanBackquote(s string) bool {
148
        for i := 0; i < len(s); i++ {
149
                if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
150
                        return false
151
                }
152
        }
153
        return true
154
}
155
 
156
func unhex(b byte) (v rune, ok bool) {
157
        c := rune(b)
158
        switch {
159
        case '0' <= c && c <= '9':
160
                return c - '0', true
161
        case 'a' <= c && c <= 'f':
162
                return c - 'a' + 10, true
163
        case 'A' <= c && c <= 'F':
164
                return c - 'A' + 10, true
165
        }
166
        return
167
}
168
 
169
// UnquoteChar decodes the first character or byte in the escaped string
170
// or character literal represented by the string s.
171
// It returns four values:
172
//
173
//      1) value, the decoded Unicode code point or byte value;
174
//      2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation;
175
//      3) tail, the remainder of the string after the character; and
176
//      4) an error that will be nil if the character is syntactically valid.
177
//
178
// The second argument, quote, specifies the type of literal being parsed
179
// and therefore which escaped quote character is permitted.
180
// If set to a single quote, it permits the sequence \' and disallows unescaped '.
181
// If set to a double quote, it permits \" and disallows unescaped ".
182
// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
183
func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) {
184
        // easy cases
185
        switch c := s[0]; {
186
        case c == quote && (quote == '\'' || quote == '"'):
187
                err = ErrSyntax
188
                return
189
        case c >= utf8.RuneSelf:
190
                r, size := utf8.DecodeRuneInString(s)
191
                return r, true, s[size:], nil
192
        case c != '\\':
193
                return rune(s[0]), false, s[1:], nil
194
        }
195
 
196
        // hard case: c is backslash
197
        if len(s) <= 1 {
198
                err = ErrSyntax
199
                return
200
        }
201
        c := s[1]
202
        s = s[2:]
203
 
204
        switch c {
205
        case 'a':
206
                value = '\a'
207
        case 'b':
208
                value = '\b'
209
        case 'f':
210
                value = '\f'
211
        case 'n':
212
                value = '\n'
213
        case 'r':
214
                value = '\r'
215
        case 't':
216
                value = '\t'
217
        case 'v':
218
                value = '\v'
219
        case 'x', 'u', 'U':
220
                n := 0
221
                switch c {
222
                case 'x':
223
                        n = 2
224
                case 'u':
225
                        n = 4
226
                case 'U':
227
                        n = 8
228
                }
229
                var v rune
230
                if len(s) < n {
231
                        err = ErrSyntax
232
                        return
233
                }
234
                for j := 0; j < n; j++ {
235
                        x, ok := unhex(s[j])
236
                        if !ok {
237
                                err = ErrSyntax
238
                                return
239
                        }
240
                        v = v<<4 | x
241
                }
242
                s = s[n:]
243
                if c == 'x' {
244
                        // single-byte string, possibly not UTF-8
245
                        value = v
246
                        break
247
                }
248
                if v > unicode.MaxRune {
249
                        err = ErrSyntax
250
                        return
251
                }
252
                value = v
253
                multibyte = true
254
        case '0', '1', '2', '3', '4', '5', '6', '7':
255
                v := rune(c) - '0'
256
                if len(s) < 2 {
257
                        err = ErrSyntax
258
                        return
259
                }
260
                for j := 0; j < 2; j++ { // one digit already; two more
261
                        x := rune(s[j]) - '0'
262
                        if x < 0 || x > 7 {
263
                                err = ErrSyntax
264
                                return
265
                        }
266
                        v = (v << 3) | x
267
                }
268
                s = s[2:]
269
                if v > 255 {
270
                        err = ErrSyntax
271
                        return
272
                }
273
                value = v
274
        case '\\':
275
                value = '\\'
276
        case '\'', '"':
277
                if c != quote {
278
                        err = ErrSyntax
279
                        return
280
                }
281
                value = rune(c)
282
        default:
283
                err = ErrSyntax
284
                return
285
        }
286
        tail = s
287
        return
288
}
289
 
290
// Unquote interprets s as a single-quoted, double-quoted,
291
// or backquoted Go string literal, returning the string value
292
// that s quotes.  (If s is single-quoted, it would be a Go
293
// character literal; Unquote returns the corresponding
294
// one-character string.)
295
func Unquote(s string) (t string, err error) {
296
        n := len(s)
297
        if n < 2 {
298
                return "", ErrSyntax
299
        }
300
        quote := s[0]
301
        if quote != s[n-1] {
302
                return "", ErrSyntax
303
        }
304
        s = s[1 : n-1]
305
 
306
        if quote == '`' {
307
                if strings.Contains(s, "`") {
308
                        return "", ErrSyntax
309
                }
310
                return s, nil
311
        }
312
        if quote != '"' && quote != '\'' {
313
                return "", ErrSyntax
314
        }
315
        if strings.Index(s, "\n") >= 0 {
316
                return "", ErrSyntax
317
        }
318
 
319
        // Is it trivial?  Avoid allocation.
320
        if strings.Index(s, `\`) < 0 && strings.IndexRune(s, rune(quote)) < 0 {
321
                switch quote {
322
                case '"':
323
                        return s, nil
324
                case '\'':
325
                        r, size := utf8.DecodeRuneInString(s)
326
                        if size == len(s) && (r != utf8.RuneError || size != 1) {
327
                                return s, nil
328
                        }
329
                }
330
        }
331
 
332
        var buf bytes.Buffer
333
        for len(s) > 0 {
334
                c, multibyte, ss, err := UnquoteChar(s, quote)
335
                if err != nil {
336
                        return "", err
337
                }
338
                s = ss
339
                if c < utf8.RuneSelf || !multibyte {
340
                        buf.WriteByte(byte(c))
341
                } else {
342
                        buf.WriteString(string(c))
343
                }
344
                if quote == '\'' && len(s) != 0 {
345
                        // single-quoted must be single character
346
                        return "", ErrSyntax
347
                }
348
        }
349
        return buf.String(), nil
350
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.