16
16
package preprocessor
17
17
18
18
import (
19
+ "bufio"
20
+ "bytes"
19
21
"context"
20
22
"fmt"
23
+ "io"
21
24
"strconv"
22
25
"strings"
23
26
@@ -37,30 +40,74 @@ var tr = i18n.Tr
37
40
// this is useful for unit-testing to provide more infos
38
41
var DebugPreprocessor bool
39
42
40
- func CTags (sourceFile * paths.Path , targetFile * paths.Path , sketch * sketch.Sketch , lineOffset int , buildProperties * properties.Map ) ([]byte , error ) {
41
- ctagsOutput , ctagsStdErr , err := RunCTags (sourceFile , buildProperties )
43
+ // PreprocessSketchWithCtags performs preprocessing of the arduino sketch using CTags.
44
+ func PreprocessSketchWithCtags (sketch * sketch.Sketch , buildPath * paths.Path , includes paths.PathList , lineOffset int , buildProperties * properties.Map , onlyUpdateCompilationDatabase bool ) ([]byte , []byte , error ) {
45
+ // Create a temporary working directory
46
+ tmpDir , err := paths .MkTempDir ("" , "" )
42
47
if err != nil {
43
- return ctagsStdErr , err
48
+ return nil , nil , err
49
+ }
50
+ defer tmpDir .RemoveAll ()
51
+ ctagsTarget := tmpDir .Join ("sketch_merged.cpp" )
52
+
53
+ normalOutput := & bytes.Buffer {}
54
+ verboseOutput := & bytes.Buffer {}
55
+
56
+ // Run GCC preprocessor
57
+ sourceFile := buildPath .Join ("sketch" , sketch .MainFile .Base ()+ ".cpp" )
58
+ gccStdout , gccStderr , err := GCC (sourceFile , ctagsTarget , includes , buildProperties )
59
+ verboseOutput .Write (gccStdout )
60
+ verboseOutput .Write (gccStderr )
61
+ normalOutput .Write (gccStderr )
62
+ if err != nil {
63
+ if ! onlyUpdateCompilationDatabase {
64
+ return normalOutput .Bytes (), verboseOutput .Bytes (), errors .WithStack (err )
65
+ }
66
+
67
+ // Do not bail out if we are generating the compile commands database
68
+ normalOutput .WriteString (fmt .Sprintf ("%s: %s" ,
69
+ tr ("An error occurred adding prototypes" ),
70
+ tr ("the compilation database may be incomplete or inaccurate" )))
71
+ if err := sourceFile .CopyTo (ctagsTarget ); err != nil {
72
+ return normalOutput .Bytes (), verboseOutput .Bytes (), errors .WithStack (err )
73
+ }
44
74
}
45
75
46
- // func PrototypesAdder(sketch *sketch.Sketch, source string, ctagsStdout []byte, lineOffset int) string {
76
+ if src , err := ctagsTarget .ReadFile (); err == nil {
77
+ filteredSource := filterSketchSource (sketch , bytes .NewReader (src ), false )
78
+ if err := ctagsTarget .WriteFile ([]byte (filteredSource )); err != nil {
79
+ return normalOutput .Bytes (), verboseOutput .Bytes (), err
80
+ }
81
+ } else {
82
+ return normalOutput .Bytes (), verboseOutput .Bytes (), err
83
+ }
84
+
85
+ // Run CTags on gcc-preprocessed source
86
+ ctagsOutput , ctagsStdErr , err := RunCTags (ctagsTarget , buildProperties )
87
+ verboseOutput .Write (ctagsStdErr )
88
+ if err != nil {
89
+ return normalOutput .Bytes (), verboseOutput .Bytes (), err
90
+ }
91
+
92
+ // Parse CTags output
47
93
parser := & ctags.CTagsParser {}
48
94
prototypes , firstFunctionLine := parser .Parse (ctagsOutput , sketch .MainFile )
49
95
if firstFunctionLine == - 1 {
50
96
firstFunctionLine = 0
51
97
}
52
98
99
+ // Add prototypes to the original sketch source
53
100
var source string
54
- if sourceData , err := targetFile .ReadFile (); err != nil {
55
- return nil , err
56
- } else {
101
+ if sourceData , err := sourceFile .ReadFile (); err == nil {
57
102
source = string (sourceData )
103
+ } else {
104
+ return normalOutput .Bytes (), verboseOutput .Bytes (), err
58
105
}
59
106
source = strings .Replace (source , "\r \n " , "\n " , - 1 )
60
107
source = strings .Replace (source , "\r " , "\n " , - 1 )
61
108
sourceRows := strings .Split (source , "\n " )
62
109
if isFirstFunctionOutsideOfSource (firstFunctionLine , sourceRows ) {
63
- return nil , nil
110
+ return normalOutput . Bytes (), verboseOutput . Bytes () , nil
64
111
}
65
112
66
113
insertionLine := firstFunctionLine + lineOffset - 1
@@ -84,8 +131,9 @@ func CTags(sourceFile *paths.Path, targetFile *paths.Path, sketch *sketch.Sketch
84
131
fmt .Println ("#END OF PREPROCESSED SOURCE" )
85
132
}
86
133
87
- err = targetFile .WriteFile ([]byte (preprocessedSource ))
88
- return ctagsStdErr , err
134
+ // Write back arduino-preprocess output to the sourceFile
135
+ err = sourceFile .WriteFile ([]byte (preprocessedSource ))
136
+ return normalOutput .Bytes (), verboseOutput .Bytes (), err
89
137
}
90
138
91
139
func composePrototypeSection (line int , prototypes []* ctags.Prototype ) string {
@@ -157,3 +205,29 @@ func RunCTags(sourceFile *paths.Path, buildProperties *properties.Map) ([]byte,
157
205
stderr = append ([]byte (args ), stderr ... )
158
206
return stdout , stderr , err
159
207
}
208
+
209
+ func filterSketchSource (sketch * sketch.Sketch , source io.Reader , removeLineMarkers bool ) string {
210
+ fileNames := paths .NewPathList ()
211
+ fileNames .Add (sketch .MainFile )
212
+ fileNames .AddAll (sketch .OtherSketchFiles )
213
+
214
+ inSketch := false
215
+ filtered := ""
216
+
217
+ scanner := bufio .NewScanner (source )
218
+ for scanner .Scan () {
219
+ line := scanner .Text ()
220
+ if filename := cpp .ParseLineMarker (line ); filename != nil {
221
+ inSketch = fileNames .Contains (filename )
222
+ if inSketch && removeLineMarkers {
223
+ continue
224
+ }
225
+ }
226
+
227
+ if inSketch {
228
+ filtered += line + "\n "
229
+ }
230
+ }
231
+
232
+ return filtered
233
+ }
0 commit comments