1616package preprocessor
1717
1818import (
19+ "bufio"
20+ "bytes"
1921 "context"
2022 "fmt"
23+ "io"
2124 "strconv"
2225 "strings"
2326
@@ -37,30 +40,74 @@ var tr = i18n.Tr
3740// this is useful for unit-testing to provide more infos
3841var DebugPreprocessor bool
3942
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 ("" , "" )
4247 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+ }
4474 }
4575
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
4793 parser := & ctags.CTagsParser {}
4894 prototypes , firstFunctionLine := parser .Parse (ctagsOutput , sketch .MainFile )
4995 if firstFunctionLine == - 1 {
5096 firstFunctionLine = 0
5197 }
5298
99+ // Add prototypes to the original sketch source
53100 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 {
57102 source = string (sourceData )
103+ } else {
104+ return normalOutput .Bytes (), verboseOutput .Bytes (), err
58105 }
59106 source = strings .Replace (source , "\r \n " , "\n " , - 1 )
60107 source = strings .Replace (source , "\r " , "\n " , - 1 )
61108 sourceRows := strings .Split (source , "\n " )
62109 if isFirstFunctionOutsideOfSource (firstFunctionLine , sourceRows ) {
63- return nil , nil
110+ return normalOutput . Bytes (), verboseOutput . Bytes () , nil
64111 }
65112
66113 insertionLine := firstFunctionLine + lineOffset - 1
@@ -84,8 +131,9 @@ func CTags(sourceFile *paths.Path, targetFile *paths.Path, sketch *sketch.Sketch
84131 fmt .Println ("#END OF PREPROCESSED SOURCE" )
85132 }
86133
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
89137}
90138
91139func composePrototypeSection (line int , prototypes []* ctags.Prototype ) string {
@@ -157,3 +205,29 @@ func RunCTags(sourceFile *paths.Path, buildProperties *properties.Map) ([]byte,
157205 stderr = append ([]byte (args ), stderr ... )
158206 return stdout , stderr , err
159207}
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