aboutsummaryrefslogtreecommitdiffstats
path: root/ccl.go
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2025-11-24 17:43:44 -0800
committerRose Hogenson <rosehogenson@posteo.net>2025-11-24 17:43:44 -0800
commit456b784f4ff742bf604340e62c11da47b46b2950 (patch)
tree0c8aa5fe9f44c2848247a4f7336548e967db78f0 /ccl.go
parent36acb0052bde87b82fb6c08d3a57680f8bea4e5f (diff)
downloadccl-456b784f4ff742bf604340e62c11da47b46b2950.tar.zst
Disallow control characters in strings
Diffstat (limited to 'ccl.go')
-rw-r--r--ccl.go20
1 files changed, 16 insertions, 4 deletions
diff --git a/ccl.go b/ccl.go
index 1333119..92a1a3f 100644
--- a/ccl.go
+++ b/ccl.go
@@ -42,9 +42,9 @@
//
// # Strings
//
-// Strings are written with " or ' and any sequence of intermediate bytes (with
-// the exception of escape sequences which are described below). Strings must be
-// valid UTF-8 after escape sequences are expanded.
+// Strings are written with " or ' and a (possibly empty) sequence of
+// intervening characters. Strings must be valid UTF-8 after expanding escape
+// sequences (described below).
//
// 'asdf'
// "that's cool"
@@ -55,6 +55,9 @@
// 'a multiline
// string'
//
+// Carriage returns (0x0d) are discarded from the string value. If you need a
+// string to contain carriage return, use the \r escape sequence.
+//
// Backslash characters inside a string are interpreted as an escape sequence.
// Any escape sequence not described below is an error. The escape sequences
// are identical to C11, with the exception that \x always takes exactly 2
@@ -162,6 +165,7 @@ import (
"reflect"
"strconv"
"strings"
+ "unicode"
"unicode/utf8"
)
@@ -357,8 +361,16 @@ func (p *parser) parseFloat(nBytes []byte) (float64, error) {
func (p *parser) unescape(rawStr []byte) ([]byte, error) {
var escaped []byte
for i := 0; i < len(rawStr); i++ {
+ if i+1 < len(rawStr) && rawStr[i] == '\r' && rawStr[i+1] == '\n' {
+ continue
+ }
if rawStr[i] != '\\' {
- escaped = append(escaped, rawStr[i])
+ r, n := utf8.DecodeRune(rawStr[i:])
+ if r != '\t' && r != '\n' && unicode.IsControl(r) {
+ return nil, p.error("control character %q must be escaped", r)
+ }
+ escaped = append(escaped, rawStr[i:i+n]...)
+ i += n - 1
continue
}
i++