Skip to content

Commit 9794f6d

Browse files
committed
Factored all c++ source lines parsers
1 parent 050e279 commit 9794f6d

File tree

11 files changed

+140
-103
lines changed

11 files changed

+140
-103
lines changed

arduino/builder/cpp.go renamed to arduino/builder/cpp/cpp.go

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,63 @@
1313
// Arduino software without disclosing the source code of your own applications.
1414
// To purchase a commercial license, send an email to [email protected].
1515

16-
package builder
16+
package cpp
1717

1818
import (
19+
"strconv"
1920
"strings"
2021
"unicode/utf8"
22+
23+
"github.com/arduino/go-paths-helper"
2124
)
2225

23-
// QuoteCppString returns the given string as a quoted string for use with the C
26+
// QuoteString returns the given string as a quoted string for use with the C
2427
// preprocessor. This adds double quotes around it and escapes any
2528
// double quotes and backslashes in the string.
26-
func QuoteCppString(str string) string {
29+
func QuoteString(str string) string {
2730
str = strings.Replace(str, "\\", "\\\\", -1)
2831
str = strings.Replace(str, "\"", "\\\"", -1)
2932
return "\"" + str + "\""
3033
}
3134

32-
// Parse a C-preprocessor string as emitted by the preprocessor. This
35+
// ParseLineMarker parses the given line as a gcc line marker and returns the contained
36+
// filename.
37+
func ParseLineMarker(line string) *paths.Path {
38+
// A line marker contains the line number and filename and looks like:
39+
// # 123 /path/to/file.cpp
40+
// It can be followed by zero or more flag number that indicate the
41+
// preprocessor state and can be ignored.
42+
// For exact details on this format, see:
43+
// https://github.com/gcc-mirror/gcc/blob/edd716b6b1caa1a5cb320a8cd7f626f30198e098/gcc/c-family/c-ppoutput.c#L413-L415
44+
45+
split := strings.SplitN(line, " ", 3)
46+
if len(split) < 3 || len(split[0]) == 0 || split[0][0] != '#' {
47+
return nil
48+
}
49+
50+
_, err := strconv.Atoi(split[1])
51+
if err != nil {
52+
return nil
53+
}
54+
55+
// If we get here, we found a # followed by a line number, so
56+
// assume this is a line marker and see if the rest of the line
57+
// starts with a string containing the filename
58+
str, rest, ok := ParseString(split[2])
59+
60+
if ok && (rest == "" || rest[0] == ' ') {
61+
return paths.New(str)
62+
}
63+
return nil
64+
}
65+
66+
// ParseString parse a string as emitted by the preprocessor. This
3367
// is a string contained in double quotes, with any backslashes or
3468
// quotes escaped with a backslash. If a valid string was present at the
3569
// start of the given line, returns the unquoted string contents, the
3670
// remainder of the line (everything after the closing "), and true.
3771
// Otherwise, returns the empty string, the entire line and false.
38-
func ParseCppString(line string) (string, string, bool) {
72+
func ParseString(line string) (string, string, bool) {
3973
// For details about how these strings are output by gcc, see:
4074
// https://github.com/gcc-mirror/gcc/blob/a588355ab948cf551bc9d2b89f18e5ae5140f52c/libcpp/macro.c#L491-L511
4175
// Note that the documentation suggests all non-printable

arduino/builder/cpp/cpp_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package cpp_test
17+
18+
import (
19+
"testing"
20+
21+
"github.com/arduino/arduino-cli/arduino/builder/cpp"
22+
"github.com/stretchr/testify/require"
23+
)
24+
25+
func TestParseString(t *testing.T) {
26+
_, _, ok := cpp.ParseString(`foo`)
27+
require.Equal(t, false, ok)
28+
29+
_, _, ok = cpp.ParseString(`"foo`)
30+
require.Equal(t, false, ok)
31+
32+
str, rest, ok := cpp.ParseString(`"foo"`)
33+
require.Equal(t, true, ok)
34+
require.Equal(t, `foo`, str)
35+
require.Equal(t, ``, rest)
36+
37+
str, rest, ok = cpp.ParseString(`"foo\\bar"`)
38+
require.Equal(t, true, ok)
39+
require.Equal(t, `foo\bar`, str)
40+
require.Equal(t, ``, rest)
41+
42+
str, rest, ok = cpp.ParseString(`"foo \"is\" quoted and \\\\bar\"\" escaped\\" and "then" some`)
43+
require.Equal(t, true, ok)
44+
require.Equal(t, `foo "is" quoted and \\bar"" escaped\`, str)
45+
require.Equal(t, ` and "then" some`, rest)
46+
47+
str, rest, ok = cpp.ParseString(`" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~"`)
48+
require.Equal(t, true, ok)
49+
require.Equal(t, ` !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~`, str)
50+
require.Equal(t, ``, rest)
51+
52+
str, rest, ok = cpp.ParseString(`"/home/ççç/"`)
53+
require.Equal(t, true, ok)
54+
require.Equal(t, `/home/ççç/`, str)
55+
require.Equal(t, ``, rest)
56+
57+
str, rest, ok = cpp.ParseString(`"/home/ççç/ /$sdsdd\\"`)
58+
require.Equal(t, true, ok)
59+
require.Equal(t, `/home/ççç/ /$sdsdd\`, str)
60+
require.Equal(t, ``, rest)
61+
}
62+
63+
func TestQuoteString(t *testing.T) {
64+
cases := map[string]string{
65+
`foo`: `"foo"`,
66+
`foo\bar`: `"foo\\bar"`,
67+
`foo "is" quoted and \\bar"" escaped\`: `"foo \"is\" quoted and \\\\bar\"\" escaped\\"`,
68+
// ASCII 0x20 - 0x7e, excluding `
69+
` !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~`: `" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~"`,
70+
}
71+
for input, expected := range cases {
72+
require.Equal(t, expected, cpp.QuoteString(input))
73+
}
74+
}

arduino/builder/cpp_test.go

Lines changed: 0 additions & 46 deletions
This file was deleted.

arduino/builder/preprocessor/ctags.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ import (
2121
"strconv"
2222
"strings"
2323

24+
"github.com/arduino/arduino-cli/arduino/builder/cpp"
2425
"github.com/arduino/arduino-cli/arduino/builder/preprocessor/ctags"
2526
"github.com/arduino/arduino-cli/arduino/sketch"
2627
"github.com/arduino/arduino-cli/executils"
2728
"github.com/arduino/arduino-cli/i18n"
28-
"github.com/arduino/arduino-cli/legacy/builder/utils"
2929
"github.com/arduino/go-paths-helper"
3030
"github.com/arduino/go-properties-orderedmap"
3131
"github.com/pkg/errors"
@@ -96,7 +96,7 @@ func composePrototypeSection(line int, prototypes []*ctags.Prototype) string {
9696
str := joinPrototypes(prototypes)
9797
str += "\n#line "
9898
str += strconv.Itoa(line)
99-
str += " " + utils.QuoteCppString(prototypes[0].File)
99+
str += " " + cpp.QuoteString(prototypes[0].File)
100100
str += "\n"
101101

102102
return str
@@ -108,7 +108,7 @@ func joinPrototypes(prototypes []*ctags.Prototype) string {
108108
if signatureContainsaDefaultArg(proto) {
109109
continue
110110
}
111-
prototypesSlice = append(prototypesSlice, "#line "+strconv.Itoa(proto.Line)+" "+utils.QuoteCppString(proto.File))
111+
prototypesSlice = append(prototypesSlice, "#line "+strconv.Itoa(proto.Line)+" "+cpp.QuoteString(proto.File))
112112
prototypeParts := []string{}
113113
if proto.Modifiers != "" {
114114
prototypeParts = append(prototypeParts, proto.Modifiers)

arduino/builder/sketch.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"regexp"
2222

23+
"github.com/arduino/arduino-cli/arduino/builder/cpp"
2324
"github.com/arduino/arduino-cli/arduino/sketch"
2425
"github.com/arduino/arduino-cli/i18n"
2526
"github.com/arduino/go-paths-helper"
@@ -96,7 +97,7 @@ func sketchMergeSources(sk *sketch.Sketch, overrides map[string]string) (int, st
9697
lineOffset++
9798
}
9899

99-
mergedSource += "#line 1 " + QuoteCppString(sk.MainFile.String()) + "\n"
100+
mergedSource += "#line 1 " + cpp.QuoteString(sk.MainFile.String()) + "\n"
100101
mergedSource += mainSrc + "\n"
101102
lineOffset++
102103

@@ -105,7 +106,7 @@ func sketchMergeSources(sk *sketch.Sketch, overrides map[string]string) (int, st
105106
if err != nil {
106107
return 0, "", err
107108
}
108-
mergedSource += "#line 1 " + QuoteCppString(file.String()) + "\n"
109+
mergedSource += "#line 1 " + cpp.QuoteString(file.String()) + "\n"
109110
mergedSource += src + "\n"
110111
}
111112

@@ -145,7 +146,7 @@ func sketchCopyAdditionalFiles(sketch *sketch.Sketch, destPath *paths.Path, over
145146
}
146147

147148
// tag each addtional file with the filename of the source it was copied from
148-
sourceBytes = append([]byte("#line 1 "+QuoteCppString(file.String())+"\n"), sourceBytes...)
149+
sourceBytes = append([]byte("#line 1 "+cpp.QuoteString(file.String())+"\n"), sourceBytes...)
149150

150151
err = writeIfDifferent(sourceBytes, targetPath)
151152
if err != nil {

internal/integrationtest/compile_1/compile_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
"testing"
2626
"time"
2727

28-
"github.com/arduino/arduino-cli/arduino/builder"
28+
"github.com/arduino/arduino-cli/arduino/builder/cpp"
2929
"github.com/arduino/arduino-cli/internal/integrationtest"
3030
"github.com/arduino/go-paths-helper"
3131
"github.com/stretchr/testify/require"
@@ -1191,7 +1191,7 @@ void loop() {
11911191
}
11921192
11931193
`
1194-
expected = strings.ReplaceAll(expected, "%SKETCH_PATH%", builder.QuoteCppString(sketchPath.Join("SketchSimple.ino").String()))
1194+
expected = strings.ReplaceAll(expected, "%SKETCH_PATH%", cpp.QuoteString(sketchPath.Join("SketchSimple.ino").String()))
11951195

11961196
jsonOut, _, err := cli.Run("compile", "-b", fqbn, "--preprocess", sketchPath.String(), "--format", "json")
11971197
require.NoError(t, err)

legacy/builder/container_add_prototypes.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"strconv"
2424
"strings"
2525

26-
bldr "github.com/arduino/arduino-cli/arduino/builder"
26+
"github.com/arduino/arduino-cli/arduino/builder/cpp"
2727
"github.com/arduino/arduino-cli/arduino/builder/preprocessor"
2828
"github.com/arduino/arduino-cli/arduino/sketch"
2929
"github.com/arduino/arduino-cli/legacy/builder/types"
@@ -137,7 +137,7 @@ func parseLineMarker(line string) *paths.Path {
137137
// If we get here, we found a # followed by a line number, so
138138
// assume this is a line marker and see if the rest of the line
139139
// starts with a string containing the filename
140-
str, rest, ok := bldr.ParseCppString(split[2])
140+
str, rest, ok := cpp.ParseString(split[2])
141141

142142
if ok && (rest == "" || rest[0] == ' ') {
143143
return paths.New(str)

legacy/builder/test/helper.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@ import (
2323
"testing"
2424
"text/template"
2525

26+
"github.com/arduino/arduino-cli/arduino/builder/cpp"
2627
"github.com/arduino/arduino-cli/arduino/cores"
2728
"github.com/arduino/arduino-cli/arduino/libraries"
2829
"github.com/arduino/arduino-cli/legacy/builder/constants"
2930
"github.com/arduino/arduino-cli/legacy/builder/types"
30-
"github.com/arduino/arduino-cli/legacy/builder/utils"
3131
paths "github.com/arduino/go-paths-helper"
3232
"github.com/stretchr/testify/assert"
3333
"github.com/stretchr/testify/require"
3434
)
3535

3636
func LoadAndInterpolate(t *testing.T, filename string, ctx *types.Context) string {
3737
funcsMap := template.FuncMap{
38-
"QuoteCppString": utils.QuoteCppPath,
38+
"QuoteCppString": func(p *paths.Path) string { return cpp.QuoteString(p.String()) },
3939
}
4040

4141
tpl, err := template.New(filepath.Base(filename)).Funcs(funcsMap).ParseFiles(filename)

0 commit comments

Comments
 (0)