@@ -18,17 +18,115 @@ 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
+ 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 )
42
+ if err != nil {
43
+ return ctagsStdErr , err
44
+ }
45
+
46
+ // func PrototypesAdder(sketch *sketch.Sketch, source string, ctagsStdout []byte, lineOffset int) string {
47
+ parser := & ctags.CTagsParser {}
48
+ prototypes , firstFunctionLine := parser .Parse (ctagsOutput , sketch .MainFile )
49
+ if firstFunctionLine == - 1 {
50
+ firstFunctionLine = 0
51
+ }
52
+
53
+ var source string
54
+ if sourceData , err := targetFile .ReadFile (); err != nil {
55
+ return nil , err
56
+ } else {
57
+ source = string (sourceData )
58
+ }
59
+ source = strings .Replace (source , "\r \n " , "\n " , - 1 )
60
+ source = strings .Replace (source , "\r " , "\n " , - 1 )
61
+ sourceRows := strings .Split (source , "\n " )
62
+ if isFirstFunctionOutsideOfSource (firstFunctionLine , sourceRows ) {
63
+ return nil , nil
64
+ }
65
+
66
+ insertionLine := firstFunctionLine + lineOffset - 1
67
+ firstFunctionChar := len (strings .Join (sourceRows [:insertionLine ], "\n " )) + 1
68
+ prototypeSection := composePrototypeSection (firstFunctionLine , prototypes )
69
+ preprocessedSource := source [:firstFunctionChar ] + prototypeSection + source [firstFunctionChar :]
70
+
71
+ if DebugPreprocessor {
72
+ fmt .Println ("#PREPROCESSED SOURCE" )
73
+ prototypesRows := strings .Split (prototypeSection , "\n " )
74
+ prototypesRows = prototypesRows [:len (prototypesRows )- 1 ]
75
+ for i := 0 ; i < len (sourceRows )+ len (prototypesRows ); i ++ {
76
+ if i < insertionLine {
77
+ fmt .Printf (" |%s\n " , sourceRows [i ])
78
+ } else if i < insertionLine + len (prototypesRows ) {
79
+ fmt .Printf ("PRO|%s\n " , prototypesRows [i - insertionLine ])
80
+ } else {
81
+ fmt .Printf (" |%s\n " , sourceRows [i - len (prototypesRows )])
82
+ }
83
+ }
84
+ fmt .Println ("#END OF PREPROCESSED SOURCE" )
85
+ }
86
+
87
+ err = targetFile .WriteFile ([]byte (preprocessedSource ))
88
+ return ctagsStdErr , err
89
+ }
90
+
91
+ func composePrototypeSection (line int , prototypes []* ctags.Prototype ) string {
92
+ if len (prototypes ) == 0 {
93
+ return ""
94
+ }
95
+
96
+ str := joinPrototypes (prototypes )
97
+ str += "\n #line "
98
+ str += strconv .Itoa (line )
99
+ str += " " + utils .QuoteCppString (prototypes [0 ].File )
100
+ str += "\n "
101
+
102
+ return str
103
+ }
104
+
105
+ func joinPrototypes (prototypes []* ctags.Prototype ) string {
106
+ prototypesSlice := []string {}
107
+ for _ , proto := range prototypes {
108
+ if signatureContainsaDefaultArg (proto ) {
109
+ continue
110
+ }
111
+ prototypesSlice = append (prototypesSlice , "#line " + strconv .Itoa (proto .Line )+ " " + utils .QuoteCppString (proto .File ))
112
+ prototypeParts := []string {}
113
+ if proto .Modifiers != "" {
114
+ prototypeParts = append (prototypeParts , proto .Modifiers )
115
+ }
116
+ prototypeParts = append (prototypeParts , proto .Prototype )
117
+ prototypesSlice = append (prototypesSlice , strings .Join (prototypeParts , " " ))
118
+ }
119
+ return strings .Join (prototypesSlice , "\n " )
120
+ }
121
+
122
+ func signatureContainsaDefaultArg (proto * ctags.Prototype ) bool {
123
+ return strings .Contains (proto .Prototype , "=" )
124
+ }
125
+
126
+ func isFirstFunctionOutsideOfSource (firstFunctionLine int , sourceRows []string ) bool {
127
+ return firstFunctionLine > len (sourceRows )- 1
128
+ }
129
+
32
130
func RunCTags (sourceFile * paths.Path , buildProperties * properties.Map ) ([]byte , []byte , error ) {
33
131
ctagsBuildProperties := properties .NewMap ()
34
132
ctagsBuildProperties .Set ("tools.ctags.path" , "{runtime.tools.ctags.path}" )
0 commit comments