xref: /AOO41X/main/soltools/cpp/_macro.c (revision 7ce203730a656307c389f82ee60505af35570552)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 #ifdef _MSC_VER
23 #   define _POSIX_
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #ifdef __hpux
29 #   define _HPUX_SOURCE
30 #endif
31 #if defined(__IBMC__) || defined(__EMX__)
32 #   define PATH_MAX _MAX_PATH
33 #endif
34 #include <limits.h>
35 
36 #include "cpp.h"
37 
38 #define NCONCAT 16384
39 
40 /*
41  * do a macro definition.  tp points to the name being defined in the line
42  */
43 void
dodefine(Tokenrow * trp)44     dodefine(Tokenrow * trp)
45 {
46     Token *tp;
47     Nlist *np;
48     Source *s;
49     Tokenrow *def, *args;
50     static uchar location[(PATH_MAX + 8) * NINC], *cp;
51 
52     tp = trp->tp + 1;
53     if (tp >= trp->lp || tp->type != NAME)
54     {
55         error(ERROR, "#defined token is not a name");
56         return;
57     }
58     np = lookup(tp, 1);
59     if (np->flag & ISUNCHANGE)
60     {
61         error(ERROR, "#defined token %t can't be redefined", tp);
62         return;
63     }
64     /* collect arguments */
65     tp += 1;
66     args = NULL;
67     if (tp < trp->lp && tp->type == LP && tp->wslen == 0)
68     {
69         /* macro with args */
70         int narg = 0;
71 
72         tp += 1;
73         args = new(Tokenrow);
74         maketokenrow(2, args);
75         if (tp->type != RP)
76         {
77             int err = 0;
78 
79             for (;;)
80             {
81                 Token *atp;
82 
83                 if (tp->type != NAME)
84                 {
85                     err++;
86                     break;
87                 }
88                 if (narg >= args->max)
89                     growtokenrow(args);
90                 for (atp = args->bp; atp < args->lp; atp++)
91                     if (atp->len == tp->len
92                         && strncmp((char *) atp->t, (char *) tp->t, tp->len) == 0)
93                         error(ERROR, "Duplicate macro argument");
94                 *args->lp++ = *tp;
95                 narg++;
96                 tp += 1;
97                 if (tp->type == RP)
98                     break;
99                 if (tp->type != COMMA)
100                 {
101                     err++;
102                     break;
103                 }
104                 tp += 1;
105             }
106             if (err)
107             {
108                 error(ERROR, "Syntax error in macro parameters");
109                 return;
110             }
111         }
112         tp += 1;
113     }
114     trp->tp = tp;
115     if (((trp->lp) - 1)->type == NL)
116         trp->lp -= 1;
117     def = normtokenrow(trp);
118     if (np->flag & ISDEFINED)
119     {
120         if (comparetokens(def, np->vp)
121             || (np->ap == NULL) != (args == NULL)
122             || (np->ap && comparetokens(args, np->ap)))
123         {
124             if ( np->loc )
125                 error(ERROR,
126                     "Macro redefinition of %t (already defined at %s)",
127                     trp->bp + 2, np->loc);
128             else
129                 error(ERROR,
130                     "Macro redefinition of %t (already defined at %s)",
131                     trp->bp + 2, "commandline" );
132         }
133     }
134     if (args)
135     {
136         Tokenrow *tap;
137 
138         tap = normtokenrow(args);
139         dofree(args->bp);
140         args = tap;
141     }
142     np->ap = args;
143     np->vp = def;
144     np->flag |= ISDEFINED;
145 
146     /* build location string of macro definition */
147     for (cp = location, s = cursource; s; s = s->next)
148         if (*s->filename)
149         {
150             if (cp != location)
151                 *cp++ = ' ';
152             sprintf((char *)cp, "%s:%d", s->filename, s->line);
153             cp += strlen((char *)cp);
154         }
155 
156     np->loc = newstring(location, strlen((char *)location), 0);
157 
158     if (Mflag)
159     {
160         if (np->ap)
161             error(INFO, "Macro definition of %s(%r) [%r]", np->name, np->ap, np->vp);
162         else
163             error(INFO, "Macro definition of %s [%r]", np->name, np->vp);
164     }
165 }
166 
167 /*
168  * Definition received via -D or -U
169  */
170 void
doadefine(Tokenrow * trp,int type)171     doadefine(Tokenrow * trp, int type)
172 {
173     Nlist *np;
174     static uchar onestr[2] = "1";
175     static Token onetoken[1] = {{NUMBER, 0, 0, 1, onestr, 0}};
176     static Tokenrow onetr = {onetoken, onetoken, onetoken + 1, 1};
177 
178     trp->tp = trp->bp;
179     if (type == 'U')
180     {
181         if (trp->lp - trp->tp != 2 || trp->tp->type != NAME)
182             goto syntax;
183         if ((np = lookup(trp->tp, 0)) == NULL)
184             return;
185         np->flag &= ~ISDEFINED;
186         return;
187     }
188 
189     if (type == 'A')
190     {
191         if (trp->tp >= trp->lp || trp->tp->type != NAME)
192             goto syntax;
193         trp->tp->type = ARCHITECTURE;
194         np = lookup(trp->tp, 1);
195         np->flag |= ISARCHITECTURE;
196         trp->tp += 1;
197         if (trp->tp >= trp->lp || trp->tp->type == END)
198         {
199             np->vp = &onetr;
200             return;
201         }
202         else
203             error(FATAL, "Illegal -A argument %r", trp);
204     }
205 
206     if (trp->tp >= trp->lp || trp->tp->type != NAME)
207         goto syntax;
208     np = lookup(trp->tp, 1);
209     np->flag |= ISDEFINED;
210     trp->tp += 1;
211     if (trp->tp >= trp->lp || trp->tp->type == END)
212     {
213         np->vp = &onetr;
214         return;
215     }
216     if (trp->tp->type != ASGN)
217         goto syntax;
218     trp->tp += 1;
219     if ((trp->lp - 1)->type == END)
220         trp->lp -= 1;
221     np->vp = normtokenrow(trp);
222     return;
223 syntax:
224     error(FATAL, "Illegal -D or -U argument %r", trp);
225 }
226 
227 
228 
229 /*
230  * Do macro expansion in a row of tokens.
231  * Flag is NULL if more input can be gathered.
232  */
233 void
expandrow(Tokenrow * trp,char * flag)234     expandrow(Tokenrow * trp, char *flag)
235 {
236     Token * tp;
237     Nlist * np;
238 
239     MacroValidatorList  validators;
240     mvl_init(&validators);
241     /* Sets all token-identifiers to 0 because tokens may not be initialised (never use C!) */
242     tokenrow_zeroTokenIdentifiers(trp);
243 
244     if (flag)
245         setsource(flag, -1, -1, "", 0);
246     for (tp = trp->tp; tp < trp->lp;)
247     {
248         mvl_check(&validators, tp);
249 
250         if (tp->type != NAME
251             || quicklook(tp->t[0], tp->len > 1 ? tp->t[1] : 0) == 0
252             || (np = lookup(tp, 0)) == NULL
253             || (np->flag & (ISDEFINED | ISMAC)) == 0
254             || (np->flag & ISACTIVE) != 0)
255         {
256             tp++;
257             continue;
258         }
259         trp->tp = tp;
260         if (np->val == KDEFINED)
261         {
262             tp->type = DEFINED;
263             if ((tp + 1) < trp->lp && (tp + 1)->type == NAME)
264                 (tp + 1)->type = NAME1;
265             else
266                 if ((tp + 3) < trp->lp && (tp + 1)->type == LP
267                     && (tp + 2)->type == NAME && (tp + 3)->type == RP)
268                     (tp + 2)->type = NAME1;
269                 else
270                     error(ERROR, "Incorrect syntax for `defined'");
271             tp++;
272             continue;
273         }
274         else
275             if (np->val == KMACHINE)
276             {
277                 if (((tp - 1) >= trp->bp) && ((tp - 1)->type == SHARP))
278                 {
279                     tp->type = ARCHITECTURE;
280                     if ((tp + 1) < trp->lp && (tp + 1)->type == NAME)
281                         (tp + 1)->type = NAME2;
282                     else
283                         if ((tp + 3) < trp->lp && (tp + 1)->type == LP
284                             && (tp + 2)->type == NAME && (tp + 3)->type == RP)
285                             (tp + 2)->type = NAME2;
286                         else
287                             error(ERROR, "Incorrect syntax for `#machine'");
288                 }
289                 tp++;
290                 continue;
291             }
292 
293         if (np->flag & ISMAC)
294             builtin(trp, np->val);
295         else
296             expand(trp, np, &validators);
297         tp = trp->tp;
298     }   // end for
299     if (flag)
300         unsetsource();
301 
302     mvl_destruct(&validators);
303 }
304 
305 /*
306  * Expand the macro whose name is np, at token trp->tp, in the tokenrow.
307  * Return trp->tp at the first token next to be expanded
308  * (ordinarily the beginning of the expansion)
309  * I.e.: the same position as before!
310  * Only one expansion is performed, then we return to the expandrow()
311  * loop and start at same position.
312  */
313 void
expand(Tokenrow * trp,Nlist * np,MacroValidatorList * pValidators)314     expand(Tokenrow * trp, Nlist * np, MacroValidatorList * pValidators)
315 {
316 //  Token * pOldNextTp;
317     Tokenrow ntr;
318     int ntokc, narg, i;
319     Tokenrow *atr[NARG + 1];
320 
321     if (Mflag == 2)
322     {
323         if (np->ap)
324             error(INFO, "Macro expansion of %t with %s(%r)", trp->tp, np->name, np->ap);
325         else
326             error(INFO, "Macro expansion of %t with %s", trp->tp, np->name);
327     }
328 
329     copytokenrow(&ntr, np->vp);         /* copy macro value */
330     if (np->ap == NULL)                 /* parameterless */
331         ntokc = 1;
332     else
333     {
334         ntokc = gatherargs(trp, atr, &narg);
335         if (narg < 0)
336         {                               /* not actually a call (no '(') */
337             trp->tp++;
338             return;
339         }
340         if (narg != rowlen(np->ap))
341         {
342             error(ERROR, "Disagreement in number of macro arguments");
343             trp->tp += ntokc;
344             return;
345         }
346 
347         /** If gatherargs passed a macro validating token, this token
348             must become valid here.
349             trp->tp+0 was checked in expandrow(), so we dont need to do it
350             again here:
351         */
352         for (i = 1; i < ntokc; i++)
353         {
354             mvl_check(pValidators,trp->tp+i);
355         }
356 
357         substargs(np, &ntr, atr);       /* put args into replacement */
358         for (i = 0; i < narg; i++)
359         {
360             dofree(atr[i]->bp);
361             dofree(atr[i]);
362         }
363     }
364 
365 /* old
366     np->flag |= ISACTIVE;
367 */
368 
369 /* rh
370 */
371     doconcat(&ntr);                     /* execute ## operators */
372     ntr.tp = ntr.bp;
373     makespace(&ntr, trp->tp);
374 
375 /* old
376 //  expandrow(&ntr, "<expand>");
377 //  insertrow(trp, ntokc, &ntr);
378 //  dofree(ntr.bp);
379 //  np->flag &= ~ISACTIVE;
380 */
381 
382 /* NP
383         // Replace macro by its value:
384 */
385 //  pOldNextTp = trp->tp+ntokc;
386     tokenrow_zeroTokenIdentifiers(&ntr);
387     insertrow(trp, ntokc, &ntr);
388         /* Reassign old macro validators:
389         */
390 //  mvl_move(pValidators, trp->tp - pOldNextTp);
391 
392         /* add validator for just invalidated macro:
393         */
394     np->flag |= ISACTIVE;
395     if (trp->tp != trp->lp)
396     {   /* tp is a valid pointer: */
397         mvl_add(pValidators,np,trp->tp);
398     }
399     else
400     {   /* tp is == lp, therefore does not point to valid memory: */
401         mvl_add(pValidators,np,0);
402     }
403         /* reset trp->tp to original position:
404         */
405     trp->tp -= ntr.lp - ntr.bp;         /* so the result will be tested for macros from the same position again */
406 
407     dofree(ntr.bp);
408 
409     return;
410 }
411 
412 /*
413  * Gather an arglist, starting in trp with tp pointing at the macro name.
414  * Return total number of tokens passed, stash number of args found.
415  * trp->tp is not changed relative to the tokenrow.
416  */
417 int
gatherargs(Tokenrow * trp,Tokenrow ** atr,int * narg)418     gatherargs(Tokenrow * trp, Tokenrow ** atr, int *narg)
419 {
420     int parens = 1;
421     int ntok = 0;
422     Token *bp, *lp;
423     Tokenrow ttr;
424     int ntokp;
425     int needspace;
426 
427     *narg = -1;                         /* means that there is no macro
428                                          * call */
429     /* look for the ( */
430     for (;;)
431     {
432         trp->tp++;
433         ntok++;
434         if (trp->tp >= trp->lp)
435         {
436             gettokens(trp, 0);
437             if ((trp->lp - 1)->type == END)
438             {
439                 trp->lp -= 1;
440                 trp->tp -= ntok;
441                 return ntok;
442             }
443         }
444         if (trp->tp->type == LP)
445             break;
446         if (trp->tp->type != NL)
447             return ntok;
448     }
449     *narg = 0;
450     ntok++;
451     ntokp = ntok;
452     trp->tp++;
453     /* search for the terminating ), possibly extending the row */
454     needspace = 0;
455     while (parens > 0)
456     {
457         if (trp->tp >= trp->lp)
458             gettokens(trp, 0);
459         if (needspace)
460         {
461             needspace = 0;
462             /* makespace(trp); [rh] */
463         }
464         if (trp->tp->type == END)
465         {
466             trp->lp -= 1;
467             trp->tp -= ntok;
468             error(ERROR, "EOF in macro arglist");
469             return ntok;
470         }
471         if (trp->tp->type == NL)
472         {
473             trp->tp += 1;
474             adjustrow(trp, -1);
475             trp->tp -= 1;
476             /* makespace(trp); [rh] */
477             needspace = 1;
478             continue;
479         }
480         if (trp->tp->type == LP)
481             parens++;
482         else
483             if (trp->tp->type == RP)
484                 parens--;
485         trp->tp++;
486         ntok++;
487     }
488     trp->tp -= ntok;
489     /* Now trp->tp won't move underneath us */
490     lp = bp = trp->tp + ntokp;
491     for (; parens >= 0; lp++)
492     {
493         if (lp->type == LP)
494         {
495             parens++;
496             continue;
497         }
498         if (lp->type == RP)
499             parens--;
500         if (lp->type == DSHARP)
501             lp->type = DSHARP1;         /* ## not special in arg */
502         if ((lp->type == COMMA && parens == 0) ||
503                 ( parens < 0 && ((lp - 1)->type != LP)))
504         {
505             if (*narg >= NARG - 1)
506                 error(FATAL, "Sorry, too many macro arguments");
507             ttr.bp = ttr.tp = bp;
508             ttr.lp = lp;
509             atr[(*narg)++] = normtokenrow(&ttr);
510             bp = lp + 1;
511         }
512     }
513     return ntok;
514 }
515 
516 /*
517  * substitute the argument list into the replacement string
518  *  This would be simple except for ## and #
519  */
520 void
substargs(Nlist * np,Tokenrow * rtr,Tokenrow ** atr)521     substargs(Nlist * np, Tokenrow * rtr, Tokenrow ** atr)
522 {
523     Tokenrow tatr;
524     Token *tp;
525     int ntok, argno;
526 
527     for (rtr->tp = rtr->bp; rtr->tp < rtr->lp;)
528     {
529         if (rtr->tp->type == SHARP)
530         {                               /* string operator */
531             tp = rtr->tp;
532             rtr->tp += 1;
533             if ((argno = lookuparg(np, rtr->tp)) < 0)
534             {
535                 error(ERROR, "# not followed by macro parameter");
536                 continue;
537             }
538             ntok = 1 + (rtr->tp - tp);
539             rtr->tp = tp;
540             insertrow(rtr, ntok, stringify(atr[argno]));
541             continue;
542         }
543         if (rtr->tp->type == NAME
544             && (argno = lookuparg(np, rtr->tp)) >= 0)
545         {
546             if (((rtr->tp + 1) < rtr->lp && (rtr->tp + 1)->type == DSHARP)
547                 || (rtr->tp != rtr->bp  && (rtr->tp - 1)->type == DSHARP))
548             {
549                 copytokenrow(&tatr, atr[argno]);
550                 makespace(&tatr, rtr->tp);
551                 insertrow(rtr, 1, &tatr);
552                 dofree(tatr.bp);
553             }
554             else
555             {
556                 copytokenrow(&tatr, atr[argno]);
557                 makespace(&tatr, rtr->tp);
558                 expandrow(&tatr, "<macro>");
559                 insertrow(rtr, 1, &tatr);
560                 dofree(tatr.bp);
561             }
562             continue;
563         }
564         rtr->tp++;
565     }
566 }
567 
568 /*
569  * Evaluate the ## operators in a tokenrow
570  */
571 void
doconcat(Tokenrow * trp)572     doconcat(Tokenrow * trp)
573 {
574     Token *ltp, *ntp;
575     Tokenrow ntr;
576     int len;
577 
578     for (trp->tp = trp->bp; trp->tp < trp->lp; trp->tp++)
579     {
580         if (trp->tp->type == DSHARP1)
581             trp->tp->type = DSHARP;
582         else
583             if (trp->tp->type == DSHARP)
584             {
585                 int  i;
586                 char tt[NCONCAT];
587 
588                 ltp = trp->tp - 1;
589                 ntp = trp->tp + 1;
590 
591                 if (ltp < trp->bp || ntp >= trp->lp)
592                 {
593                     error(ERROR, "## occurs at border of replacement");
594                     continue;
595                 }
596 
597                 ntp = ltp;
598                 i   = 1;
599                 len = 0;
600 
601                 do
602                 {
603                     if (len + ntp->len + ntp->wslen > sizeof(tt))
604                     {
605                         error(ERROR, "## string concatination buffer overrun");
606                         break;
607                     }
608 
609                     if (ntp != trp->tp + 1)
610                     {
611                         strncpy((char *) tt + len, (char *) ntp->t - ntp->wslen,
612                                 ntp->len + ntp->wslen);
613                         len += ntp->len + ntp->wslen;
614                     }
615                     else    // Leerzeichen um ## herum entfernen:
616                     {
617                         strncpy((char *) tt + len, (char *) ntp->t, ntp->len);
618                         len += ntp->len;
619                     }
620 
621                     ntp = trp->tp + i;
622                     i++;
623                 }
624                 while (ntp < trp->lp);
625 
626                 tt[len] = '\0';
627                 setsource("<##>", -1, -1, tt, 0);
628                 maketokenrow(3, &ntr);
629                 gettokens(&ntr, 1);
630                 unsetsource();
631                 if (ntr.bp->type == UNCLASS)
632                     error(WARNING, "Bad token %r produced by ##", &ntr);
633                 while ((ntr.lp-1)->len == 0 && ntr.lp != ntr.bp)
634                     ntr.lp--;
635 
636                 doconcat(&ntr);
637                 trp->tp = ltp;
638                 makespace(&ntr, ltp);
639                 insertrow(trp, ntp - ltp, &ntr);
640                 dofree(ntr.bp);
641                 trp->tp--;
642             }
643     }
644 }
645 
646 /*
647  * tp is a potential parameter name of macro mac;
648  * look it up in mac's arglist, and if found, return the
649  * corresponding index in the argname array.  Return -1 if not found.
650  */
651 int
lookuparg(Nlist * mac,Token * tp)652     lookuparg(Nlist * mac, Token * tp)
653 {
654     Token *ap;
655 
656     if (tp->type != NAME || mac->ap == NULL)
657         return -1;
658     for (ap = mac->ap->bp; ap < mac->ap->lp; ap++)
659     {
660         if (ap->len == tp->len && strncmp((char *) ap->t, (char *) tp->t, ap->len) == 0)
661             return ap - mac->ap->bp;
662     }
663     return -1;
664 }
665 
666 /*
667  * Return a quoted version of the tokenrow (from # arg)
668  */
669 #define STRLEN  512
670 Tokenrow *
stringify(Tokenrow * vp)671     stringify(Tokenrow * vp)
672 {
673     static Token t = {STRING, 0, 0, 0, NULL, 0};
674     static Tokenrow tr = {&t, &t, &t + 1, 1};
675     Token *tp;
676     uchar s[STRLEN];
677     uchar *sp = s, *cp;
678     int i, instring;
679 
680     *sp++ = '"';
681     for (tp = vp->bp; tp < vp->lp; tp++)
682     {
683         instring = tp->type == STRING || tp->type == CCON;
684         if (sp + 2 * tp->len + tp->wslen  >= &s[STRLEN - 10])
685         {
686             error(ERROR, "Stringified macro arg is too long");
687             break;
688         }
689 
690         // Change by np 31.10.2001, #93725 - begin
691         if ( tp->wslen > 0 )
692         *sp++ = ' ';
693         // change end.
694 
695         for (i = 0, cp = tp->t; (unsigned int)i < tp->len; i++)
696         {
697             if (instring && (*cp == '"' || *cp == '\\'))
698                 *sp++ = '\\';
699             *sp++ = *cp++;
700         }
701     }
702     *sp++ = '"';
703     *sp = '\0';
704     sp = s;
705     t.len = strlen((char *) sp);
706     t.t = newstring(sp, t.len, 0);
707     return &tr;
708 }
709 
710 /*
711  * expand a builtin name
712  */
713 void
builtin(Tokenrow * trp,int biname)714     builtin(Tokenrow * trp, int biname)
715 {
716     char *op;
717     Token *tp;
718     Source *s;
719 
720     tp = trp->tp;
721     trp->tp++;
722     /* need to find the real source */
723     s = cursource;
724     while (s && s->fd == -1)
725         s = s->next;
726     if (s == NULL)
727         s = cursource;
728     /* most are strings */
729     tp->type = STRING;
730     if (tp->wslen)
731     {
732         *outptr++ = ' ';
733         tp->wslen = 1;
734     }
735     op = outptr;
736     *op++ = '"';
737     switch (biname)
738     {
739 
740         case KLINENO:
741             tp->type = NUMBER;
742             op = outnum(op - 1, s->line);
743             break;
744 
745         case KFILE:
746             {
747                 char *src = s->filename;
748 
749                 while ((*op++ = *src++) != 0)
750                     if (src[-1] == '\\')
751                         *op++ = '\\';
752                 op--;
753                 break;
754             }
755 
756         case KDATE:
757             strncpy(op, curtime + 4, 7);
758             strncpy(op + 7, curtime + 20, 4);
759             op += 11;
760             break;
761 
762         case KTIME:
763             strncpy(op, curtime + 11, 8);
764             op += 8;
765             break;
766 
767         default:
768             error(ERROR, "cpp botch: unknown internal macro");
769             return;
770     }
771     if (tp->type == STRING)
772         *op++ = '"';
773     tp->t = (uchar *) outptr;
774     tp->len = op - outptr;
775     outptr = op;
776 }
777 
778