Skip to content

Commit 991949b

Browse files
committed
Add step to correct tags data C linkage
1 parent 251ddae commit 991949b

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* This file is part of Arduino Builder.
3+
*
4+
* Arduino Builder is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*
18+
* As a special exception, you may use this file as part of a free software
19+
* library without restriction. Specifically, if other files instantiate
20+
* templates or use macros or inline functions from this file, or you compile
21+
* this file and link it with other files to produce an executable, this
22+
* file does not by itself cause the resulting executable to be covered by
23+
* the GNU General Public License. This exception does not however
24+
* invalidate any other reasons why the executable file might be covered by
25+
* the GNU General Public License.
26+
*
27+
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
28+
*/
29+
30+
package ctags
31+
32+
import (
33+
"bufio"
34+
"os"
35+
"strings"
36+
37+
"arduino.cc/builder/types"
38+
)
39+
40+
func (p *CTagsParser) FixCLinkageTagsDeclarations(tags []*types.CTag) {
41+
42+
linesMap := p.FindCLinkageLines(tags)
43+
for i, _ := range tags {
44+
45+
if sliceContainsInt(linesMap[tags[i].Filename], tags[i].Line) &&
46+
!strings.Contains(tags[i].PrototypeModifiers, EXTERN) {
47+
tags[i].PrototypeModifiers = tags[i].PrototypeModifiers + " " + EXTERN
48+
}
49+
}
50+
}
51+
52+
func sliceContainsInt(s []int, e int) bool {
53+
for _, a := range s {
54+
if a == e {
55+
return true
56+
}
57+
}
58+
return false
59+
}
60+
61+
/* This function scans the source files searching for "extern C" context
62+
* It save the line numbers in a map filename -> {lines...}
63+
*/
64+
func (p *CTagsParser) FindCLinkageLines(tags []*types.CTag) map[string][]int {
65+
66+
lines := make(map[string][]int)
67+
68+
for _, tag := range tags {
69+
70+
if lines[tag.Filename] != nil {
71+
break
72+
}
73+
74+
file, err := os.Open(tag.Filename)
75+
if err == nil {
76+
defer file.Close()
77+
78+
lines[tag.Filename] = append(lines[tag.Filename], 0)
79+
80+
scanner := bufio.NewScanner(file)
81+
82+
// we can't remove the comments otherwise the line number will be wrong
83+
// there are three cases:
84+
// 1 - extern "C" void foo()
85+
// 2 - extern "C" {
86+
// void foo();
87+
// void bar();
88+
// }
89+
// 3 - extern "C"
90+
// {
91+
// void foo();
92+
// void bar();
93+
// }
94+
// case 1 and 2 can be simply recognized with string matching and indent level count
95+
// case 3 needs specia attention: if the line ONLY contains `extern "C"` string, don't bail out on indent level = 0
96+
97+
inScope := false
98+
enteringScope := false
99+
indentLevels := 0
100+
line := 0
101+
102+
externCDecl := removeSpacesAndTabs(EXTERN)
103+
104+
for scanner.Scan() {
105+
line++
106+
str := removeSpacesAndTabs(scanner.Text())
107+
108+
if len(str) == 0 {
109+
continue
110+
}
111+
112+
// check if we are on the first non empty line after externCDecl in case 3
113+
if enteringScope == true {
114+
enteringScope = false
115+
}
116+
117+
// check if the line contains externCDecl
118+
if strings.Contains(str, externCDecl) {
119+
inScope = true
120+
if len(str) == len(externCDecl) {
121+
// case 3
122+
enteringScope = true
123+
}
124+
}
125+
if inScope == true {
126+
lines[tag.Filename] = append(lines[tag.Filename], line)
127+
}
128+
indentLevels += strings.Count(str, "{") - strings.Count(str, "}")
129+
130+
// Bail out if indentLevel is zero and we are not in case 3
131+
if indentLevels == 0 && enteringScope == false {
132+
inScope = false
133+
}
134+
}
135+
}
136+
137+
}
138+
return lines
139+
}

src/arduino.cc/builder/ctags_runner.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ func (s *CTagsRunner) Run(ctx *types.Context) error {
7575

7676
parser := &ctags.CTagsParser{}
7777
ctx.CTagsOfPreprocessedSource = parser.Parse(ctx.CTagsOutput)
78+
79+
parser.FixCLinkageTagsDeclarations(ctx.CTagsOfPreprocessedSource)
7880
protos, line := parser.GeneratePrototypes()
7981
if line != -1 {
8082
ctx.PrototypesLineWhereToInsert = line

0 commit comments

Comments
 (0)