Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2002 Andrew Tridgell
3 : : *
4 : : * This program is free software; you can redistribute it and/or modify it
5 : : * under the terms of the GNU General Public License as published by the Free
6 : : * Software Foundation; either version 3 of the License, or (at your option)
7 : : * any later version.
8 : : *
9 : : * This program is distributed in the hope that it will be useful, but WITHOUT
10 : : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 : : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 : : * more details.
13 : : *
14 : : * You should have received a copy of the GNU General Public License along with
15 : : * this program; if not, write to the Free Software Foundation, Inc., 51
16 : : * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 : : */
18 : :
19 : : /*
20 : : * C/C++ unifier
21 : : *
22 : : * The idea is that changes that don't affect the resulting C code should not
23 : : * change the hash. This is achieved by folding white-space and other
24 : : * non-semantic fluff in the input into a single unified format.
25 : : *
26 : : * This unifier was design to match the output of the unifier in compilercache,
27 : : * which is flex based. The major difference is that this unifier is much
28 : : * faster (about 2x) and more forgiving of syntactic errors. Continuing on
29 : : * syntactic errors is important to cope with C/C++ extensions in the local
30 : : * compiler (for example, inline assembly systems).
31 : : */
32 : :
33 : : #include "ccache.h"
34 : :
35 : : static const char *const s_tokens[] = {
36 : : "...", ">>=", "<<=", "+=", "-=", "*=", "/=", "%=", "&=", "^=",
37 : : "|=", ">>", "<<", "++", "--", "->", "&&", "||", "<=", ">=",
38 : : "==", "!=", ";", "{", "<%", "}", "%>", ",", ":", "=",
39 : : "(", ")", "[", "<:", "]", ":>", ".", "&", "!", "~",
40 : : "-", "+", "*", "/", "%", "<", ">", "^", "|", "?",
41 : : 0
42 : : };
43 : :
44 : : #define C_ALPHA 1
45 : : #define C_SPACE 2
46 : : #define C_TOKEN 4
47 : : #define C_QUOTE 8
48 : : #define C_DIGIT 16
49 : : #define C_HEX 32
50 : : #define C_FLOAT 64
51 : : #define C_SIGN 128
52 : :
53 : : static struct {
54 : : unsigned char type;
55 : : unsigned char num_toks;
56 : : const char *toks[7];
57 : : } tokens[256];
58 : :
59 : : /* build up the table used by the unifier */
60 : : static void
61 : 0 : build_table(void)
62 : : {
63 : : unsigned char c;
64 : : int i;
65 : : static bool done;
66 : :
67 [ # # ]: 0 : if (done) {
68 : 0 : return;
69 : : }
70 : 0 : done = true;
71 : :
72 : 0 : memset(tokens, 0, sizeof(tokens));
73 [ # # ]: 0 : for (c = 0; c < 128; c++) {
74 [ # # ][ # # ]: 0 : if (isalpha(c) || c == '_') {
75 : 0 : tokens[c].type |= C_ALPHA;
76 : : }
77 [ # # ]: 0 : if (isdigit(c)) {
78 : 0 : tokens[c].type |= C_DIGIT;
79 : : }
80 [ # # ]: 0 : if (isspace(c)) {
81 : 0 : tokens[c].type |= C_SPACE;
82 : : }
83 [ # # ]: 0 : if (isxdigit(c)) {
84 : 0 : tokens[c].type |= C_HEX;
85 : : }
86 : : }
87 : 0 : tokens['\''].type |= C_QUOTE;
88 : 0 : tokens['"'].type |= C_QUOTE;
89 : 0 : tokens['l'].type |= C_FLOAT;
90 : 0 : tokens['L'].type |= C_FLOAT;
91 : 0 : tokens['f'].type |= C_FLOAT;
92 : 0 : tokens['F'].type |= C_FLOAT;
93 : 0 : tokens['U'].type |= C_FLOAT;
94 : 0 : tokens['u'].type |= C_FLOAT;
95 : :
96 : 0 : tokens['-'].type |= C_SIGN;
97 : 0 : tokens['+'].type |= C_SIGN;
98 : :
99 [ # # ]: 0 : for (i = 0; s_tokens[i]; i++) {
100 : 0 : c = s_tokens[i][0];
101 : 0 : tokens[c].type |= C_TOKEN;
102 : 0 : tokens[c].toks[tokens[c].num_toks] = s_tokens[i];
103 : 0 : tokens[c].num_toks++;
104 : : }
105 : : }
106 : :
107 : : /* buffer up characters before hashing them */
108 : : static void
109 : 0 : pushchar(struct mdfour *hash, unsigned char c)
110 : : {
111 : : static unsigned char buf[64];
112 : : static size_t len;
113 : :
114 [ # # ]: 0 : if (c == 0) {
115 [ # # ]: 0 : if (len > 0) {
116 : 0 : hash_buffer(hash, (char *)buf, len);
117 : 0 : len = 0;
118 : : }
119 : 0 : hash_buffer(hash, NULL, 0);
120 : 0 : return;
121 : : }
122 : :
123 : 0 : buf[len++] = c;
124 [ # # ]: 0 : if (len == 64) {
125 : 0 : hash_buffer(hash, (char *)buf, len);
126 : 0 : len = 0;
127 : : }
128 : : }
129 : :
130 : : /* hash some C/C++ code after unifying */
131 : : static void
132 : 0 : unify(struct mdfour *hash, unsigned char *p, size_t size)
133 : : {
134 : : size_t ofs;
135 : : unsigned char q;
136 : : int i;
137 : :
138 : 0 : build_table();
139 : :
140 [ # # ]: 0 : for (ofs = 0; ofs < size;) {
141 [ # # ]: 0 : if (p[ofs] == '#') {
142 [ # # ][ # # ]: 0 : if ((size-ofs) > 2 && p[ofs+1] == ' ' && isdigit(p[ofs+2])) {
[ # # ]
143 : : do {
144 : 0 : ofs++;
145 [ # # ][ # # ]: 0 : } while (ofs < size && p[ofs] != '\n');
146 : 0 : ofs++;
147 : : } else {
148 : : do {
149 : 0 : pushchar(hash, p[ofs]);
150 : 0 : ofs++;
151 [ # # ][ # # ]: 0 : } while (ofs < size && p[ofs] != '\n');
152 : 0 : pushchar(hash, '\n');
153 : 0 : ofs++;
154 : : }
155 : 0 : continue;
156 : : }
157 : :
158 [ # # ]: 0 : if (tokens[p[ofs]].type & C_ALPHA) {
159 : : do {
160 : 0 : pushchar(hash, p[ofs]);
161 : 0 : ofs++;
162 [ # # ][ # # ]: 0 : } while (ofs < size && (tokens[p[ofs]].type & (C_ALPHA|C_DIGIT)));
163 : 0 : pushchar(hash, '\n');
164 : 0 : continue;
165 : : }
166 : :
167 [ # # ]: 0 : if (tokens[p[ofs]].type & C_DIGIT) {
168 : : do {
169 : 0 : pushchar(hash, p[ofs]);
170 : 0 : ofs++;
171 : : } while (ofs < size &&
172 [ # # ][ # # ]: 0 : ((tokens[p[ofs]].type & C_DIGIT) || p[ofs] == '.'));
[ # # ]
173 [ # # ][ # # ]: 0 : if (ofs < size && (p[ofs] == 'x' || p[ofs] == 'X')) {
[ # # ]
174 : : do {
175 : 0 : pushchar(hash, p[ofs]);
176 : 0 : ofs++;
177 [ # # ][ # # ]: 0 : } while (ofs < size && (tokens[p[ofs]].type & C_HEX));
178 : : }
179 [ # # ][ # # ]: 0 : if (ofs < size && (p[ofs] == 'E' || p[ofs] == 'e')) {
[ # # ]
180 : 0 : pushchar(hash, p[ofs]);
181 : 0 : ofs++;
182 [ # # ][ # # ]: 0 : while (ofs < size && (tokens[p[ofs]].type & (C_DIGIT|C_SIGN))) {
183 : 0 : pushchar(hash, p[ofs]);
184 : 0 : ofs++;
185 : : }
186 : : }
187 [ # # ][ # # ]: 0 : while (ofs < size && (tokens[p[ofs]].type & C_FLOAT)) {
188 : 0 : pushchar(hash, p[ofs]);
189 : 0 : ofs++;
190 : : }
191 : 0 : pushchar(hash, '\n');
192 : 0 : continue;
193 : : }
194 : :
195 [ # # ]: 0 : if (tokens[p[ofs]].type & C_SPACE) {
196 : : do {
197 : 0 : ofs++;
198 [ # # ][ # # ]: 0 : } while (ofs < size && (tokens[p[ofs]].type & C_SPACE));
199 : 0 : continue;
200 : : }
201 : :
202 [ # # ]: 0 : if (tokens[p[ofs]].type & C_QUOTE) {
203 : 0 : q = p[ofs];
204 : 0 : pushchar(hash, p[ofs]);
205 : : do {
206 : 0 : ofs++;
207 [ # # ][ # # ]: 0 : while (ofs < size-1 && p[ofs] == '\\') {
208 : 0 : pushchar(hash, p[ofs]);
209 : 0 : pushchar(hash, p[ofs+1]);
210 : 0 : ofs += 2;
211 : : }
212 : 0 : pushchar(hash, p[ofs]);
213 [ # # ][ # # ]: 0 : } while (ofs < size && p[ofs] != q);
214 : 0 : pushchar(hash, '\n');
215 : 0 : ofs++;
216 : 0 : continue;
217 : : }
218 : :
219 [ # # ]: 0 : if (tokens[p[ofs]].type & C_TOKEN) {
220 : 0 : q = p[ofs];
221 [ # # ]: 0 : for (i = 0; i < tokens[q].num_toks; i++) {
222 : 0 : unsigned char *s = (unsigned char *)tokens[q].toks[i];
223 : 0 : int len = strlen((char *)s);
224 [ # # ][ # # ]: 0 : if (size >= ofs+len && memcmp(&p[ofs], s, len) == 0) {
225 : : int j;
226 [ # # ]: 0 : for (j = 0; s[j]; j++) {
227 : 0 : pushchar(hash, s[j]);
228 : 0 : ofs++;
229 : : }
230 : 0 : pushchar(hash, '\n');
231 : 0 : break;
232 : : }
233 : : }
234 [ # # ]: 0 : if (i < tokens[q].num_toks) {
235 : 0 : continue;
236 : : }
237 : : }
238 : :
239 : 0 : pushchar(hash, p[ofs]);
240 : 0 : pushchar(hash, '\n');
241 : 0 : ofs++;
242 : : }
243 : 0 : pushchar(hash, 0);
244 : 0 : }
245 : :
246 : :
247 : : /* hash a file that consists of preprocessor output, but remove any line
248 : : number information from the hash
249 : : */
250 : : int
251 : 0 : unify_hash(struct mdfour *hash, const char *fname)
252 : : {
253 : : char *data;
254 : : size_t size;
255 : :
256 [ # # ]: 0 : if (!read_file(fname, 0, &data, &size)) {
257 : 0 : stats_update(STATS_PREPROCESSOR);
258 : 0 : return -1;
259 : : }
260 : 0 : unify(hash, (unsigned char *)data, size);
261 : 0 : free(data);
262 : 0 : return 0;
263 : : }
|