Mercurial > ~dholland > hg > tradcpp > index.cgi
annotate macro.c @ 136:59680a727e9d
Improve previous.
Just in case we ever crash and reach cleanup() while processing an
-include foo option, take the array entry for it out of the array to
make sure it doesn't get freed twice. This case shouldn't be
reachable, but it's better to be safe.
author | David A. Holland |
---|---|
date | Tue, 09 Jul 2013 13:38:43 -0400 |
parents | 2e1496dd96c4 |
children | 7ab3d0c09cd8 |
rev | line source |
---|---|
30 | 1 /*- |
99
60184aa42604
add 2013 to copyrights where it seems warranted
David A. Holland
parents:
88
diff
changeset
|
2 * Copyright (c) 2010, 2013 The NetBSD Foundation, Inc. |
30 | 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 | |
33 | 30 #include <stdint.h> |
17 | 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" | |
19 | 38 #include "output.h" |
39 | |
40 struct expansionitem { | |
41 bool isstring; | |
42 union { | |
43 char *string; | |
44 unsigned param; | |
45 }; | |
46 }; | |
107 | 47 DECLARRAY(expansionitem, static UNUSED); |
47
2e25e55dba6b
Fix inline usage as per the version in dholland-make2.
David A. Holland
parents:
42
diff
changeset
|
48 DEFARRAY(expansionitem, static); |
17 | 49 |
50 struct macro { | |
51 struct place defplace; | |
52 struct place expansionplace; | |
53 unsigned hash; | |
54 char *name; | |
18 | 55 bool hasparams; |
56 struct stringarray params; | |
19 | 57 struct expansionitemarray expansion; |
58 bool inuse; | |
17 | 59 }; |
107 | 60 DECLARRAY(macro, static UNUSED); |
47
2e25e55dba6b
Fix inline usage as per the version in dholland-make2.
David A. Holland
parents:
42
diff
changeset
|
61 DEFARRAY(macro, static); |
107 | 62 DECLARRAY(macroarray, static UNUSED); |
47
2e25e55dba6b
Fix inline usage as per the version in dholland-make2.
David A. Holland
parents:
42
diff
changeset
|
63 DEFARRAY(macroarray, static); |
17 | 64 |
65 static struct macroarrayarray macros; | |
66 static unsigned total_macros; | |
67 static unsigned hashmask; | |
68 | |
69 //////////////////////////////////////////////////////////// | |
70 // macro structure ops | |
71 | |
72 static | |
19 | 73 struct expansionitem * |
74 expansionitem_create_string(const char *string) | |
75 { | |
76 struct expansionitem *ei; | |
77 | |
78 ei = domalloc(sizeof(*ei)); | |
79 ei->isstring = true; | |
80 ei->string = dostrdup(string); | |
81 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 if (ei->isstring) { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
113 dostrfree(ei->string); |
19 | 114 } |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
115 dofree(ei, sizeof(*ei)); |
19 | 116 } |
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 | |
17 | 139 struct macro * |
18 | 140 macro_create(struct place *p1, const char *name, unsigned hash, |
19 | 141 struct place *p2) |
17 | 142 { |
143 struct macro *m; | |
144 | |
145 m = domalloc(sizeof(*m)); | |
146 m->defplace = *p1; | |
147 m->expansionplace = *p2; | |
148 m->hash = hash; | |
149 m->name = dostrdup(name); | |
18 | 150 m->hasparams = false; |
151 stringarray_init(&m->params); | |
19 | 152 expansionitemarray_init(&m->expansion); |
153 m->inuse = false; | |
17 | 154 return m; |
155 } | |
156 | |
19 | 157 DESTROYALL_ARRAY(expansionitem, ); |
158 | |
17 | 159 static |
160 void | |
161 macro_destroy(struct macro *m) | |
162 { | |
19 | 163 expansionitemarray_destroyall(&m->expansion); |
164 expansionitemarray_cleanup(&m->expansion); | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
165 dostrfree(m->name); |
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
166 dofree(m, sizeof(*m)); |
17 | 167 } |
168 | |
18 | 169 static |
170 bool | |
171 macro_eq(const struct macro *m1, const struct macro *m2) | |
172 { | |
173 unsigned num1, num2, i; | |
19 | 174 struct expansionitem *ei1, *ei2; |
18 | 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 | |
19 | 185 num1 = expansionitemarray_num(&m1->expansion); |
186 num2 = expansionitemarray_num(&m2->expansion); | |
187 if (num1 != num2) { | |
18 | 188 return false; |
189 } | |
190 | |
19 | 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 | |
18 | 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 | |
17 | 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 | |
19 | 225 hashfunc(const char *s, size_t len) |
17 | 226 { |
227 uint16_t x1, x2, a; | |
19 | 228 size_t i; |
17 | 229 |
230 x1 = (uint16_t) (len >> 16); | |
231 x2 = (uint16_t) (len); | |
232 if (x1==0) { | |
233 x1++; | |
234 } | |
235 if (x2==0) { | |
236 x2++; | |
237 } | |
238 | |
239 for (i=0; i<len; i+=2) { | |
240 if (i==len-1) { | |
241 a = (unsigned char)s[i]; | |
242 /* don't run off the end of the array */ | |
243 } | |
244 else { | |
245 a = (unsigned char)s[i] + | |
246 ((uint16_t)(unsigned char)s[i+1] << 8); | |
247 } | |
248 x1 += a; | |
249 if (x1 < a) { | |
250 x1++; | |
251 } | |
252 x2 += x1; | |
253 if (x2 < x1) { | |
254 x2++; | |
255 } | |
256 } | |
257 | |
258 x1 ^= 0xffff; | |
259 x2 ^= 0xffff; | |
260 return ((uint32_t)x2)*65535U + x1; | |
261 } | |
262 | |
263 static | |
264 void | |
265 macrotable_init(void) | |
266 { | |
267 unsigned i; | |
268 | |
269 macroarrayarray_init(¯os); | |
270 macroarrayarray_setsize(¯os, 4); | |
271 for (i=0; i<4; i++) { | |
272 macroarrayarray_set(¯os, i, NULL); | |
273 } | |
274 total_macros = 0; | |
275 hashmask = 0x3; | |
276 } | |
277 | |
278 DESTROYALL_ARRAY(macro, ); | |
279 | |
280 static | |
281 void | |
282 macrotable_cleanup(void) | |
283 { | |
284 struct macroarray *bucket; | |
285 unsigned numbuckets, i; | |
286 | |
287 numbuckets = macroarrayarray_num(¯os); | |
288 for (i=0; i<numbuckets; i++) { | |
289 bucket = macroarrayarray_get(¯os, i); | |
28 | 290 if (bucket != NULL) { |
291 macroarray_destroyall(bucket); | |
292 macroarray_destroy(bucket); | |
293 } | |
17 | 294 } |
295 macroarrayarray_setsize(¯os, 0); | |
296 macroarrayarray_cleanup(¯os); | |
297 } | |
298 | |
299 static | |
300 struct macro * | |
19 | 301 macrotable_findlen(const char *name, size_t len, bool remove) |
17 | 302 { |
303 unsigned hash; | |
304 struct macroarray *bucket; | |
305 struct macro *m, *m2; | |
306 unsigned i, num; | |
19 | 307 size_t mlen; |
17 | 308 |
19 | 309 hash = hashfunc(name, len); |
17 | 310 bucket = macroarrayarray_get(¯os, hash & hashmask); |
311 if (bucket == NULL) { | |
312 return NULL; | |
313 } | |
314 num = macroarray_num(bucket); | |
315 for (i=0; i<num; i++) { | |
316 m = macroarray_get(bucket, i); | |
317 if (hash != m->hash) { | |
318 continue; | |
319 } | |
19 | 320 mlen = strlen(m->name); |
321 if (len == mlen && !memcmp(name, m->name, len)) { | |
17 | 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 return NULL; | |
334 } | |
335 | |
336 static | |
19 | 337 struct macro * |
338 macrotable_find(const char *name, bool remove) | |
339 { | |
340 return macrotable_findlen(name, strlen(name), remove); | |
341 } | |
342 | |
343 static | |
17 | 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; | |
74 | 358 tossbit = newmask & ~hashmask; |
17 | 359 hashmask = newmask; |
360 | |
361 for (i=0; i<numbuckets; i++) { | |
362 newbucket = NULL; | |
363 oldbucket = macroarrayarray_get(¯os, i); | |
74 | 364 if (oldbucket == NULL) { |
365 macroarrayarray_set(¯os, numbuckets + i, NULL); | |
366 continue; | |
367 } | |
17 | 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); | |
74 | 381 if (m != NULL) { |
382 if (k < j) { | |
383 macroarray_set(oldbucket, k, m); | |
384 } | |
385 k++; | |
17 | 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 numbuckets = macroarrayarray_num(¯os); | |
402 if (total_macros > 0 && total_macros / numbuckets > 9) { | |
403 macrotable_rehash(); | |
404 } | |
405 | |
19 | 406 hash = hashfunc(m->name, strlen(m->name)); |
17 | 407 bucket = macroarrayarray_get(¯os, hash & hashmask); |
408 if (bucket == NULL) { | |
409 bucket = macroarray_create(); | |
410 macroarrayarray_set(¯os, hash & hashmask, bucket); | |
411 } | |
412 macroarray_add(bucket, m, NULL); | |
413 total_macros++; | |
414 } | |
415 | |
416 //////////////////////////////////////////////////////////// | |
417 // external macro definition interface | |
418 | |
18 | 419 static |
420 struct macro * | |
421 macro_define_common_start(struct place *p1, const char *macro, | |
19 | 422 struct place *p2) |
17 | 423 { |
424 struct macro *m; | |
19 | 425 unsigned hash; |
17 | 426 |
18 | 427 if (!is_identifier(macro)) { |
428 complain(p1, "Invalid macro name %s", macro); | |
429 complain_fail(); | |
430 } | |
431 | |
19 | 432 hash = hashfunc(macro, strlen(macro)); |
433 m = macro_create(p1, macro, hash, p2); | |
18 | 434 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 oldm = macrotable_find(m->name, false); | |
445 if (oldm != NULL) { | |
446 ok = macro_eq(m, oldm); | |
447 if (ok) { | |
84
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
448 /* in traditional cpp this is silent */ |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
449 //complain(&m->defplace, |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
450 // "Warning: redefinition of %s", m->name); |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
451 //complain(&oldm->defplace, |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
452 // "Previous definition was here"); |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
453 //if (mode.werror) { |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
454 // complain_fail(); |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
455 //} |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
456 } else { |
18 | 457 complain(&m->defplace, |
84
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
458 "Warning: non-identical redefinition of %s", |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
459 m->name); |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
460 complain(&oldm->defplace, |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
461 "Previous definition was here"); |
7e4723d34248
Complain only about non-identical redefinitions of macros.
David A. Holland
parents:
74
diff
changeset
|
462 /* in traditional cpp this is not fatal */ |
17 | 463 if (mode.werror) { |
464 complain_fail(); | |
465 } | |
466 } | |
18 | 467 macro_destroy(m); |
17 | 468 return; |
469 } | |
18 | 470 macrotable_add(m); |
471 } | |
17 | 472 |
18 | 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 | |
19 | 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); | |
27 | 516 if (strlen(param) == len && !memcmp(name, param, len)) { |
19 | 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 (pos > blockstart) { | |
540 ei = expansionitem_create_stringlen( | |
541 buf + blockstart, | |
27 | 542 wordstart - blockstart); |
19 | 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, | |
25 | 557 pos - blockstart); |
19 | 558 expansionitemarray_add(&m->expansion, ei, NULL); |
559 } | |
560 } | |
561 | |
18 | 562 void |
563 macro_define_plain(struct place *p1, const char *macro, | |
564 struct place *p2, const char *expansion) | |
565 { | |
566 struct macro *m; | |
19 | 567 struct expansionitem *ei; |
18 | 568 |
19 | 569 m = macro_define_common_start(p1, macro, p2); |
570 ei = expansionitem_create_string(expansion); | |
571 expansionitemarray_add(&m->expansion, ei, NULL); | |
18 | 572 macro_define_common_end(m); |
573 } | |
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 | |
19 | 582 m = macro_define_common_start(p1, macro, p3); |
25 | 583 m->hasparams = true; |
18 | 584 macro_parse_parameters(m, p2, params); |
19 | 585 macro_parse_expansion(m, expansion); |
18 | 586 macro_define_common_end(m); |
17 | 587 } |
588 | |
589 void | |
590 macro_undef(const char *macro) | |
591 { | |
592 struct macro *m; | |
593 | |
594 m = macrotable_find(macro, true); | |
595 if (m) { | |
596 macro_destroy(m); | |
597 } | |
598 } | |
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 | |
19 | 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 es->honordefined = honordefined; | |
634 es->state = ES_NORMAL; | |
635 es->curmacro = NULL; | |
636 stringarray_init(&es->args); | |
637 es->argparens = 0; | |
638 es->tobuf = tobuf; | |
639 es->buf = NULL; | |
640 es->bufpos = 0; | |
641 es->bufmax = 0; | |
642 } | |
643 | |
644 static | |
645 void | |
646 expstate_cleanup(struct expstate *es) | |
647 { | |
648 assert(es->state == ES_NORMAL); | |
649 stringarray_cleanup(&es->args); | |
650 if (es->buf) { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
651 dofree(es->buf, es->bufmax); |
19 | 652 } |
653 } | |
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++) { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
663 dostrfree(stringarray_get(&es->args, i)); |
19 | 664 } |
665 stringarray_setsize(&es->args, 0); | |
666 } | |
667 | |
668 static | |
669 void | |
21 | 670 expand_send(struct expstate *es, struct place *p, const char *buf, size_t len) |
19 | 671 { |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
672 size_t oldmax; |
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
673 |
19 | 674 if (es->tobuf) { |
38
b156910b59b2
Wrap free() in dofree() to allow instrumenting it for debugging.
David A. Holland
parents:
33
diff
changeset
|
675 assert(es->bufpos <= es->bufmax); |
19 | 676 if (es->bufpos + len > es->bufmax) { |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
677 oldmax = es->bufmax; |
19 | 678 if (es->bufmax == 0) { |
679 es->bufmax = 64; | |
680 } | |
681 while (es->bufpos + len > es->bufmax) { | |
682 es->bufmax *= 2; | |
683 } | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
684 es->buf = dorealloc(es->buf, oldmax, es->bufmax); |
19 | 685 } |
686 memcpy(es->buf + es->bufpos, buf, len); | |
687 es->bufpos += len; | |
38
b156910b59b2
Wrap free() in dofree() to allow instrumenting it for debugging.
David A. Holland
parents:
33
diff
changeset
|
688 assert(es->bufpos <= es->bufmax); |
19 | 689 } else { |
21 | 690 output(p, buf, len); |
19 | 691 } |
692 } | |
693 | |
694 static | |
695 void | |
21 | 696 expand_send_eof(struct expstate *es, struct place *p) |
19 | 697 { |
698 if (es->tobuf) { | |
21 | 699 expand_send(es, p, "", 1); |
19 | 700 es->bufpos--; |
701 } else { | |
702 output_eof(); | |
703 } | |
704 } | |
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); | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
729 text = dorealloc(text, oldlen + 1, oldlen + len + 1); |
19 | 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 * | |
28 | 737 expand_substitute(struct place *p, struct expstate *es) |
19 | 738 { |
739 struct expansionitem *ei; | |
740 unsigned i, num; | |
741 size_t len; | |
742 char *arg; | |
743 char *ret; | |
28 | 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 } | |
19 | 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 strcat(ret, ei->string); | |
783 } else { | |
784 arg = stringarray_get(&es->args, ei->param); | |
785 strcat(ret, arg); | |
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(); | |
21 | 804 expand_send(es, p, "0", 1); |
19 | 805 return; |
806 } | |
807 m = macrotable_find(stringarray_get(&es->args, 0), false); | |
21 | 808 expand_send(es, p, (m != NULL) ? "1" : "0", 1); |
25 | 809 expstate_destroyargs(es); |
19 | 810 return; |
811 } | |
812 | |
813 assert(es->curmacro->inuse == false); | |
814 es->curmacro->inuse = true; | |
815 | |
28 | 816 newbuf = expand_substitute(p, es); |
19 | 817 newbuf2 = macroexpand(p, newbuf, strlen(newbuf), false); |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
818 dostrfree(newbuf); |
25 | 819 expstate_destroyargs(es); |
19 | 820 doexpand(es, p, newbuf2, strlen(newbuf2)); |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
821 dostrfree(newbuf2); |
19 | 822 |
823 es->curmacro->inuse = false; | |
824 } | |
825 | |
87
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
826 /* |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
827 * The traditional behavior if a function-like macro appears without |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
828 * arguments is to pretend it isn't a macro; that is, just emit its |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
829 * name. |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
830 */ |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
831 static |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
832 void |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
833 expand_missingargs(struct expstate *es, struct place *p, bool needspace) |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
834 { |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
835 if (es->curmacro == NULL) { |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
836 /* defined */ |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
837 expand_send(es, p, "defined", 7); |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
838 return; |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
839 } |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
840 expand_send(es, p, es->curmacro->name, strlen(es->curmacro->name)); |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
841 /* send a space in case we ate whitespace after the macro name */ |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
842 if (needspace) { |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
843 expand_send(es, p, " ", 1); |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
844 } |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
845 } |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
846 |
19 | 847 static |
848 void | |
849 expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len) | |
850 { | |
851 switch (es->state) { | |
852 case ES_NORMAL: | |
21 | 853 expand_send(es, p, buf, len); |
19 | 854 break; |
855 case ES_WANTLPAREN: | |
856 break; | |
857 case ES_NOARG: | |
118
c13f36775fe8
Preserve leading whitespace in macro arguments.
David A. Holland
parents:
117
diff
changeset
|
858 expand_newarg(es, buf, len); |
c13f36775fe8
Preserve leading whitespace in macro arguments.
David A. Holland
parents:
117
diff
changeset
|
859 es->state = ES_HAVEARG; |
19 | 860 break; |
861 case ES_HAVEARG: | |
862 expand_appendarg(es, buf, len); | |
863 break; | |
864 } | |
865 } | |
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; | |
17 | 874 |
19 | 875 switch (es->state) { |
876 case ES_NORMAL: | |
877 if (es->honordefined && | |
878 len == 7 && !memcmp(buf, "defined", 7)) { | |
879 es->curmacro = NULL; | |
880 es->state = ES_WANTLPAREN; | |
881 break; | |
882 } | |
883 m = macrotable_findlen(buf, len, false); | |
42
ad7763329eba
Don't crash if a macro tries to expand itself recursively.
David A. Holland
parents:
40
diff
changeset
|
884 if (m == NULL || m->inuse) { |
21 | 885 expand_send(es, p, buf, len); |
19 | 886 } 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)); | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
894 dostrfree(newbuf); |
19 | 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) { | |
87
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
903 expand_missingargs(es, p, true); |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
904 es->state = ES_NORMAL; |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
905 /* try again */ |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
906 expand_got_word(es, p, buf, len); |
19 | 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 } | |
923 | |
924 static | |
925 void | |
926 expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len) | |
927 { | |
928 switch (es->state) { | |
929 case ES_NORMAL: | |
21 | 930 expand_send(es, p, buf, len); |
19 | 931 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 } | |
946 | |
947 static | |
948 void | |
949 expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len) | |
950 { | |
951 switch (es->state) { | |
952 case ES_NORMAL: | |
21 | 953 expand_send(es, p, buf, len); |
19 | 954 break; |
955 case ES_WANTLPAREN: | |
87
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
956 expand_missingargs(es, p, false); |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
957 es->state = ES_NORMAL; |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
958 /* try again */ |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
959 expand_got_rparen(es, p, buf, len); |
19 | 960 break; |
961 case ES_NOARG: | |
962 assert(es->argparens == 0); | |
117
c46959e2d9ef
Handle empty arguments properly when there's more than one argument.
David A. Holland
parents:
107
diff
changeset
|
963 if (stringarray_num(&es->args) > 0) { |
c46959e2d9ef
Handle empty arguments properly when there's more than one argument.
David A. Holland
parents:
107
diff
changeset
|
964 /* we are after a comma; enter an empty argument */ |
c46959e2d9ef
Handle empty arguments properly when there's more than one argument.
David A. Holland
parents:
107
diff
changeset
|
965 expand_newarg(es, buf, 0); |
c46959e2d9ef
Handle empty arguments properly when there's more than one argument.
David A. Holland
parents:
107
diff
changeset
|
966 } |
19 | 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 } | |
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: | |
21 | 988 expand_send(es, p, buf, len); |
19 | 989 break; |
990 case ES_WANTLPAREN: | |
87
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
991 expand_missingargs(es, p, false); |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
992 es->state = ES_NORMAL; |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
993 /* try again */ |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
994 expand_got_comma(es, p, buf, len); |
19 | 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 switch (es->state) { | |
1015 case ES_NORMAL: | |
21 | 1016 expand_send(es, p, buf, len); |
19 | 1017 break; |
1018 case ES_WANTLPAREN: | |
87
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
1019 expand_missingargs(es, p, false); |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
1020 es->state = ES_NORMAL; |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
1021 /* try again */ |
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
1022 expand_got_other(es, p, buf, len); |
19 | 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 } | |
1033 | |
1034 static | |
1035 void | |
1036 expand_got_eof(struct expstate *es, struct place *p) | |
1037 { | |
1038 switch (es->state) { | |
1039 case ES_NORMAL: | |
1040 break; | |
1041 case ES_WANTLPAREN: | |
87
2b153df78214
Don't bomb out if a function-like macro is given no arguments.
David A. Holland
parents:
85
diff
changeset
|
1042 expand_missingargs(es, p, false); |
19 | 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 } | |
88 | 1056 expand_send_eof(es, p); |
19 | 1057 es->state = ES_NORMAL; |
1058 es->curmacro = NULL; | |
1059 es->argparens = 0; | |
1060 } | |
1061 | |
1062 static | |
1063 void | |
1064 doexpand(struct expstate *es, struct place *p, char *buf, size_t len) | |
1065 { | |
85 | 1066 char *s; |
19 | 1067 size_t x; |
85 | 1068 bool inquote = false; |
128
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
118
diff
changeset
|
1069 char quote = '\0'; |
19 | 1070 |
1071 while (len > 0) { | |
1072 x = strspn(buf, ws); | |
28 | 1073 if (x > len) { |
1074 /* XXX gross, need strnspn */ | |
1075 x = len; | |
1076 } | |
1077 | |
19 | 1078 if (x > 0) { |
1079 expand_got_ws(es, p, buf, x); | |
1080 buf += x; | |
1081 len -= x; | |
28 | 1082 continue; |
19 | 1083 } |
1084 | |
1085 x = strspn(buf, alnum); | |
28 | 1086 if (x > len) { |
1087 /* XXX gross, need strnspn */ | |
1088 x = len; | |
1089 } | |
1090 | |
19 | 1091 if (x > 0) { |
1092 expand_got_word(es, p, buf, x); | |
1093 buf += x; | |
1094 len -= x; | |
1095 continue; | |
1096 } | |
1097 | |
85 | 1098 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 | |
129
2e1496dd96c4
Don't recognize macro argument parens or commas within quotes.
David A. Holland
parents:
128
diff
changeset
|
1111 if (!inquote && buf[0] == '(') { |
19 | 1112 expand_got_lparen(es, p, buf, 1); |
1113 buf++; | |
1114 len--; | |
1115 continue; | |
1116 } | |
1117 | |
129
2e1496dd96c4
Don't recognize macro argument parens or commas within quotes.
David A. Holland
parents:
128
diff
changeset
|
1118 if (!inquote && buf[0] == ')') { |
19 | 1119 expand_got_rparen(es, p, buf, 1); |
1120 buf++; | |
1121 len--; | |
1122 continue; | |
1123 } | |
1124 | |
129
2e1496dd96c4
Don't recognize macro argument parens or commas within quotes.
David A. Holland
parents:
128
diff
changeset
|
1125 if (!inquote && buf[0] == ',') { |
19 | 1126 expand_got_comma(es, p, buf, 1); |
1127 buf++; | |
1128 len--; | |
1129 continue; | |
1130 } | |
1131 | |
128
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
118
diff
changeset
|
1132 if (len > 1 && buf[0] == '\\' && |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
118
diff
changeset
|
1133 (buf[1] == '"' || buf[1] == '\'')) { |
85 | 1134 expand_got_other(es, p, buf, 2); |
1135 buf += 2; | |
1136 len -= 2; | |
1137 continue; | |
1138 } | |
128
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
118
diff
changeset
|
1139 if (!inquote && (buf[0] == '"' || buf[0] == '\'')) { |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
118
diff
changeset
|
1140 inquote = true; |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
118
diff
changeset
|
1141 quote = buf[0]; |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
118
diff
changeset
|
1142 } else if (inquote && buf[0] == quote) { |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
118
diff
changeset
|
1143 inquote = false; |
85 | 1144 } |
1145 | |
19 | 1146 expand_got_other(es, p, buf, 1); |
1147 buf++; | |
1148 len--; | |
1149 } | |
1150 } | |
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); | |
40 | 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 | |
19 | 1165 ret = es.buf; |
1166 es.buf = NULL; | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
1167 es.bufpos = es.bufmax = 0; |
40 | 1168 |
19 | 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 doexpand(&mainstate, p, buf, len); | |
21 | 1178 output(p, "\n", 1); |
19 | 1179 } |
1180 | |
1181 void | |
1182 macro_sendeof(struct place *p) | |
1183 { | |
1184 expand_got_eof(&mainstate, p); | |
1185 } | |
17 | 1186 |
1187 //////////////////////////////////////////////////////////// | |
1188 // module initialization | |
1189 | |
1190 void | |
1191 macros_init(void) | |
1192 { | |
1193 macrotable_init(); | |
19 | 1194 expstate_init(&mainstate, false, false); |
17 | 1195 } |
1196 | |
1197 void | |
1198 macros_cleanup(void) | |
1199 { | |
19 | 1200 expstate_cleanup(&mainstate); |
17 | 1201 macrotable_cleanup(); |
1202 } |