Skip to content

Commit e418963

Browse files
Add utils.ParseCppString function function function function
This allows properly parsing and unescaping a string literal. This function is not currently used (it was written to prepare for better parsing of #line directives, which might or might not be added later), but it might be relevant for other things in the future as well. Signed-off-by: Matthijs Kooijman <[email protected]>
1 parent a2eb033 commit e418963

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

src/arduino.cc/builder/test/utils_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,31 @@ func TestQuoteCppString(t *testing.T) {
100100
require.Equal(t, expected, utils.QuoteCppString(input))
101101
}
102102
}
103+
104+
func TestParseCppString(t *testing.T) {
105+
str, rest, ok := utils.ParseCppString(`foo`)
106+
require.Equal(t, false, ok)
107+
108+
str, rest, ok = utils.ParseCppString(`"foo`)
109+
require.Equal(t, false, ok)
110+
111+
str, rest, ok = utils.ParseCppString(`"foo"`)
112+
require.Equal(t, true, ok)
113+
require.Equal(t, `foo`, str)
114+
require.Equal(t, ``, rest)
115+
116+
str, rest, ok = utils.ParseCppString(`"foo\\bar"`)
117+
require.Equal(t, true, ok)
118+
require.Equal(t, `foo\bar`, str)
119+
require.Equal(t, ``, rest)
120+
121+
str, rest, ok = utils.ParseCppString(`"foo \"is\" quoted and \\\\bar\"\" escaped\\" and "then" some`)
122+
require.Equal(t, true, ok)
123+
require.Equal(t, `foo "is" quoted and \\bar"" escaped\`, str)
124+
require.Equal(t, ` and "then" some`, rest)
125+
126+
str, rest, ok = utils.ParseCppString(`" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~"`,)
127+
require.Equal(t, true, ok)
128+
require.Equal(t, ` !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~`, str)
129+
require.Equal(t, ``, rest)
130+
}

src/arduino.cc/builder/utils/utils.go

+44
Original file line numberDiff line numberDiff line change
@@ -416,3 +416,47 @@ func QuoteCppString(str string) string {
416416
str = strings.Replace(str, "\"", "\\\"", -1)
417417
return "\"" + str + "\""
418418
}
419+
420+
// Parse a C-preprocessor string as emitted by the preprocessor. This
421+
// is a string contained in double quotes, with any backslashes or
422+
// quotes escaped with a backslash. If a valid string was present at the
423+
// start of the given line, returns the unquoted string contents, the
424+
// remaineder of the line (everything after the closing "), and true.
425+
// Otherwise, returns the empty string, the entire line and false.
426+
func ParseCppString(line string) (string, string, bool) {
427+
// For details about how these strings are output by gcc, see:
428+
// https://github.com/gcc-mirror/gcc/blob/a588355ab948cf551bc9d2b89f18e5ae5140f52c/libcpp/macro.c#L491-L511
429+
// Note that the documentaiton suggests all non-printable
430+
// characters are also escaped, but the implementation does not
431+
// actually do this. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51259
432+
if len(line) < 1 || line[0] != '"' {
433+
return "", line, false
434+
}
435+
436+
i := 1
437+
res := ""
438+
for {
439+
if i >= len(line) {
440+
return "", line, false
441+
}
442+
443+
switch (line[i]) {
444+
// Backslash, next character is used unmodified
445+
case '\\':
446+
i++
447+
if i >= len(line) {
448+
return "", line, false
449+
}
450+
res += string(line[i])
451+
break
452+
// Quote, end of string
453+
case '"':
454+
return res, line[i+1:], true
455+
default:
456+
res += string(line[i])
457+
break
458+
}
459+
460+
i++
461+
}
462+
}

0 commit comments

Comments
 (0)