1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | #ifdef _MSC_VER |
21 | # define _POSIX_ |
22 | #endif |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | #if defined(__IBMC__) || defined(__EMX__) |
27 | # define PATH_MAX4096 _MAX_PATH |
28 | #endif |
29 | #include <limits.h> |
30 | |
31 | #include "cpp.h" |
32 | |
33 | #define NCONCAT16384 16384 |
34 | |
35 | |
36 | |
37 | |
38 | void |
39 | dodefine(Tokenrow * trp) |
40 | { |
41 | Token *tp; |
42 | Nlist *np; |
43 | Source *s; |
44 | Tokenrow *def, *args; |
45 | static uchar location[(PATH_MAX4096 + 8) * NINC32], *cp; |
46 | |
47 | tp = trp->tp + 1; |
48 | if (tp >= trp->lp || tp->type != NAME) |
49 | { |
50 | error(ERROR, "#defined token is not a name"); |
51 | return; |
52 | } |
53 | np = lookup(tp, 1); |
54 | if (np->flag & ISUNCHANGE0x04) |
55 | { |
56 | error(ERROR, "#defined token %t can't be redefined", tp); |
57 | return; |
58 | } |
59 | |
60 | tp += 1; |
61 | args = NULL((void*)0); |
62 | if (tp < trp->lp && tp->type == LP && tp->wslen == 0) |
63 | { |
64 | tp += 1; |
65 | args = new(Tokenrow)(Tokenrow *)domalloc(sizeof(Tokenrow)); |
66 | maketokenrow(2, args); |
67 | if (tp->type != RP) |
68 | { |
69 | |
70 | size_t narg = 0; |
71 | int err = 0; |
72 | |
73 | for (;;) |
74 | { |
75 | Token *atp; |
76 | |
77 | if (tp->type != NAME) |
78 | { |
79 | err++; |
80 | break; |
81 | } |
82 | if (narg >= args->max) |
83 | growtokenrow(args); |
84 | for (atp = args->bp; atp < args->lp; atp++) |
85 | if (atp->len == tp->len |
86 | && strncmp((char *) atp->t, (char *) tp->t, tp->len) == 0) |
87 | error(ERROR, "Duplicate macro argument"); |
88 | *args->lp++ = *tp; |
89 | narg++; |
90 | tp += 1; |
91 | if (tp->type == RP) |
92 | break; |
93 | if (tp->type != COMMA) |
94 | { |
95 | err++; |
96 | break; |
97 | } |
98 | tp += 1; |
99 | } |
100 | if (err) |
101 | { |
102 | error(ERROR, "Syntax error in macro parameters"); |
103 | return; |
104 | } |
105 | } |
106 | tp += 1; |
107 | } |
108 | trp->tp = tp; |
109 | if (((trp->lp) - 1)->type == NL) |
110 | trp->lp -= 1; |
111 | def = normtokenrow(trp); |
112 | if (np->flag & ISDEFINED0x01) |
113 | { |
114 | if (comparetokens(def, np->vp) |
115 | || (np->ap == NULL((void*)0)) != (args == NULL((void*)0)) |
116 | || (np->ap && comparetokens(args, np->ap))) |
117 | { |
118 | if ( np->loc ) |
119 | error(ERROR, |
120 | "Macro redefinition of %t (already defined at %s)", |
121 | trp->bp + 2, np->loc); |
122 | else |
123 | error(ERROR, |
124 | "Macro redefinition of %t (already defined at %s)", |
125 | trp->bp + 2, "commandline" ); |
126 | } |
127 | } |
128 | if (args) |
129 | { |
130 | Tokenrow *tap; |
131 | |
132 | tap = normtokenrow(args); |
133 | dofree(args->bp); |
134 | args = tap; |
135 | } |
136 | np->ap = args; |
137 | np->vp = def; |
138 | np->flag |= ISDEFINED0x01; |
139 | |
140 | |
141 | for (cp = location, s = cursource; s; s = s->next) |
142 | if (*s->filename) |
143 | { |
144 | if (cp != location) |
145 | *cp++ = ' '; |
146 | sprintf((char *)cp, "%s:%d", s->filename, s->line); |
147 | cp += strlen((char *)cp); |
148 | } |
149 | |
150 | np->loc = newstring(location, strlen((char *)location), 0); |
151 | |
152 | if (Mflag) |
153 | { |
154 | if (np->ap) |
155 | error(INFO, "Macro definition of %s(%r) [%r]", np->name, np->ap, np->vp); |
156 | else |
157 | error(INFO, "Macro definition of %s [%r]", np->name, np->vp); |
158 | } |
159 | } |
160 | |
161 | |
162 | |
163 | |
164 | void |
165 | doadefine(Tokenrow * trp, int type) |
166 | { |
167 | Nlist *np; |
168 | static uchar onestr[2] = "1"; |
169 | static Token onetoken[1] = {{NUMBER, 0, 0, 1, onestr, 0}}; |
170 | static Tokenrow onetr = {onetoken, onetoken, onetoken + 1, 1}; |
171 | |
172 | trp->tp = trp->bp; |
173 | if (type == 'U') |
174 | { |
175 | if (trp->lp - trp->tp != 2 || trp->tp->type != NAME) |
176 | goto syntax; |
177 | if ((np = lookup(trp->tp, 0)) == NULL((void*)0)) |
178 | return; |
179 | np->flag &= ~ISDEFINED0x01; |
180 | return; |
181 | } |
182 | |
183 | if (type == 'A') |
184 | { |
185 | if (trp->tp >= trp->lp || trp->tp->type != NAME) |
186 | goto syntax; |
187 | trp->tp->type = ARCHITECTURE; |
188 | np = lookup(trp->tp, 1); |
189 | np->flag |= ISARCHITECTURE0x10; |
190 | trp->tp += 1; |
191 | if (trp->tp >= trp->lp || trp->tp->type == END) |
192 | { |
193 | np->vp = &onetr; |
194 | return; |
195 | } |
196 | else |
197 | error(FATAL, "Illegal -A argument %r", trp); |
198 | } |
199 | |
200 | if (trp->tp >= trp->lp || trp->tp->type != NAME) |
201 | goto syntax; |
202 | np = lookup(trp->tp, 1); |
203 | np->flag |= ISDEFINED0x01; |
204 | trp->tp += 1; |
205 | if (trp->tp >= trp->lp || trp->tp->type == END) |
206 | { |
207 | np->vp = &onetr; |
208 | return; |
209 | } |
210 | if (trp->tp->type != ASGN) |
211 | goto syntax; |
212 | trp->tp += 1; |
213 | if ((trp->lp - 1)->type == END) |
214 | trp->lp -= 1; |
215 | np->vp = normtokenrow(trp); |
216 | return; |
217 | syntax: |
218 | error(FATAL, "Illegal -D or -U argument %r", trp); |
219 | } |
220 | |
221 | |
222 | |
223 | |
224 | |
225 | |
226 | |
227 | void |
228 | expandrow(Tokenrow * trp, char *flag) |
229 | { |
230 | Token * tp; |
231 | Nlist * np; |
232 | |
233 | MacroValidatorList validators; |
234 | mvl_init(&validators); |
235 | |
236 | tokenrow_zeroTokenIdentifiers(trp); |
237 | |
238 | if (flag) |
239 | setsource(flag, -1, -1, "", 0); |
240 | for (tp = trp->tp; tp < trp->lp;) |
241 | { |
242 | mvl_check(&validators, tp); |
243 | |
244 | if (tp->type != NAME |
245 | || quicklook(tp->t[0], tp->len > 1 ? tp->t[1] : 0)(namebit[(tp->t[0])&077] & (1<<((tp->len > 1 ? tp->t[1] : 0)&037))) == 0 |
246 | || (np = lookup(tp, 0)) == NULL((void*)0) |
247 | || (np->flag & (ISDEFINED0x01 | ISMAC0x08)) == 0 |
248 | || (np->flag & ISACTIVE0x80) != 0) |
249 | { |
250 | tp++; |
251 | continue; |
252 | } |
253 | trp->tp = tp; |
254 | if (np->val == KDEFINED) |
255 | { |
256 | tp->type = DEFINED; |
257 | if ((tp + 1) < trp->lp && (tp + 1)->type == NAME) |
258 | (tp + 1)->type = NAME1; |
259 | else |
260 | if ((tp + 3) < trp->lp && (tp + 1)->type == LP |
261 | && (tp + 2)->type == NAME && (tp + 3)->type == RP) |
262 | (tp + 2)->type = NAME1; |
263 | else |
264 | error(ERROR, "Incorrect syntax for `defined'"); |
265 | tp++; |
266 | continue; |
267 | } |
268 | else |
269 | if (np->val == KMACHINE) |
270 | { |
271 | if (((tp - 1) >= trp->bp) && ((tp - 1)->type == SHARP)) |
272 | { |
273 | tp->type = ARCHITECTURE; |
274 | if ((tp + 1) < trp->lp && (tp + 1)->type == NAME) |
275 | (tp + 1)->type = NAME2; |
276 | else |
277 | if ((tp + 3) < trp->lp && (tp + 1)->type == LP |
278 | && (tp + 2)->type == NAME && (tp + 3)->type == RP) |
279 | (tp + 2)->type = NAME2; |
280 | else |
281 | error(ERROR, "Incorrect syntax for `#machine'"); |
282 | } |
283 | tp++; |
284 | continue; |
285 | } |
286 | |
287 | if (np->flag & ISMAC0x08) |
288 | builtin(trp, np->val); |
289 | else |
290 | expand(trp, np, &validators); |
291 | tp = trp->tp; |
292 | } |
293 | if (flag) |
294 | unsetsource(); |
295 | |
296 | mvl_destruct(&validators); |
297 | } |
298 | |
299 | |
300 | |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | |
307 | void |
308 | expand(Tokenrow * trp, Nlist * np, MacroValidatorList * pValidators) |
309 | { |
310 | Tokenrow ntr; |
311 | int ntokc, narg; |
312 | Tokenrow *atr[NARG32 + 1]; |
313 | |
314 | if (Mflag == 2) |
315 | { |
316 | if (np->ap) |
317 | error(INFO, "Macro expansion of %t with %s(%r)", trp->tp, np->name, np->ap); |
318 | else |
319 | error(INFO, "Macro expansion of %t with %s", trp->tp, np->name); |
320 | } |
321 | |
322 | copytokenrow(&ntr, np->vp); |
323 | if (np->ap == NULL((void*)0)) |
324 | ntokc = 1; |
325 | else |
326 | { |
327 | int i; |
328 | |
329 | ntokc = gatherargs(trp, atr, &narg); |
330 | if (narg < 0) |
331 | { |
332 | trp->tp++; |
333 | return; |
334 | } |
335 | if (narg != rowlen(np->ap)((np->ap)->lp - (np->ap)->bp)) |
336 | { |
337 | error(ERROR, "Disagreement in number of macro arguments"); |
338 | trp->tp += ntokc; |
339 | return; |
340 | } |
341 | |
342 | |
343 | |
344 | |
345 | |
346 | |
347 | for (i = 1; i < ntokc; i++) |
348 | { |
349 | mvl_check(pValidators,trp->tp+i); |
350 | } |
351 | |
352 | substargs(np, &ntr, atr); |
353 | for (i = 0; i < narg; i++) |
354 | { |
355 | dofree(atr[i]->bp); |
356 | dofree(atr[i]); |
357 | } |
358 | } |
359 | |
360 | doconcat(&ntr); |
361 | ntr.tp = ntr.bp; |
362 | makespace(&ntr, trp->tp); |
363 | |
364 | tokenrow_zeroTokenIdentifiers(&ntr); |
365 | insertrow(trp, ntokc, &ntr); |
366 | |
367 | |
368 | |
369 | np->flag |= ISACTIVE0x80; |
370 | if (trp->tp != trp->lp) |
371 | { |
372 | mvl_add(pValidators,np,trp->tp); |
373 | } |
374 | else |
375 | { |
376 | mvl_add(pValidators,np,0); |
377 | } |
378 | |
379 | |
380 | trp->tp -= ntr.lp - ntr.bp; |
381 | |
382 | dofree(ntr.bp); |
383 | |
384 | return; |
385 | } |
386 | |
387 | |
388 | |
389 | |
390 | |
391 | |
392 | int |
393 | gatherargs(Tokenrow * trp, Tokenrow ** atr, int *narg) |
394 | { |
395 | int parens = 1; |
396 | int ntok = 0; |
397 | Token *bp, *lp; |
398 | Tokenrow ttr; |
399 | int ntokp; |
400 | int needspace; |
401 | |
402 | *narg = -1; |
403 | |
404 | |
405 | for (;;) |
406 | { |
407 | trp->tp++; |
408 | ntok++; |
409 | if (trp->tp >= trp->lp) |
410 | { |
411 | gettokens(trp, 0); |
412 | if ((trp->lp - 1)->type == END) |
413 | { |
414 | trp->lp -= 1; |
415 | trp->tp -= ntok; |
416 | return ntok; |
417 | } |
418 | } |
419 | if (trp->tp->type == LP) |
420 | break; |
421 | if (trp->tp->type != NL) |
422 | return ntok; |
423 | } |
424 | *narg = 0; |
425 | ntok++; |
426 | ntokp = ntok; |
427 | trp->tp++; |
428 | |
429 | needspace = 0; |
430 | while (parens > 0) |
431 | { |
432 | if (trp->tp >= trp->lp) |
433 | gettokens(trp, 0); |
434 | if (needspace) |
435 | { |
436 | needspace = 0; |
437 | |
438 | } |
439 | if (trp->tp->type == END) |
440 | { |
441 | trp->lp -= 1; |
442 | trp->tp -= ntok; |
443 | error(ERROR, "EOF in macro arglist"); |
444 | return ntok; |
445 | } |
446 | if (trp->tp->type == NL) |
447 | { |
448 | trp->tp += 1; |
449 | adjustrow(trp, -1); |
450 | trp->tp -= 1; |
451 | |
452 | needspace = 1; |
453 | continue; |
454 | } |
455 | if (trp->tp->type == LP) |
456 | parens++; |
457 | else |
458 | if (trp->tp->type == RP) |
459 | parens--; |
460 | trp->tp++; |
461 | ntok++; |
462 | } |
463 | trp->tp -= ntok; |
464 | |
465 | lp = bp = trp->tp + ntokp; |
466 | for (; parens >= 0; lp++) |
467 | { |
468 | if (lp->type == LP) |
469 | { |
470 | parens++; |
471 | continue; |
472 | } |
473 | if (lp->type == RP) |
474 | parens--; |
475 | if (lp->type == DSHARP) |
476 | lp->type = DSHARP1; |
477 | if ((lp->type == COMMA && parens == 0) || |
478 | ( parens < 0 && ((lp - 1)->type != LP))) |
479 | { |
480 | if (*narg >= NARG32 - 1) |
481 | error(FATAL, "Sorry, too many macro arguments"); |
482 | ttr.bp = ttr.tp = bp; |
483 | ttr.lp = lp; |
484 | atr[(*narg)++] = normtokenrow(&ttr); |
485 | bp = lp + 1; |
486 | } |
487 | } |
488 | return ntok; |
489 | } |
490 | |
491 | |
492 | |
493 | |
494 | |
495 | void |
496 | substargs(Nlist * np, Tokenrow * rtr, Tokenrow ** atr) |
497 | { |
498 | Tokenrow tatr; |
499 | Token *tp; |
500 | int ntok, argno; |
501 | |
502 | for (rtr->tp = rtr->bp; rtr->tp < rtr->lp;) |
503 | { |
504 | if (rtr->tp->type == SHARP) |
505 | { |
506 | tp = rtr->tp; |
507 | rtr->tp += 1; |
508 | if ((argno = lookuparg(np, rtr->tp)) < 0) |
509 | { |
510 | error(ERROR, "# not followed by macro parameter"); |
511 | continue; |
512 | } |
513 | ntok = 1 + (int)(rtr->tp - tp); |
514 | rtr->tp = tp; |
515 | insertrow(rtr, ntok, stringify(atr[argno])); |
516 | continue; |
517 | } |
518 | if (rtr->tp->type == NAME |
519 | && (argno = lookuparg(np, rtr->tp)) >= 0) |
520 | { |
521 | if (((rtr->tp + 1) < rtr->lp && (rtr->tp + 1)->type == DSHARP) |
522 | || (rtr->tp != rtr->bp && (rtr->tp - 1)->type == DSHARP)) |
523 | { |
524 | copytokenrow(&tatr, atr[argno]); |
525 | makespace(&tatr, rtr->tp); |
526 | insertrow(rtr, 1, &tatr); |
527 | dofree(tatr.bp); |
528 | } |
529 | else |
530 | { |
531 | copytokenrow(&tatr, atr[argno]); |
532 | makespace(&tatr, rtr->tp); |
533 | expandrow(&tatr, "<macro>"); |
534 | insertrow(rtr, 1, &tatr); |
535 | dofree(tatr.bp); |
536 | } |
537 | continue; |
538 | } |
539 | rtr->tp++; |
540 | } |
541 | } |
542 | |
543 | |
544 | |
545 | |
546 | void |
547 | doconcat(Tokenrow * trp) |
548 | { |
549 | Token *ltp, *ntp; |
550 | Tokenrow ntr; |
551 | size_t len; |
552 | |
553 | for (trp->tp = trp->bp; trp->tp < trp->lp; trp->tp++) |
554 | { |
555 | if (trp->tp->type == DSHARP1) |
556 | trp->tp->type = DSHARP; |
557 | else |
558 | if (trp->tp->type == DSHARP) |
559 | { |
560 | int i; |
561 | char tt[NCONCAT16384]; |
562 | |
563 | ltp = trp->tp - 1; |
564 | ntp = trp->tp + 1; |
565 | |
566 | if (ltp < trp->bp || ntp >= trp->lp) |
567 | { |
568 | error(ERROR, "## occurs at border of replacement"); |
569 | continue; |
570 | } |
571 | |
572 | ntp = ltp; |
573 | i = 1; |
574 | len = 0; |
575 | |
576 | do |
577 | { |
578 | if (len + ntp->len + ntp->wslen > sizeof(tt)) |
579 | { |
580 | error(ERROR, "## string concatination buffer overrun"); |
581 | break; |
582 | } |
583 | |
584 | if (ntp != trp->tp + 1) |
585 | { |
586 | strncpy((char *) tt + len, (char *) ntp->t - ntp->wslen, |
587 | ntp->len + ntp->wslen); |
588 | len += ntp->len + ntp->wslen; |
589 | } |
590 | else |
591 | { |
592 | strncpy((char *) tt + len, (char *) ntp->t, ntp->len); |
593 | len += ntp->len; |
594 | } |
595 | |
596 | ntp = trp->tp + i; |
597 | i++; |
598 | } |
599 | while (ntp < trp->lp); |
600 | |
601 | tt[len] = '\0'; |
602 | setsource("<##>", -1, -1, tt, 0); |
603 | maketokenrow(3, &ntr); |
604 | gettokens(&ntr, 1); |
605 | unsetsource(); |
606 | if (ntr.bp->type == UNCLASS) |
607 | error(WARNING, "Bad token %r produced by ##", &ntr); |
608 | while ((ntr.lp-1)->len == 0 && ntr.lp != ntr.bp) |
609 | ntr.lp--; |
610 | |
611 | doconcat(&ntr); |
612 | trp->tp = ltp; |
613 | makespace(&ntr, ltp); |
614 | insertrow(trp, (int)(ntp - ltp), &ntr); |
615 | dofree(ntr.bp); |
616 | trp->tp--; |
617 | } |
618 | } |
619 | } |
620 | |
621 | |
622 | |
623 | |
624 | |
625 | |
626 | int |
627 | lookuparg(Nlist * mac, Token * tp) |
628 | { |
629 | Token *ap; |
630 | |
631 | if (tp->type != NAME || mac->ap == NULL((void*)0)) |
632 | return -1; |
633 | for (ap = mac->ap->bp; ap < mac->ap->lp; ap++) |
634 | { |
635 | if (ap->len == tp->len && strncmp((char *) ap->t, (char *) tp->t, ap->len) == 0) |
636 | return (int)(ap - mac->ap->bp); |
637 | } |
638 | return -1; |
639 | } |
640 | |
641 | |
642 | |
643 | |
644 | #define STRLEN512 512 |
645 | Tokenrow * |
646 | stringify(Tokenrow * vp) |
647 | { |
648 | static Token t = {STRING, 0, 0, 0, NULL((void*)0), 0}; |
649 | static Tokenrow tr = {&t, &t, &t + 1, 1}; |
650 | Token *tp; |
651 | uchar s[STRLEN512]; |
652 | uchar *sp = s, *cp; |
653 | int i, instring; |
654 | |
655 | *sp++ = '"'; |
656 | for (tp = vp->bp; tp < vp->lp; tp++) |
657 | { |
658 | instring = tp->type == STRING || tp->type == CCON; |
659 | if (sp + 2 * tp->len + tp->wslen >= &s[STRLEN512 - 10]) |
660 | { |
661 | error(ERROR, "Stringified macro arg is too long"); |
662 | break; |
663 | } |
664 | |
665 | |
666 | if ( tp->wslen > 0 ) |
667 | *sp++ = ' '; |
668 | |
669 | |
670 | for (i = 0, cp = tp->t; (unsigned int)i < tp->len; i++) |
671 | { |
672 | if (instring && (*cp == '"' || *cp == '\\')) |
673 | *sp++ = '\\'; |
674 | *sp++ = *cp++; |
675 | } |
676 | } |
677 | *sp++ = '"'; |
678 | *sp = '\0'; |
679 | sp = s; |
680 | t.len = strlen((char *) sp); |
681 | t.t = newstring(sp, t.len, 0); |
682 | return &tr; |
683 | } |
684 | |
685 | |
686 | |
687 | |
688 | void |
689 | builtin(Tokenrow * trp, int biname) |
690 | { |
691 | char *op; |
692 | Token *tp; |
693 | Source *s; |
694 | |
695 | tp = trp->tp; |
696 | trp->tp++; |
697 | |
698 | s = cursource; |
699 | while (s && s->fd == -1) |
700 | s = s->next; |
701 | if (s == NULL((void*)0)) |
| |
702 | s = cursource; |
| 2 | | Null pointer value stored to 's' | |
|
703 | |
704 | tp->type = STRING; |
705 | if (tp->wslen) |
| |
706 | { |
707 | *outptr++ = ' '; |
708 | tp->wslen = 1; |
709 | } |
710 | op = outptr; |
711 | *op++ = '"'; |
712 | switch (biname) |
| 4 | | Control jumps to 'case KFILE:' at line 720 | |
|
713 | { |
714 | |
715 | case KLINENO: |
716 | tp->type = NUMBER; |
717 | op = outnum(op - 1, s->line); |
718 | break; |
719 | |
720 | case KFILE: |
721 | { |
722 | char *src = s->filename; |
| 5 | | Access to field 'filename' results in a dereference of a null pointer (loaded from variable 's') |
|
723 | |
724 | while ((*op++ = *src++) != 0) |
725 | if (src[-1] == '\\') |
726 | *op++ = '\\'; |
727 | op--; |
728 | break; |
729 | } |
730 | |
731 | case KDATE: |
732 | strncpy(op, curtime + 4, 7); |
733 | strncpy(op + 7, curtime + 20, 4); |
734 | op += 11; |
735 | break; |
736 | |
737 | case KTIME: |
738 | strncpy(op, curtime + 11, 8); |
739 | op += 8; |
740 | break; |
741 | |
742 | default: |
743 | error(ERROR, "cpp botch: unknown internal macro"); |
744 | return; |
745 | } |
746 | if (tp->type == STRING) |
747 | *op++ = '"'; |
748 | tp->t = (uchar *) outptr; |
749 | tp->len = op - outptr; |
750 | outptr = op; |
751 | } |
752 | |
753 | |