@@ -18,17 +18,116 @@ package preprocessor
18
18
import (
19
19
"context"
20
20
"fmt"
21
+ "strconv"
21
22
"strings"
22
23
24
+ "github.com/arduino/arduino-cli/arduino/builder/preprocessor/ctags"
25
+ "github.com/arduino/arduino-cli/arduino/sketch"
23
26
"github.com/arduino/arduino-cli/executils"
24
27
"github.com/arduino/arduino-cli/i18n"
28
+ "github.com/arduino/arduino-cli/legacy/builder/utils"
25
29
"github.com/arduino/go-paths-helper"
26
30
"github.com/arduino/go-properties-orderedmap"
27
31
"github.com/pkg/errors"
28
32
)
29
33
30
34
var tr = i18n .Tr
31
35
36
+ // DebugPreprocessor when set to true the CTags preprocessor will output debugging info to stdout
37
+ // this is useful for unit-testing to provide more infos
38
+ var DebugPreprocessor bool
39
+
40
+ // CTags performs a run of ctags on the given source file. Returns the ctags output and the stderr contents.
41
+ func CTags (sourceFile * paths.Path , targetFile * paths.Path , sketch * sketch.Sketch , lineOffset int , buildProperties * properties.Map ) ([]byte , error ) {
42
+ ctagsOutput , ctagsStdErr , err := RunCTags (sourceFile , buildProperties )
43
+ if err != nil {
44
+ return ctagsStdErr , err
45
+ }
46
+
47
+ // func PrototypesAdder(sketch *sketch.Sketch, source string, ctagsStdout []byte, lineOffset int) string {
48
+ parser := & ctags.CTagsParser {}
49
+ prototypes , firstFunctionLine := parser .Parse (ctagsOutput , sketch .MainFile )
50
+ if firstFunctionLine == - 1 {
51
+ firstFunctionLine = 0
52
+ }
53
+
54
+ var source string
55
+ if sourceData , err := targetFile .ReadFile (); err != nil {
56
+ return nil , err
57
+ } else {
58
+ source = string (sourceData )
59
+ }
60
+ source = strings .Replace (source , "\r \n " , "\n " , - 1 )
61
+ source = strings .Replace (source , "\r " , "\n " , - 1 )
62
+ sourceRows := strings .Split (source , "\n " )
63
+ if isFirstFunctionOutsideOfSource (firstFunctionLine , sourceRows ) {
64
+ return nil , nil
65
+ }
66
+
67
+ insertionLine := firstFunctionLine + lineOffset - 1
68
+ firstFunctionChar := len (strings .Join (sourceRows [:insertionLine ], "\n " )) + 1
69
+ prototypeSection := composePrototypeSection (firstFunctionLine , prototypes )
70
+ preprocessedSource := source [:firstFunctionChar ] + prototypeSection + source [firstFunctionChar :]
71
+
72
+ if DebugPreprocessor {
73
+ fmt .Println ("#PREPROCESSED SOURCE" )
74
+ prototypesRows := strings .Split (prototypeSection , "\n " )
75
+ prototypesRows = prototypesRows [:len (prototypesRows )- 1 ]
76
+ for i := 0 ; i < len (sourceRows )+ len (prototypesRows ); i ++ {
77
+ if i < insertionLine {
78
+ fmt .Printf (" |%s\n " , sourceRows [i ])
79
+ } else if i < insertionLine + len (prototypesRows ) {
80
+ fmt .Printf ("PRO|%s\n " , prototypesRows [i - insertionLine ])
81
+ } else {
82
+ fmt .Printf (" |%s\n " , sourceRows [i - len (prototypesRows )])
83
+ }
84
+ }
85
+ fmt .Println ("#END OF PREPROCESSED SOURCE" )
86
+ }
87
+
88
+ err = targetFile .WriteFile ([]byte (preprocessedSource ))
89
+ return ctagsStdErr , err
90
+ }
91
+
92
+ func composePrototypeSection (line int , prototypes []* ctags.Prototype ) string {
93
+ if len (prototypes ) == 0 {
94
+ return ""
95
+ }
96
+
97
+ str := joinPrototypes (prototypes )
98
+ str += "\n #line "
99
+ str += strconv .Itoa (line )
100
+ str += " " + utils .QuoteCppString (prototypes [0 ].File )
101
+ str += "\n "
102
+
103
+ return str
104
+ }
105
+
106
+ func joinPrototypes (prototypes []* ctags.Prototype ) string {
107
+ prototypesSlice := []string {}
108
+ for _ , proto := range prototypes {
109
+ if signatureContainsaDefaultArg (proto ) {
110
+ continue
111
+ }
112
+ prototypesSlice = append (prototypesSlice , "#line " + strconv .Itoa (proto .Line )+ " " + utils .QuoteCppString (proto .File ))
113
+ prototypeParts := []string {}
114
+ if proto .Modifiers != "" {
115
+ prototypeParts = append (prototypeParts , proto .Modifiers )
116
+ }
117
+ prototypeParts = append (prototypeParts , proto .Prototype )
118
+ prototypesSlice = append (prototypesSlice , strings .Join (prototypeParts , " " ))
119
+ }
120
+ return strings .Join (prototypesSlice , "\n " )
121
+ }
122
+
123
+ func signatureContainsaDefaultArg (proto * ctags.Prototype ) bool {
124
+ return strings .Contains (proto .Prototype , "=" )
125
+ }
126
+
127
+ func isFirstFunctionOutsideOfSource (firstFunctionLine int , sourceRows []string ) bool {
128
+ return firstFunctionLine > len (sourceRows )- 1
129
+ }
130
+
32
131
// RunCTags performs a run of ctags on the given source file. Returns the ctags output and the stderr contents.
33
132
func RunCTags (sourceFile * paths.Path , buildProperties * properties.Map ) ([]byte , []byte , error ) {
34
133
ctagsBuildProperties := properties .NewMap ()
0 commit comments