GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/*- |
||
2 |
* Copyright (c) 2010, 2013 The NetBSD Foundation, Inc. |
||
3 |
* All rights reserved. |
||
4 |
* |
||
5 |
* This code is derived from software contributed to The NetBSD Foundation |
||
6 |
* by David A. Holland. |
||
7 |
* |
||
8 |
* Redistribution and use in source and binary forms, with or without |
||
9 |
* modification, are permitted provided that the following conditions |
||
10 |
* are met: |
||
11 |
* 1. Redistributions of source code must retain the above copyright |
||
12 |
* notice, this list of conditions and the following disclaimer. |
||
13 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
14 |
* notice, this list of conditions and the following disclaimer in the |
||
15 |
* documentation and/or other materials provided with the distribution. |
||
16 |
* |
||
17 |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
||
18 |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||
19 |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||
20 |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
||
21 |
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
22 |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
23 |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
24 |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
25 |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
26 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
27 |
* POSSIBILITY OF SUCH DAMAGE. |
||
28 |
*/ |
||
29 |
|||
30 |
#include <stdint.h> |
||
31 |
#include <stdlib.h> |
||
32 |
#include <string.h> |
||
33 |
|||
34 |
#include "array.h" |
||
35 |
#include "mode.h" |
||
36 |
#include "place.h" |
||
37 |
#include "macro.h" |
||
38 |
#include "output.h" |
||
39 |
|||
40 |
struct expansionitem { |
||
41 |
bool isstring; |
||
42 |
union { |
||
43 |
char *string; |
||
44 |
unsigned param; |
||
45 |
}; |
||
46 |
}; |
||
47 |
DECLARRAY(expansionitem, static UNUSED); |
||
48 |
157896 |
DEFARRAY(expansionitem, static); |
|
49 |
|||
50 |
struct macro { |
||
51 |
struct place defplace; |
||
52 |
struct place expansionplace; |
||
53 |
unsigned hash; |
||
54 |
char *name; |
||
55 |
bool hasparams; |
||
56 |
struct stringarray params; |
||
57 |
struct expansionitemarray expansion; |
||
58 |
bool inuse; |
||
59 |
}; |
||
60 |
DECLARRAY(macro, static UNUSED); |
||
61 |
167445784 |
DEFARRAY(macro, static); |
|
62 |
DECLARRAY(macroarray, static UNUSED); |
||
63 |
53026740 |
DEFARRAY(macroarray, static); |
|
64 |
|||
65 |
static struct macroarrayarray macros; |
||
66 |
static unsigned total_macros; |
||
67 |
static unsigned hashmask; |
||
68 |
|||
69 |
//////////////////////////////////////////////////////////// |
||
70 |
// macro structure ops |
||
71 |
|||
72 |
static |
||
73 |
struct expansionitem * |
||
74 |
expansionitem_create_string(const char *string) |
||
75 |
{ |
||
76 |
struct expansionitem *ei; |
||
77 |
|||
78 |
26316 |
ei = domalloc(sizeof(*ei)); |
|
79 |
13158 |
ei->isstring = true; |
|
80 |
13158 |
ei->string = dostrdup(string); |
|
81 |
13158 |
return ei; |
|
82 |
} |
||
83 |
|||
84 |
static |
||
85 |
struct expansionitem * |
||
86 |
expansionitem_create_stringlen(const char *string, size_t len) |
||
87 |
{ |
||
88 |
struct expansionitem *ei; |
||
89 |
|||
90 |
ei = domalloc(sizeof(*ei)); |
||
91 |
ei->isstring = true; |
||
92 |
ei->string = dostrndup(string, len); |
||
93 |
return ei; |
||
94 |
} |
||
95 |
|||
96 |
static |
||
97 |
struct expansionitem * |
||
98 |
expansionitem_create_param(unsigned param) |
||
99 |
{ |
||
100 |
struct expansionitem *ei; |
||
101 |
|||
102 |
ei = domalloc(sizeof(*ei)); |
||
103 |
ei->isstring = false; |
||
104 |
ei->param = param; |
||
105 |
return ei; |
||
106 |
} |
||
107 |
|||
108 |
static |
||
109 |
void |
||
110 |
expansionitem_destroy(struct expansionitem *ei) |
||
111 |
{ |
||
112 |
✓✗ | 26316 |
if (ei->isstring) { |
113 |
13158 |
dostrfree(ei->string); |
|
114 |
13158 |
} |
|
115 |
13158 |
dofree(ei, sizeof(*ei)); |
|
116 |
13158 |
} |
|
117 |
|||
118 |
static |
||
119 |
bool |
||
120 |
expansionitem_eq(const struct expansionitem *ei1, |
||
121 |
const struct expansionitem *ei2) |
||
122 |
{ |
||
123 |
if (ei1->isstring != ei2->isstring) { |
||
124 |
return false; |
||
125 |
} |
||
126 |
if (ei1->isstring) { |
||
127 |
if (strcmp(ei1->string, ei2->string) != 0) { |
||
128 |
return false; |
||
129 |
} |
||
130 |
} else { |
||
131 |
if (ei1->param != ei2->param) { |
||
132 |
return false; |
||
133 |
} |
||
134 |
} |
||
135 |
return true; |
||
136 |
} |
||
137 |
|||
138 |
static |
||
139 |
struct macro * |
||
140 |
macro_create(struct place *p1, const char *name, unsigned hash, |
||
141 |
struct place *p2) |
||
142 |
{ |
||
143 |
struct macro *m; |
||
144 |
|||
145 |
26316 |
m = domalloc(sizeof(*m)); |
|
146 |
13158 |
m->defplace = *p1; |
|
147 |
13158 |
m->expansionplace = *p2; |
|
148 |
13158 |
m->hash = hash; |
|
149 |
13158 |
m->name = dostrdup(name); |
|
150 |
13158 |
m->hasparams = false; |
|
151 |
13158 |
stringarray_init(&m->params); |
|
152 |
13158 |
expansionitemarray_init(&m->expansion); |
|
153 |
13158 |
m->inuse = false; |
|
154 |
13158 |
return m; |
|
155 |
} |
||
156 |
|||
157 |
✓✓ | 78948 |
DESTROYALL_ARRAY(expansionitem, ); |
158 |
|||
159 |
static |
||
160 |
void |
||
161 |
macro_destroy(struct macro *m) |
||
162 |
{ |
||
163 |
26316 |
expansionitemarray_destroyall(&m->expansion); |
|
164 |
13158 |
expansionitemarray_cleanup(&m->expansion); |
|
165 |
13158 |
dostrfree(m->name); |
|
166 |
13158 |
dofree(m, sizeof(*m)); |
|
167 |
13158 |
} |
|
168 |
|||
169 |
static |
||
170 |
bool |
||
171 |
macro_eq(const struct macro *m1, const struct macro *m2) |
||
172 |
{ |
||
173 |
unsigned num1, num2, i; |
||
174 |
struct expansionitem *ei1, *ei2; |
||
175 |
const char *p1, *p2; |
||
176 |
|||
177 |
if (strcmp(m1->name, m2->name) != 0) { |
||
178 |
return false; |
||
179 |
} |
||
180 |
|||
181 |
if (m1->hasparams != m2->hasparams) { |
||
182 |
return false; |
||
183 |
} |
||
184 |
|||
185 |
num1 = expansionitemarray_num(&m1->expansion); |
||
186 |
num2 = expansionitemarray_num(&m2->expansion); |
||
187 |
if (num1 != num2) { |
||
188 |
return false; |
||
189 |
} |
||
190 |
|||
191 |
for (i=0; i<num1; i++) { |
||
192 |
ei1 = expansionitemarray_get(&m1->expansion, i); |
||
193 |
ei2 = expansionitemarray_get(&m2->expansion, i); |
||
194 |
if (!expansionitem_eq(ei1, ei2)) { |
||
195 |
return false; |
||
196 |
} |
||
197 |
} |
||
198 |
|||
199 |
num1 = stringarray_num(&m1->params); |
||
200 |
num2 = stringarray_num(&m2->params); |
||
201 |
if (num1 != num2) { |
||
202 |
return false; |
||
203 |
} |
||
204 |
|||
205 |
for (i=0; i<num1; i++) { |
||
206 |
p1 = stringarray_get(&m1->params, i); |
||
207 |
p2 = stringarray_get(&m2->params, i); |
||
208 |
if (strcmp(p1, p2) != 0) { |
||
209 |
return false; |
||
210 |
} |
||
211 |
} |
||
212 |
return true; |
||
213 |
} |
||
214 |
|||
215 |
//////////////////////////////////////////////////////////// |
||
216 |
// macro table |
||
217 |
|||
218 |
/* |
||
219 |
* Unless I've screwed up, this is something called Fletcher's Checksum |
||
220 |
* that showed up in Dr. Dobbs in, according to my notes, May 1992. The |
||
221 |
* implementation is new. |
||
222 |
*/ |
||
223 |
static |
||
224 |
unsigned |
||
225 |
hashfunc(const char *s, size_t len) |
||
226 |
{ |
||
227 |
uint16_t x1, x2, a; |
||
228 |
size_t i; |
||
229 |
|||
230 |
52977032 |
x1 = (uint16_t) (len >> 16); |
|
231 |
26488516 |
x2 = (uint16_t) (len); |
|
232 |
✓✗ | 26488516 |
if (x1==0) { |
233 |
26488516 |
x1++; |
|
234 |
26488516 |
} |
|
235 |
✗✓ | 26488516 |
if (x2==0) { |
236 |
x2++; |
||
237 |
} |
||
238 |
|||
239 |
✓✓ | 169469192 |
for (i=0; i<len; i+=2) { |
240 |
✓✓ | 58246080 |
if (i==len-1) { |
241 |
13886076 |
a = (unsigned char)s[i]; |
|
242 |
/* don't run off the end of the array */ |
||
243 |
13886076 |
} |
|
244 |
else { |
||
245 |
88720008 |
a = (unsigned char)s[i] + |
|
246 |
44360004 |
((uint16_t)(unsigned char)s[i+1] << 8); |
|
247 |
} |
||
248 |
58246080 |
x1 += a; |
|
249 |
✓✓ | 58246080 |
if (x1 < a) { |
250 |
8051234 |
x1++; |
|
251 |
8051234 |
} |
|
252 |
58246080 |
x2 += x1; |
|
253 |
✓✓ | 58246080 |
if (x2 < x1) { |
254 |
17260372 |
x2++; |
|
255 |
17260372 |
} |
|
256 |
} |
||
257 |
|||
258 |
26488516 |
x1 ^= 0xffff; |
|
259 |
26488516 |
x2 ^= 0xffff; |
|
260 |
26488516 |
return ((uint32_t)x2)*65535U + x1; |
|
261 |
} |
||
262 |
|||
263 |
static |
||
264 |
void |
||
265 |
macrotable_init(void) |
||
266 |
{ |
||
267 |
unsigned i; |
||
268 |
|||
269 |
2924 |
macroarrayarray_init(¯os); |
|
270 |
1462 |
macroarrayarray_setsize(¯os, 4); |
|
271 |
✓✓ | 14620 |
for (i=0; i<4; i++) { |
272 |
5848 |
macroarrayarray_set(¯os, i, NULL); |
|
273 |
} |
||
274 |
1462 |
total_macros = 0; |
|
275 |
1462 |
hashmask = 0x3; |
|
276 |
1462 |
} |
|
277 |
|||
278 |
✓✓ | 49708 |
DESTROYALL_ARRAY(macro, ); |
279 |
|||
280 |
static |
||
281 |
void |
||
282 |
macrotable_cleanup(void) |
||
283 |
{ |
||
284 |
struct macroarray *bucket; |
||
285 |
unsigned numbuckets, i; |
||
286 |
|||
287 |
2924 |
numbuckets = macroarrayarray_num(¯os); |
|
288 |
✓✓ | 14620 |
for (i=0; i<numbuckets; i++) { |
289 |
5848 |
bucket = macroarrayarray_get(¯os, i); |
|
290 |
✓✗ | 5848 |
if (bucket != NULL) { |
291 |
5848 |
macroarray_destroyall(bucket); |
|
292 |
5848 |
macroarray_destroy(bucket); |
|
293 |
5848 |
} |
|
294 |
} |
||
295 |
1462 |
macroarrayarray_setsize(¯os, 0); |
|
296 |
1462 |
macroarrayarray_cleanup(¯os); |
|
297 |
1462 |
} |
|
298 |
|||
299 |
static |
||
300 |
struct macro * |
||
301 |
macrotable_findlen(const char *name, size_t len, bool remove) |
||
302 |
{ |
||
303 |
unsigned hash; |
||
304 |
struct macroarray *bucket; |
||
305 |
struct macro *m, *m2; |
||
306 |
unsigned i, num; |
||
307 |
size_t mlen; |
||
308 |
|||
309 |
26462200 |
hash = hashfunc(name, len); |
|
310 |
26462200 |
bucket = macroarrayarray_get(¯os, hash & hashmask); |
|
311 |
✓✓ | 26462200 |
if (bucket == NULL) { |
312 |
5848 |
return NULL; |
|
313 |
} |
||
314 |
26456352 |
num = macroarray_num(bucket); |
|
315 |
✓✓ | 167322976 |
for (i=0; i<num; i++) { |
316 |
57205136 |
m = macroarray_get(bucket, i); |
|
317 |
✗✓ | 57205136 |
if (hash != m->hash) { |
318 |
continue; |
||
319 |
} |
||
320 |
mlen = strlen(m->name); |
||
321 |
if (len == mlen && !memcmp(name, m->name, len)) { |
||
322 |
if (remove) { |
||
323 |
if (i < num-1) { |
||
324 |
m2 = macroarray_get(bucket, num-1); |
||
325 |
macroarray_set(bucket, i, m2); |
||
326 |
} |
||
327 |
macroarray_setsize(bucket, num-1); |
||
328 |
total_macros--; |
||
329 |
} |
||
330 |
return m; |
||
331 |
} |
||
332 |
} |
||
333 |
26456352 |
return NULL; |
|
334 |
26462200 |
} |
|
335 |
|||
336 |
static |
||
337 |
struct macro * |
||
338 |
macrotable_find(const char *name, bool remove) |
||
339 |
{ |
||
340 |
14620 |
return macrotable_findlen(name, strlen(name), remove); |
|
341 |
} |
||
342 |
|||
343 |
static |
||
344 |
void |
||
345 |
macrotable_rehash(void) |
||
346 |
{ |
||
347 |
struct macroarray *newbucket, *oldbucket; |
||
348 |
struct macro *m; |
||
349 |
unsigned newmask, tossbit; |
||
350 |
unsigned numbuckets, i; |
||
351 |
unsigned oldnum, j, k; |
||
352 |
|||
353 |
numbuckets = macroarrayarray_num(¯os); |
||
354 |
macroarrayarray_setsize(¯os, numbuckets*2); |
||
355 |
|||
356 |
assert(hashmask == numbuckets - 1); |
||
357 |
newmask = (hashmask << 1) | 1U; |
||
358 |
tossbit = newmask & ~hashmask; |
||
359 |
hashmask = newmask; |
||
360 |
|||
361 |
for (i=0; i<numbuckets; i++) { |
||
362 |
newbucket = NULL; |
||
363 |
oldbucket = macroarrayarray_get(¯os, i); |
||
364 |
if (oldbucket == NULL) { |
||
365 |
macroarrayarray_set(¯os, numbuckets + i, NULL); |
||
366 |
continue; |
||
367 |
} |
||
368 |
oldnum = macroarray_num(oldbucket); |
||
369 |
for (j=0; j<oldnum; j++) { |
||
370 |
m = macroarray_get(oldbucket, j); |
||
371 |
if (m->hash & tossbit) { |
||
372 |
if (newbucket == NULL) { |
||
373 |
newbucket = macroarray_create(); |
||
374 |
} |
||
375 |
macroarray_set(oldbucket, j, NULL); |
||
376 |
macroarray_add(newbucket, m, NULL); |
||
377 |
} |
||
378 |
} |
||
379 |
for (j=k=0; j<oldnum; j++) { |
||
380 |
m = macroarray_get(oldbucket, j); |
||
381 |
if (m != NULL) { |
||
382 |
if (k < j) { |
||
383 |
macroarray_set(oldbucket, k, m); |
||
384 |
} |
||
385 |
k++; |
||
386 |
} |
||
387 |
} |
||
388 |
macroarray_setsize(oldbucket, k); |
||
389 |
macroarrayarray_set(¯os, numbuckets + i, newbucket); |
||
390 |
} |
||
391 |
} |
||
392 |
|||
393 |
static |
||
394 |
void |
||
395 |
macrotable_add(struct macro *m) |
||
396 |
{ |
||
397 |
unsigned hash; |
||
398 |
struct macroarray *bucket; |
||
399 |
unsigned numbuckets; |
||
400 |
|||
401 |
26316 |
numbuckets = macroarrayarray_num(¯os); |
|
402 |
✓✓✗✓ |
24854 |
if (total_macros > 0 && total_macros / numbuckets > 9) { |
403 |
macrotable_rehash(); |
||
404 |
} |
||
405 |
|||
406 |
13158 |
hash = hashfunc(m->name, strlen(m->name)); |
|
407 |
13158 |
bucket = macroarrayarray_get(¯os, hash & hashmask); |
|
408 |
✓✓ | 13158 |
if (bucket == NULL) { |
409 |
5848 |
bucket = macroarray_create(); |
|
410 |
5848 |
macroarrayarray_set(¯os, hash & hashmask, bucket); |
|
411 |
5848 |
} |
|
412 |
13158 |
macroarray_add(bucket, m, NULL); |
|
413 |
13158 |
total_macros++; |
|
414 |
13158 |
} |
|
415 |
|||
416 |
//////////////////////////////////////////////////////////// |
||
417 |
// external macro definition interface |
||
418 |
|||
419 |
static |
||
420 |
struct macro * |
||
421 |
macro_define_common_start(struct place *p1, const char *macro, |
||
422 |
struct place *p2) |
||
423 |
{ |
||
424 |
struct macro *m; |
||
425 |
unsigned hash; |
||
426 |
|||
427 |
✗✓ | 26316 |
if (!is_identifier(macro)) { |
428 |
complain(p1, "Invalid macro name %s", macro); |
||
429 |
complain_fail(); |
||
430 |
} |
||
431 |
|||
432 |
13158 |
hash = hashfunc(macro, strlen(macro)); |
|
433 |
13158 |
m = macro_create(p1, macro, hash, p2); |
|
434 |
13158 |
return m; |
|
435 |
} |
||
436 |
|||
437 |
static |
||
438 |
void |
||
439 |
macro_define_common_end(struct macro *m) |
||
440 |
{ |
||
441 |
struct macro *oldm; |
||
442 |
bool ok; |
||
443 |
|||
444 |
26316 |
oldm = macrotable_find(m->name, false); |
|
445 |
✗✓ | 13158 |
if (oldm != NULL) { |
446 |
ok = macro_eq(m, oldm); |
||
447 |
if (ok) { |
||
448 |
/* in traditional cpp this is silent */ |
||
449 |
//complain(&m->defplace, |
||
450 |
// "Warning: redefinition of %s", m->name); |
||
451 |
//complain(&oldm->defplace, |
||
452 |
// "Previous definition was here"); |
||
453 |
//if (mode.werror) { |
||
454 |
// complain_fail(); |
||
455 |
//} |
||
456 |
} else { |
||
457 |
complain(&m->defplace, |
||
458 |
"Warning: non-identical redefinition of %s", |
||
459 |
m->name); |
||
460 |
complain(&oldm->defplace, |
||
461 |
"Previous definition was here"); |
||
462 |
/* in traditional cpp this is not fatal */ |
||
463 |
if (mode.werror) { |
||
464 |
complain_fail(); |
||
465 |
} |
||
466 |
} |
||
467 |
macro_destroy(m); |
||
468 |
return; |
||
469 |
} |
||
470 |
13158 |
macrotable_add(m); |
|
471 |
26316 |
} |
|
472 |
|||
473 |
static |
||
474 |
void |
||
475 |
macro_parse_parameters(struct macro *m, struct place *p, const char *params) |
||
476 |
{ |
||
477 |
size_t len; |
||
478 |
const char *s; |
||
479 |
char *param; |
||
480 |
|||
481 |
while (params != NULL) { |
||
482 |
len = strspn(params, ws); |
||
483 |
params += len; |
||
484 |
p->column += len; |
||
485 |
s = strchr(params, ','); |
||
486 |
if (s) { |
||
487 |
len = s-params; |
||
488 |
param = dostrndup(params, len); |
||
489 |
s++; |
||
490 |
} else { |
||
491 |
len = strlen(params); |
||
492 |
param = dostrndup(params, len); |
||
493 |
} |
||
494 |
notrailingws(param, strlen(param)); |
||
495 |
if (!is_identifier(param)) { |
||
496 |
complain(p, "Invalid macro parameter name %s", param); |
||
497 |
complain_fail(); |
||
498 |
} else { |
||
499 |
stringarray_add(&m->params, param, NULL); |
||
500 |
} |
||
501 |
params = s; |
||
502 |
p->column += len; |
||
503 |
} |
||
504 |
} |
||
505 |
|||
506 |
static |
||
507 |
bool |
||
508 |
isparam(struct macro *m, const char *name, size_t len, unsigned *num_ret) |
||
509 |
{ |
||
510 |
unsigned num, i; |
||
511 |
const char *param; |
||
512 |
|||
513 |
num = stringarray_num(&m->params); |
||
514 |
for (i=0; i<num; i++) { |
||
515 |
param = stringarray_get(&m->params, i); |
||
516 |
if (strlen(param) == len && !memcmp(name, param, len)) { |
||
517 |
*num_ret = i; |
||
518 |
return true; |
||
519 |
} |
||
520 |
} |
||
521 |
return false; |
||
522 |
} |
||
523 |
|||
524 |
static |
||
525 |
void |
||
526 |
macro_parse_expansion(struct macro *m, const char *buf) |
||
527 |
{ |
||
528 |
size_t blockstart, wordstart, pos; |
||
529 |
struct expansionitem *ei; |
||
530 |
unsigned param; |
||
531 |
|||
532 |
pos = blockstart = 0; |
||
533 |
while (buf[pos] != '\0') { |
||
534 |
pos += strspn(buf+pos, ws); |
||
535 |
if (strchr(alnum, buf[pos])) { |
||
536 |
wordstart = pos; |
||
537 |
pos += strspn(buf+pos, alnum); |
||
538 |
if (isparam(m, buf+wordstart, pos-wordstart, ¶m)) { |
||
539 |
if (wordstart > blockstart) { |
||
540 |
ei = expansionitem_create_stringlen( |
||
541 |
buf + blockstart, |
||
542 |
wordstart - blockstart); |
||
543 |
expansionitemarray_add(&m->expansion, |
||
544 |
ei, NULL); |
||
545 |
} |
||
546 |
ei = expansionitem_create_param(param); |
||
547 |
expansionitemarray_add(&m->expansion, ei,NULL); |
||
548 |
blockstart = pos; |
||
549 |
continue; |
||
550 |
} |
||
551 |
continue; |
||
552 |
} |
||
553 |
pos++; |
||
554 |
} |
||
555 |
if (pos > blockstart) { |
||
556 |
ei = expansionitem_create_stringlen(buf + blockstart, |
||
557 |
pos - blockstart); |
||
558 |
expansionitemarray_add(&m->expansion, ei, NULL); |
||
559 |
} |
||
560 |
} |
||
561 |
|||
562 |
void |
||
563 |
macro_define_plain(struct place *p1, const char *macro, |
||
564 |
struct place *p2, const char *expansion) |
||
565 |
{ |
||
566 |
struct macro *m; |
||
567 |
struct expansionitem *ei; |
||
568 |
|||
569 |
26316 |
m = macro_define_common_start(p1, macro, p2); |
|
570 |
13158 |
ei = expansionitem_create_string(expansion); |
|
571 |
13158 |
expansionitemarray_add(&m->expansion, ei, NULL); |
|
572 |
13158 |
macro_define_common_end(m); |
|
573 |
13158 |
} |
|
574 |
|||
575 |
void |
||
576 |
macro_define_params(struct place *p1, const char *macro, |
||
577 |
struct place *p2, const char *params, |
||
578 |
struct place *p3, const char *expansion) |
||
579 |
{ |
||
580 |
struct macro *m; |
||
581 |
|||
582 |
m = macro_define_common_start(p1, macro, p3); |
||
583 |
m->hasparams = true; |
||
584 |
macro_parse_parameters(m, p2, params); |
||
585 |
macro_parse_expansion(m, expansion); |
||
586 |
macro_define_common_end(m); |
||
587 |
} |
||
588 |
|||
589 |
void |
||
590 |
macro_undef(const char *macro) |
||
591 |
{ |
||
592 |
struct macro *m; |
||
593 |
|||
594 |
2924 |
m = macrotable_find(macro, true); |
|
595 |
✗✓ | 1462 |
if (m) { |
596 |
macro_destroy(m); |
||
597 |
} |
||
598 |
1462 |
} |
|
599 |
|||
600 |
bool |
||
601 |
macro_isdefined(const char *macro) |
||
602 |
{ |
||
603 |
struct macro *m; |
||
604 |
|||
605 |
m = macrotable_find(macro, false); |
||
606 |
return m != NULL; |
||
607 |
} |
||
608 |
|||
609 |
//////////////////////////////////////////////////////////// |
||
610 |
// macro expansion |
||
611 |
|||
612 |
struct expstate { |
||
613 |
bool honordefined; |
||
614 |
enum { ES_NORMAL, ES_WANTLPAREN, ES_NOARG, ES_HAVEARG } state; |
||
615 |
struct macro *curmacro; |
||
616 |
struct stringarray args; |
||
617 |
unsigned argparens; |
||
618 |
|||
619 |
bool tobuf; |
||
620 |
char *buf; |
||
621 |
size_t bufpos, bufmax; |
||
622 |
}; |
||
623 |
|||
624 |
static struct expstate mainstate; |
||
625 |
|||
626 |
static void doexpand(struct expstate *es, struct place *p, |
||
627 |
char *buf, size_t len); |
||
628 |
|||
629 |
static |
||
630 |
void |
||
631 |
expstate_init(struct expstate *es, bool tobuf, bool honordefined) |
||
632 |
{ |
||
633 |
1462 |
es->honordefined = honordefined; |
|
634 |
1462 |
es->state = ES_NORMAL; |
|
635 |
1462 |
es->curmacro = NULL; |
|
636 |
1462 |
stringarray_init(&es->args); |
|
637 |
1462 |
es->argparens = 0; |
|
638 |
1462 |
es->tobuf = tobuf; |
|
639 |
1462 |
es->buf = NULL; |
|
640 |
1462 |
es->bufpos = 0; |
|
641 |
1462 |
es->bufmax = 0; |
|
642 |
1462 |
} |
|
643 |
|||
644 |
static |
||
645 |
void |
||
646 |
expstate_cleanup(struct expstate *es) |
||
647 |
{ |
||
648 |
✗✓ | 2924 |
assert(es->state == ES_NORMAL); |
649 |
1462 |
stringarray_cleanup(&es->args); |
|
650 |
✗✓ | 1462 |
if (es->buf) { |
651 |
dofree(es->buf, es->bufmax); |
||
652 |
} |
||
653 |
1462 |
} |
|
654 |
|||
655 |
static |
||
656 |
void |
||
657 |
expstate_destroyargs(struct expstate *es) |
||
658 |
{ |
||
659 |
unsigned i, num; |
||
660 |
|||
661 |
num = stringarray_num(&es->args); |
||
662 |
for (i=0; i<num; i++) { |
||
663 |
dostrfree(stringarray_get(&es->args, i)); |
||
664 |
} |
||
665 |
stringarray_setsize(&es->args, 0); |
||
666 |
} |
||
667 |
|||
668 |
static |
||
669 |
void |
||
670 |
expand_send(struct expstate *es, struct place *p, const char *buf, size_t len) |
||
671 |
{ |
||
672 |
size_t oldmax; |
||
673 |
|||
674 |
✗✓ | 109047656 |
if (es->tobuf) { |
675 |
assert(es->bufpos <= es->bufmax); |
||
676 |
if (es->bufpos + len > es->bufmax) { |
||
677 |
oldmax = es->bufmax; |
||
678 |
if (es->bufmax == 0) { |
||
679 |
es->bufmax = 64; |
||
680 |
} |
||
681 |
while (es->bufpos + len > es->bufmax) { |
||
682 |
es->bufmax *= 2; |
||
683 |
} |
||
684 |
es->buf = dorealloc(es->buf, oldmax, es->bufmax); |
||
685 |
} |
||
686 |
memcpy(es->buf + es->bufpos, buf, len); |
||
687 |
es->bufpos += len; |
||
688 |
assert(es->bufpos <= es->bufmax); |
||
689 |
} else { |
||
690 |
54523828 |
output(p, buf, len); |
|
691 |
} |
||
692 |
54523828 |
} |
|
693 |
|||
694 |
static |
||
695 |
void |
||
696 |
expand_send_eof(struct expstate *es, struct place *p) |
||
697 |
{ |
||
698 |
✗✓ | 2924 |
if (es->tobuf) { |
699 |
expand_send(es, p, "", 1); |
||
700 |
es->bufpos--; |
||
701 |
} else { |
||
702 |
1462 |
output_eof(); |
|
703 |
} |
||
704 |
1462 |
} |
|
705 |
|||
706 |
static |
||
707 |
void |
||
708 |
expand_newarg(struct expstate *es, char *buf, size_t len) |
||
709 |
{ |
||
710 |
char *text; |
||
711 |
|||
712 |
text = dostrndup(buf, len); |
||
713 |
stringarray_add(&es->args, text, NULL); |
||
714 |
} |
||
715 |
|||
716 |
static |
||
717 |
void |
||
718 |
expand_appendarg(struct expstate *es, char *buf, size_t len) |
||
719 |
{ |
||
720 |
unsigned num; |
||
721 |
char *text; |
||
722 |
size_t oldlen; |
||
723 |
|||
724 |
num = stringarray_num(&es->args); |
||
725 |
assert(num > 0); |
||
726 |
|||
727 |
text = stringarray_get(&es->args, num - 1); |
||
728 |
oldlen = strlen(text); |
||
729 |
text = dorealloc(text, oldlen + 1, oldlen + len + 1); |
||
730 |
memcpy(text + oldlen, buf, len); |
||
731 |
text[oldlen+len] = '\0'; |
||
732 |
stringarray_set(&es->args, num - 1, text); |
||
733 |
} |
||
734 |
|||
735 |
static |
||
736 |
char * |
||
737 |
expand_substitute(struct place *p, struct expstate *es) |
||
738 |
{ |
||
739 |
struct expansionitem *ei; |
||
740 |
unsigned i, num; |
||
741 |
size_t len; |
||
742 |
char *arg; |
||
743 |
char *ret; |
||
744 |
unsigned numargs, numparams; |
||
745 |
|||
746 |
numargs = stringarray_num(&es->args); |
||
747 |
numparams = stringarray_num(&es->curmacro->params); |
||
748 |
|||
749 |
if (numargs == 0 && numparams == 1) { |
||
750 |
/* no arguments <=> one empty argument */ |
||
751 |
stringarray_add(&es->args, dostrdup(""), NULL); |
||
752 |
numargs++; |
||
753 |
} |
||
754 |
if (numargs != numparams) { |
||
755 |
complain(p, "Wrong number of arguments for macro %s; " |
||
756 |
"found %u, expected %u", |
||
757 |
es->curmacro->name, numargs, numparams); |
||
758 |
complain_fail(); |
||
759 |
while (numargs < numparams) { |
||
760 |
stringarray_add(&es->args, dostrdup(""), NULL); |
||
761 |
numargs++; |
||
762 |
} |
||
763 |
} |
||
764 |
|||
765 |
len = 0; |
||
766 |
num = expansionitemarray_num(&es->curmacro->expansion); |
||
767 |
for (i=0; i<num; i++) { |
||
768 |
ei = expansionitemarray_get(&es->curmacro->expansion, i); |
||
769 |
if (ei->isstring) { |
||
770 |
len += strlen(ei->string); |
||
771 |
} else { |
||
772 |
arg = stringarray_get(&es->args, ei->param); |
||
773 |
len += strlen(arg); |
||
774 |
} |
||
775 |
} |
||
776 |
|||
777 |
ret = domalloc(len+1); |
||
778 |
*ret = '\0'; |
||
779 |
for (i=0; i<num; i++) { |
||
780 |
ei = expansionitemarray_get(&es->curmacro->expansion, i); |
||
781 |
if (ei->isstring) { |
||
782 |
strlcat(ret, ei->string, len+1); |
||
783 |
} else { |
||
784 |
arg = stringarray_get(&es->args, ei->param); |
||
785 |
strlcat(ret, arg, len+1); |
||
786 |
} |
||
787 |
} |
||
788 |
|||
789 |
return ret; |
||
790 |
} |
||
791 |
|||
792 |
static |
||
793 |
void |
||
794 |
expand_domacro(struct expstate *es, struct place *p) |
||
795 |
{ |
||
796 |
struct macro *m; |
||
797 |
char *newbuf, *newbuf2; |
||
798 |
|||
799 |
if (es->curmacro == NULL) { |
||
800 |
/* defined() */ |
||
801 |
if (stringarray_num(&es->args) != 1) { |
||
802 |
complain(p, "Too many arguments for defined()"); |
||
803 |
complain_fail(); |
||
804 |
expand_send(es, p, "0", 1); |
||
805 |
return; |
||
806 |
} |
||
807 |
m = macrotable_find(stringarray_get(&es->args, 0), false); |
||
808 |
expand_send(es, p, (m != NULL) ? "1" : "0", 1); |
||
809 |
expstate_destroyargs(es); |
||
810 |
return; |
||
811 |
} |
||
812 |
|||
813 |
assert(es->curmacro->inuse == false); |
||
814 |
es->curmacro->inuse = true; |
||
815 |
|||
816 |
newbuf = expand_substitute(p, es); |
||
817 |
newbuf2 = macroexpand(p, newbuf, strlen(newbuf), false); |
||
818 |
dostrfree(newbuf); |
||
819 |
expstate_destroyargs(es); |
||
820 |
doexpand(es, p, newbuf2, strlen(newbuf2)); |
||
821 |
dostrfree(newbuf2); |
||
822 |
|||
823 |
es->curmacro->inuse = false; |
||
824 |
} |
||
825 |
|||
826 |
/* |
||
827 |
* The traditional behavior if a function-like macro appears without |
||
828 |
* arguments is to pretend it isn't a macro; that is, just emit its |
||
829 |
* name. |
||
830 |
*/ |
||
831 |
static |
||
832 |
void |
||
833 |
expand_missingargs(struct expstate *es, struct place *p, bool needspace) |
||
834 |
{ |
||
835 |
if (es->curmacro == NULL) { |
||
836 |
/* defined */ |
||
837 |
expand_send(es, p, "defined", 7); |
||
838 |
return; |
||
839 |
} |
||
840 |
expand_send(es, p, es->curmacro->name, strlen(es->curmacro->name)); |
||
841 |
/* send a space in case we ate whitespace after the macro name */ |
||
842 |
if (needspace) { |
||
843 |
expand_send(es, p, " ", 1); |
||
844 |
} |
||
845 |
} |
||
846 |
|||
847 |
static |
||
848 |
void |
||
849 |
expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len) |
||
850 |
{ |
||
851 |
✓✗✗✓ |
52469718 |
switch (es->state) { |
852 |
case ES_NORMAL: |
||
853 |
17489906 |
expand_send(es, p, buf, len); |
|
854 |
17489906 |
break; |
|
855 |
case ES_WANTLPAREN: |
||
856 |
break; |
||
857 |
case ES_NOARG: |
||
858 |
expand_newarg(es, buf, len); |
||
859 |
es->state = ES_HAVEARG; |
||
860 |
break; |
||
861 |
case ES_HAVEARG: |
||
862 |
expand_appendarg(es, buf, len); |
||
863 |
break; |
||
864 |
} |
||
865 |
17489906 |
} |
|
866 |
|||
867 |
static |
||
868 |
void |
||
869 |
expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len) |
||
870 |
{ |
||
871 |
struct macro *m; |
||
872 |
struct expansionitem *ei; |
||
873 |
char *newbuf; |
||
874 |
|||
875 |
✓✗✗✗ ✓ |
79342740 |
switch (es->state) { |
876 |
case ES_NORMAL: |
||
877 |
✗✓✗✗ |
52895160 |
if (es->honordefined && |
878 |
26447580 |
len == 7 && !memcmp(buf, "defined", 7)) { |
|
879 |
es->curmacro = NULL; |
||
880 |
es->state = ES_WANTLPAREN; |
||
881 |
break; |
||
882 |
} |
||
883 |
26447580 |
m = macrotable_findlen(buf, len, false); |
|
884 |
✗✓✗✗ |
26447580 |
if (m == NULL || m->inuse) { |
885 |
26447580 |
expand_send(es, p, buf, len); |
|
886 |
✗✗ | 26447580 |
} else if (!m->hasparams) { |
887 |
m->inuse = true; |
||
888 |
assert(expansionitemarray_num(&m->expansion) == 1); |
||
889 |
ei = expansionitemarray_get(&m->expansion, 0); |
||
890 |
assert(ei->isstring); |
||
891 |
newbuf = macroexpand(p, ei->string, |
||
892 |
strlen(ei->string), false); |
||
893 |
doexpand(es, p, newbuf, strlen(newbuf)); |
||
894 |
dostrfree(newbuf); |
||
895 |
m->inuse = false; |
||
896 |
} else { |
||
897 |
es->curmacro = m; |
||
898 |
es->state = ES_WANTLPAREN; |
||
899 |
} |
||
900 |
break; |
||
901 |
case ES_WANTLPAREN: |
||
902 |
if (es->curmacro != NULL) { |
||
903 |
expand_missingargs(es, p, true); |
||
904 |
es->state = ES_NORMAL; |
||
905 |
/* try again */ |
||
906 |
expand_got_word(es, p, buf, len); |
||
907 |
} else { |
||
908 |
/* "defined foo" means "defined(foo)" */ |
||
909 |
expand_newarg(es, buf, len); |
||
910 |
es->state = ES_NORMAL; |
||
911 |
expand_domacro(es, p); |
||
912 |
} |
||
913 |
break; |
||
914 |
case ES_NOARG: |
||
915 |
expand_newarg(es, buf, len); |
||
916 |
es->state = ES_HAVEARG; |
||
917 |
break; |
||
918 |
case ES_HAVEARG: |
||
919 |
expand_appendarg(es, buf, len); |
||
920 |
break; |
||
921 |
} |
||
922 |
26447580 |
} |
|
923 |
|||
924 |
static |
||
925 |
void |
||
926 |
expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len) |
||
927 |
{ |
||
928 |
✓✗✗✗ ✓ |
245616 |
switch (es->state) { |
929 |
case ES_NORMAL: |
||
930 |
81872 |
expand_send(es, p, buf, len); |
|
931 |
81872 |
break; |
|
932 |
case ES_WANTLPAREN: |
||
933 |
es->state = ES_NOARG; |
||
934 |
break; |
||
935 |
case ES_NOARG: |
||
936 |
expand_newarg(es, buf, len); |
||
937 |
es->state = ES_HAVEARG; |
||
938 |
es->argparens++; |
||
939 |
break; |
||
940 |
case ES_HAVEARG: |
||
941 |
expand_appendarg(es, buf, len); |
||
942 |
es->argparens++; |
||
943 |
break; |
||
944 |
} |
||
945 |
81872 |
} |
|
946 |
|||
947 |
static |
||
948 |
void |
||
949 |
expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len) |
||
950 |
{ |
||
951 |
✓✗✗✗ ✓ |
245616 |
switch (es->state) { |
952 |
case ES_NORMAL: |
||
953 |
81872 |
expand_send(es, p, buf, len); |
|
954 |
81872 |
break; |
|
955 |
case ES_WANTLPAREN: |
||
956 |
expand_missingargs(es, p, false); |
||
957 |
es->state = ES_NORMAL; |
||
958 |
/* try again */ |
||
959 |
expand_got_rparen(es, p, buf, len); |
||
960 |
break; |
||
961 |
case ES_NOARG: |
||
962 |
assert(es->argparens == 0); |
||
963 |
if (stringarray_num(&es->args) > 0) { |
||
964 |
/* we are after a comma; enter an empty argument */ |
||
965 |
expand_newarg(es, buf, 0); |
||
966 |
} |
||
967 |
es->state = ES_NORMAL; |
||
968 |
expand_domacro(es, p); |
||
969 |
break; |
||
970 |
case ES_HAVEARG: |
||
971 |
if (es->argparens > 0) { |
||
972 |
es->argparens--; |
||
973 |
expand_appendarg(es, buf, len); |
||
974 |
} else { |
||
975 |
es->state = ES_NORMAL; |
||
976 |
expand_domacro(es, p); |
||
977 |
} |
||
978 |
break; |
||
979 |
} |
||
980 |
81872 |
} |
|
981 |
|||
982 |
static |
||
983 |
void |
||
984 |
expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len) |
||
985 |
{ |
||
986 |
switch (es->state) { |
||
987 |
case ES_NORMAL: |
||
988 |
expand_send(es, p, buf, len); |
||
989 |
break; |
||
990 |
case ES_WANTLPAREN: |
||
991 |
expand_missingargs(es, p, false); |
||
992 |
es->state = ES_NORMAL; |
||
993 |
/* try again */ |
||
994 |
expand_got_comma(es, p, buf, len); |
||
995 |
break; |
||
996 |
case ES_NOARG: |
||
997 |
assert(es->argparens == 0); |
||
998 |
expand_newarg(es, buf, 0); |
||
999 |
break; |
||
1000 |
case ES_HAVEARG: |
||
1001 |
if (es->argparens > 0) { |
||
1002 |
expand_appendarg(es, buf, len); |
||
1003 |
} else { |
||
1004 |
es->state = ES_NOARG; |
||
1005 |
} |
||
1006 |
break; |
||
1007 |
} |
||
1008 |
} |
||
1009 |
|||
1010 |
static |
||
1011 |
void |
||
1012 |
expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len) |
||
1013 |
{ |
||
1014 |
✓✗✗✗ ✓ |
31267794 |
switch (es->state) { |
1015 |
case ES_NORMAL: |
||
1016 |
10422598 |
expand_send(es, p, buf, len); |
|
1017 |
10422598 |
break; |
|
1018 |
case ES_WANTLPAREN: |
||
1019 |
expand_missingargs(es, p, false); |
||
1020 |
es->state = ES_NORMAL; |
||
1021 |
/* try again */ |
||
1022 |
expand_got_other(es, p, buf, len); |
||
1023 |
break; |
||
1024 |
case ES_NOARG: |
||
1025 |
expand_newarg(es, buf, len); |
||
1026 |
es->state = ES_HAVEARG; |
||
1027 |
break; |
||
1028 |
case ES_HAVEARG: |
||
1029 |
expand_appendarg(es, buf, len); |
||
1030 |
break; |
||
1031 |
} |
||
1032 |
10422598 |
} |
|
1033 |
|||
1034 |
static |
||
1035 |
void |
||
1036 |
expand_got_eof(struct expstate *es, struct place *p) |
||
1037 |
{ |
||
1038 |
✗✗✗✓ |
2924 |
switch (es->state) { |
1039 |
case ES_NORMAL: |
||
1040 |
break; |
||
1041 |
case ES_WANTLPAREN: |
||
1042 |
expand_missingargs(es, p, false); |
||
1043 |
break; |
||
1044 |
case ES_NOARG: |
||
1045 |
case ES_HAVEARG: |
||
1046 |
if (es->curmacro) { |
||
1047 |
complain(p, "Unclosed argument list for macro %s", |
||
1048 |
es->curmacro->name); |
||
1049 |
} else { |
||
1050 |
complain(p, "Unclosed argument list for defined()"); |
||
1051 |
} |
||
1052 |
complain_fail(); |
||
1053 |
expstate_destroyargs(es); |
||
1054 |
break; |
||
1055 |
} |
||
1056 |
1462 |
expand_send_eof(es, p); |
|
1057 |
1462 |
es->state = ES_NORMAL; |
|
1058 |
1462 |
es->curmacro = NULL; |
|
1059 |
1462 |
es->argparens = 0; |
|
1060 |
1462 |
} |
|
1061 |
|||
1062 |
static |
||
1063 |
void |
||
1064 |
doexpand(struct expstate *es, struct place *p, char *buf, size_t len) |
||
1065 |
{ |
||
1066 |
char *s; |
||
1067 |
size_t x; |
||
1068 |
bool inquote = false; |
||
1069 |
char quote = '\0'; |
||
1070 |
|||
1071 |
✓✓ | 76617572 |
while (len > 0) { |
1072 |
54523828 |
x = strspn(buf, ws); |
|
1073 |
✗✓ | 54523828 |
if (x > len) { |
1074 |
/* XXX gross, need strnspn */ |
||
1075 |
x = len; |
||
1076 |
} |
||
1077 |
|||
1078 |
✓✓ | 54523828 |
if (x > 0) { |
1079 |
17489906 |
expand_got_ws(es, p, buf, x); |
|
1080 |
17489906 |
buf += x; |
|
1081 |
17489906 |
len -= x; |
|
1082 |
17489906 |
continue; |
|
1083 |
} |
||
1084 |
|||
1085 |
37033922 |
x = strspn(buf, alnum); |
|
1086 |
✗✓ | 37033922 |
if (x > len) { |
1087 |
/* XXX gross, need strnspn */ |
||
1088 |
x = len; |
||
1089 |
} |
||
1090 |
|||
1091 |
✓✓ | 37033922 |
if (!inquote && x > 0) { |
1092 |
26447580 |
expand_got_word(es, p, buf, x); |
|
1093 |
26447580 |
buf += x; |
|
1094 |
26447580 |
len -= x; |
|
1095 |
26447580 |
continue; |
|
1096 |
} |
||
1097 |
|||
1098 |
✓✗✓✓ ✗✓ |
23292584 |
if (!inquote && len > 1 && buf[0] == '/' && buf[1] == '*') { |
1099 |
s = strstr(buf, "*/"); |
||
1100 |
if (s) { |
||
1101 |
x = s - buf; |
||
1102 |
} else { |
||
1103 |
x = len; |
||
1104 |
} |
||
1105 |
expand_got_ws(es, p, buf, x); |
||
1106 |
buf += x; |
||
1107 |
len -= x; |
||
1108 |
continue; |
||
1109 |
} |
||
1110 |
|||
1111 |
✓✗✓✓ |
21172684 |
if (!inquote && buf[0] == '(') { |
1112 |
81872 |
expand_got_lparen(es, p, buf, 1); |
|
1113 |
81872 |
buf++; |
|
1114 |
81872 |
len--; |
|
1115 |
81872 |
continue; |
|
1116 |
} |
||
1117 |
|||
1118 |
✓✗✓✓ |
21008940 |
if (!inquote && buf[0] == ')') { |
1119 |
81872 |
expand_got_rparen(es, p, buf, 1); |
|
1120 |
81872 |
buf++; |
|
1121 |
81872 |
len--; |
|
1122 |
81872 |
continue; |
|
1123 |
} |
||
1124 |
|||
1125 |
✓✗✗✓ |
20845196 |
if (!inquote && buf[0] == ',') { |
1126 |
expand_got_comma(es, p, buf, 1); |
||
1127 |
buf++; |
||
1128 |
len--; |
||
1129 |
continue; |
||
1130 |
} |
||
1131 |
|||
1132 |
✓✗✗✓ ✗✗ |
20845196 |
if (len > 1 && buf[0] == '\\' && |
1133 |
(buf[1] == '"' || buf[1] == '\'')) { |
||
1134 |
expand_got_other(es, p, buf, 2); |
||
1135 |
buf += 2; |
||
1136 |
len -= 2; |
||
1137 |
continue; |
||
1138 |
} |
||
1139 |
✓✗✓✗ ✗✓ |
31267794 |
if (!inquote && (buf[0] == '"' || buf[0] == '\'')) { |
1140 |
inquote = true; |
||
1141 |
quote = buf[0]; |
||
1142 |
✗✓✗✗ |
10422598 |
} else if (inquote && buf[0] == quote) { |
1143 |
inquote = false; |
||
1144 |
} |
||
1145 |
|||
1146 |
10422598 |
expand_got_other(es, p, buf, 1); |
|
1147 |
10422598 |
buf++; |
|
1148 |
10422598 |
len--; |
|
1149 |
} |
||
1150 |
3890382 |
} |
|
1151 |
|||
1152 |
char * |
||
1153 |
macroexpand(struct place *p, char *buf, size_t len, bool honordefined) |
||
1154 |
{ |
||
1155 |
struct expstate es; |
||
1156 |
char *ret; |
||
1157 |
|||
1158 |
expstate_init(&es, true, honordefined); |
||
1159 |
doexpand(&es, p, buf, len); |
||
1160 |
expand_got_eof(&es, p); |
||
1161 |
|||
1162 |
/* trim to fit, so the malloc debugging won't complain */ |
||
1163 |
es.buf = dorealloc(es.buf, es.bufmax, strlen(es.buf) + 1); |
||
1164 |
|||
1165 |
ret = es.buf; |
||
1166 |
es.buf = NULL; |
||
1167 |
es.bufpos = es.bufmax = 0; |
||
1168 |
|||
1169 |
expstate_cleanup(&es); |
||
1170 |
|||
1171 |
return ret; |
||
1172 |
} |
||
1173 |
|||
1174 |
void |
||
1175 |
macro_sendline(struct place *p, char *buf, size_t len) |
||
1176 |
{ |
||
1177 |
7780764 |
doexpand(&mainstate, p, buf, len); |
|
1178 |
3890382 |
output(p, "\n", 1); |
|
1179 |
3890382 |
} |
|
1180 |
|||
1181 |
void |
||
1182 |
macro_sendeof(struct place *p) |
||
1183 |
{ |
||
1184 |
2924 |
expand_got_eof(&mainstate, p); |
|
1185 |
1462 |
} |
|
1186 |
|||
1187 |
//////////////////////////////////////////////////////////// |
||
1188 |
// module initialization |
||
1189 |
|||
1190 |
void |
||
1191 |
macros_init(void) |
||
1192 |
{ |
||
1193 |
2924 |
macrotable_init(); |
|
1194 |
1462 |
expstate_init(&mainstate, false, false); |
|
1195 |
1462 |
} |
|
1196 |
|||
1197 |
void |
||
1198 |
macros_cleanup(void) |
||
1199 |
{ |
||
1200 |
2924 |
expstate_cleanup(&mainstate); |
|
1201 |
1462 |
macrotable_cleanup(); |
|
1202 |
1462 |
} |
Generated by: GCOVR (Version 3.3) |