update dev300-m58
[ooovba.git] / idlc / source / preproc / macro.c
blob4a157bb45466e978320f628d9011a6ebf127fd7d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: macro.c,v $
10 * $Revision: 1.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 #ifdef _MSC_VER
31 # define _POSIX_
32 #endif
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
37 #ifdef __hpux
38 # define _HPUX_SOURCE
39 #endif
40 #ifdef SCO
41 # define _IBCS2
42 #endif
43 #include <limits.h>
45 #include "cpp.h"
47 #define NCONCAT 16384
50 * do a macro definition. tp points to the name being defined in the line
52 void
53 dodefine(Tokenrow * trp)
55 Token *tp;
56 Nlist *np;
57 Source *s;
58 Tokenrow *def, *args;
59 #ifdef OS2
60 static uchar location[(_MAX_PATH + 8) * NINC], *cp;
61 #else
62 static uchar location[(PATH_MAX + 8) * NINC], *cp;
63 #endif
64 tp = trp->tp + 1;
65 if (tp >= trp->lp || tp->type != NAME)
67 error(ERROR, "#defined token is not a name");
68 return;
70 np = lookup(tp, 1);
71 if (np->flag & ISUNCHANGE)
73 error(ERROR, "#defined token %t can't be redefined", tp);
74 return;
76 /* collect arguments */
77 tp += 1;
78 args = NULL;
79 if (tp < trp->lp && tp->type == LP && tp->wslen == 0)
81 /* macro with args */
82 int narg = 0;
84 tp += 1;
85 args = new(Tokenrow);
86 maketokenrow(2, args);
87 if (tp->type != RP)
89 int err = 0;
91 for (;;)
93 Token *atp;
95 if (tp->type != NAME)
97 err++;
98 break;
100 if (narg >= args->max)
101 growtokenrow(args);
102 for (atp = args->bp; atp < args->lp; atp++)
103 if (atp->len == tp->len
104 && strncmp((char *) atp->t, (char *) tp->t, tp->len) == 0)
105 error(ERROR, "Duplicate macro argument");
106 *args->lp++ = *tp;
107 narg++;
108 tp += 1;
109 if (tp->type == RP)
110 break;
111 if (tp->type != COMMA)
113 err++;
114 break;
116 tp += 1;
118 if (err)
120 error(ERROR, "Syntax error in macro parameters");
121 return;
124 tp += 1;
126 trp->tp = tp;
127 if (((trp->lp) - 1)->type == NL)
128 trp->lp -= 1;
129 def = normtokenrow(trp);
130 if (np->flag & ISDEFINED)
132 if (comparetokens(def, np->vp)
133 || (np->ap == NULL) != (args == NULL)
134 || (np->ap && comparetokens(args, np->ap)))
135 error(ERROR, "Macro redefinition of %t (already defined at %s)", trp->bp + 2, np->loc);
137 if (args)
139 Tokenrow *tap;
141 tap = normtokenrow(args);
142 dofree(args->bp);
143 args = tap;
145 np->ap = args;
146 np->vp = def;
147 np->flag |= ISDEFINED;
149 /* build location string of macro definition */
150 for (cp = location, s = cursource; s; s = s->next)
151 if (*s->filename)
153 if (cp != location)
154 *cp++ = ' ';
155 sprintf((char *)cp, "%s:%d", s->filename, s->line);
156 cp += strlen((char *)cp);
159 np->loc = newstring(location, strlen((char *)location), 0);
161 if (Mflag)
163 if (np->ap)
164 error(INFO, "Macro definition of %s(%r) [%r]", np->name, np->ap, np->vp);
165 else
166 error(INFO, "Macro definition of %s [%r]", np->name, np->vp);
171 * Definition received via -D or -U
173 void
174 doadefine(Tokenrow * trp, int type)
176 Nlist *np;
177 static uchar onestr[2] = "1";
178 static Token onetoken[1] = {{NUMBER, 0, 0, 1, onestr}};
179 static Tokenrow onetr = {onetoken, onetoken, onetoken + 1, 1};
181 trp->tp = trp->bp;
182 if (type == 'U')
184 if (trp->lp - trp->tp != 2 || trp->tp->type != NAME)
185 goto syntax;
186 if ((np = lookup(trp->tp, 0)) == NULL)
187 return;
188 np->flag &= ~ISDEFINED;
189 return;
192 if (type == 'A')
194 if (trp->tp >= trp->lp || trp->tp->type != NAME)
195 goto syntax;
196 trp->tp->type = ARCHITECTURE;
197 np = lookup(trp->tp, 1);
198 np->flag |= ISARCHITECTURE;
199 trp->tp += 1;
200 if (trp->tp >= trp->lp || trp->tp->type == END)
202 np->vp = &onetr;
203 return;
205 else
206 error(FATAL, "Illegal -A argument %r", trp);
209 if (trp->tp >= trp->lp || trp->tp->type != NAME)
210 goto syntax;
211 np = lookup(trp->tp, 1);
212 np->flag |= ISDEFINED;
213 trp->tp += 1;
214 if (trp->tp >= trp->lp || trp->tp->type == END)
216 np->vp = &onetr;
217 return;
219 if (trp->tp->type != ASGN)
220 goto syntax;
221 trp->tp += 1;
222 if ((trp->lp - 1)->type == END)
223 trp->lp -= 1;
224 np->vp = normtokenrow(trp);
225 return;
226 syntax:
227 error(FATAL, "Illegal -D or -U argument %r", trp);
231 * Do macro expansion in a row of tokens.
232 * Flag is NULL if more input can be gathered.
234 void
235 expandrow(Tokenrow * trp, char *flag)
237 Token *tp;
238 Nlist *np;
240 if (flag)
241 setsource(flag, -1, -1, "", 0);
242 for (tp = trp->tp; tp < trp->lp;)
244 if (tp->type != NAME
245 || quicklook(tp->t[0], tp->len > 1 ? tp->t[1] : 0) == 0
246 || (np = lookup(tp, 0)) == NULL
247 || (np->flag & (ISDEFINED | ISMAC)) == 0
248 || (np->flag & ISACTIVE) != 0)
250 tp++;
251 continue;
253 trp->tp = tp;
254 if (np->val == KDEFINED)
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;
268 else
269 if (np->val == KMACHINE)
271 if (((tp - 1) >= trp->bp) && ((tp - 1)->type == SHARP))
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'");
283 tp++;
284 continue;
287 if (np->flag & ISMAC)
288 builtin(trp, np->val);
289 else
290 expand(trp, np);
291 tp = trp->tp;
293 if (flag)
294 unsetsource();
298 * Expand the macro whose name is np, at token trp->tp, in the tokenrow.
299 * Return trp->tp at the first token next to be expanded
300 * (ordinarily the beginning of the expansion)
302 void
303 expand(Tokenrow * trp, Nlist * np)
305 Tokenrow ntr;
306 int ntokc, narg, i;
307 Tokenrow *atr[NARG + 1];
309 if (Mflag == 2)
311 if (np->ap)
312 error(INFO, "Macro expansion of %t with %s(%r)", trp->tp, np->name, np->ap);
313 else
314 error(INFO, "Macro expansion of %t with %s", trp->tp, np->name);
317 copytokenrow(&ntr, np->vp); /* copy macro value */
318 if (np->ap == NULL) /* parameterless */
319 ntokc = 1;
320 else
322 ntokc = gatherargs(trp, atr, &narg);
323 if (narg < 0)
324 { /* not actually a call (no '(') */
325 trp->tp++;
326 return;
328 if (narg != rowlen(np->ap))
330 error(ERROR, "Disagreement in number of macro arguments");
331 trp->tp += ntokc;
332 return;
334 substargs(np, &ntr, atr); /* put args into replacement */
335 for (i = 0; i < narg; i++)
337 dofree(atr[i]->bp);
338 dofree(atr[i]);
342 np->flag |= ISACTIVE;
344 doconcat(&ntr); /* execute ## operators */
345 ntr.tp = ntr.bp;
346 makespace(&ntr, trp->tp);
347 expandrow(&ntr, "<expand>");
348 insertrow(trp, ntokc, &ntr);
349 dofree(ntr.bp);
351 np->flag &= ~ISACTIVE;
353 return;
357 * Gather an arglist, starting in trp with tp pointing at the macro name.
358 * Return total number of tokens passed, stash number of args found.
359 * trp->tp is not changed relative to the tokenrow.
362 gatherargs(Tokenrow * trp, Tokenrow ** atr, int *narg)
364 int parens = 1;
365 int ntok = 0;
366 Token *bp, *lp;
367 Tokenrow ttr;
368 int ntokp;
369 int needspace;
371 *narg = -1; /* means that there is no macro
372 * call */
373 /* look for the ( */
374 for (;;)
376 trp->tp++;
377 ntok++;
378 if (trp->tp >= trp->lp)
380 gettokens(trp, 0);
381 if ((trp->lp - 1)->type == END)
383 trp->lp -= 1;
384 trp->tp -= ntok;
385 return ntok;
388 if (trp->tp->type == LP)
389 break;
390 if (trp->tp->type != NL)
391 return ntok;
393 *narg = 0;
394 ntok++;
395 ntokp = ntok;
396 trp->tp++;
397 /* search for the terminating ), possibly extending the row */
398 needspace = 0;
399 while (parens > 0)
401 if (trp->tp >= trp->lp)
402 gettokens(trp, 0);
403 if (needspace)
405 needspace = 0;
406 /* makespace(trp); [rh] */
408 if (trp->tp->type == END)
410 trp->lp -= 1;
411 trp->tp -= ntok;
412 error(ERROR, "EOF in macro arglist");
413 return ntok;
415 if (trp->tp->type == NL)
417 trp->tp += 1;
418 adjustrow(trp, -1);
419 trp->tp -= 1;
420 /* makespace(trp); [rh] */
421 needspace = 1;
422 continue;
424 if (trp->tp->type == LP)
425 parens++;
426 else
427 if (trp->tp->type == RP)
428 parens--;
429 trp->tp++;
430 ntok++;
432 trp->tp -= ntok;
433 /* Now trp->tp won't move underneath us */
434 lp = bp = trp->tp + ntokp;
435 for (; parens >= 0; lp++)
437 if (lp->type == LP)
439 parens++;
440 continue;
442 if (lp->type == RP)
443 parens--;
444 if (lp->type == DSHARP)
445 lp->type = DSHARP1; /* ## not special in arg */
446 if ((lp->type == COMMA && parens == 0)
447 || (parens < 0 && (lp - 1)->type != LP))
449 if (*narg >= NARG - 1)
450 error(FATAL, "Sorry, too many macro arguments");
451 ttr.bp = ttr.tp = bp;
452 ttr.lp = lp;
453 atr[(*narg)++] = normtokenrow(&ttr);
454 bp = lp + 1;
457 return ntok;
461 * substitute the argument list into the replacement string
462 * This would be simple except for ## and #
464 void
465 substargs(Nlist * np, Tokenrow * rtr, Tokenrow ** atr)
467 Tokenrow tatr;
468 Token *tp;
469 int ntok, argno;
471 for (rtr->tp = rtr->bp; rtr->tp < rtr->lp;)
473 if (rtr->tp->type == SHARP)
474 { /* string operator */
475 tp = rtr->tp;
476 rtr->tp += 1;
477 if ((argno = lookuparg(np, rtr->tp)) < 0)
479 error(ERROR, "# not followed by macro parameter");
480 continue;
482 ntok = 1 + (rtr->tp - tp);
483 rtr->tp = tp;
484 insertrow(rtr, ntok, stringify(atr[argno]));
485 continue;
487 if (rtr->tp->type == NAME
488 && (argno = lookuparg(np, rtr->tp)) >= 0)
490 if (((rtr->tp + 1) < rtr->lp && (rtr->tp + 1)->type == DSHARP)
491 || (rtr->tp != rtr->bp && (rtr->tp - 1)->type == DSHARP))
493 copytokenrow(&tatr, atr[argno]);
494 makespace(&tatr, rtr->tp);
495 insertrow(rtr, 1, &tatr);
496 dofree(tatr.bp);
498 else
500 copytokenrow(&tatr, atr[argno]);
501 makespace(&tatr, rtr->tp);
502 expandrow(&tatr, "<macro>");
503 insertrow(rtr, 1, &tatr);
504 dofree(tatr.bp);
506 continue;
508 rtr->tp++;
513 * Evaluate the ## operators in a tokenrow
515 void
516 doconcat(Tokenrow * trp)
518 Token *ltp, *ntp;
519 Tokenrow ntr;
520 int len;
522 for (trp->tp = trp->bp; trp->tp < trp->lp; trp->tp++)
524 if (trp->tp->type == DSHARP1)
525 trp->tp->type = DSHARP;
526 else
527 if (trp->tp->type == DSHARP)
529 int i;
530 char tt[NCONCAT];
532 ltp = trp->tp - 1;
533 ntp = trp->tp + 1;
535 if (ltp < trp->bp || ntp >= trp->lp)
537 error(ERROR, "## occurs at border of replacement");
538 continue;
541 ntp = ltp;
542 i = 1;
543 len = 0;
547 if (len + ntp->len + ntp->wslen > sizeof(tt))
549 error(ERROR, "## string concatination buffer overrun");
550 break;
553 strncpy((char *) tt + len, (char *) ntp->t - ntp->wslen,
554 ntp->len + ntp->wslen);
555 len += ntp->len + ntp->wslen;
557 ntp = trp->tp + i;
558 i++;
560 while (ntp < trp->lp);
562 tt[len] = '\0';
563 setsource("<##>", -1, -1, tt, 0);
564 maketokenrow(3, &ntr);
565 gettokens(&ntr, 1);
566 unsetsource();
567 if (ntr.bp->type == UNCLASS)
568 error(WARNING, "Bad token %r produced by ##", &ntr);
569 doconcat(&ntr);
570 trp->tp = ltp;
571 makespace(&ntr, ltp);
572 insertrow(trp, ntp - ltp, &ntr);
573 dofree(ntr.bp);
574 trp->tp--;
580 * tp is a potential parameter name of macro mac;
581 * look it up in mac's arglist, and if found, return the
582 * corresponding index in the argname array. Return -1 if not found.
585 lookuparg(Nlist * mac, Token * tp)
587 Token *ap;
589 if (tp->type != NAME || mac->ap == NULL)
590 return -1;
591 for (ap = mac->ap->bp; ap < mac->ap->lp; ap++)
593 if (ap->len == tp->len && strncmp((char *) ap->t, (char *) tp->t, ap->len) == 0)
594 return ap - mac->ap->bp;
596 return -1;
600 * Return a quoted version of the tokenrow (from # arg)
602 #define STRLEN 512
603 Tokenrow *
604 stringify(Tokenrow * vp)
606 static Token t = {STRING, 0, 0, 0, NULL};
607 static Tokenrow tr = {&t, &t, &t + 1, 1};
608 Token *tp;
609 uchar s[STRLEN];
610 uchar *sp = s, *cp;
611 int i, instring;
613 *sp++ = '"';
614 for (tp = vp->bp; tp < vp->lp; tp++)
616 instring = tp->type == STRING || tp->type == CCON;
617 if (sp + 2 * tp->len >= &s[STRLEN - 10])
619 error(ERROR, "Stringified macro arg is too long");
620 break;
622 for (i = 0, cp = tp->t; (unsigned int)i < tp->len; i++)
624 if (instring && (*cp == '"' || *cp == '\\'))
625 *sp++ = '\\';
626 *sp++ = *cp++;
629 *sp++ = '"';
630 *sp = '\0';
631 sp = s;
632 t.len = strlen((char *) sp);
633 t.t = newstring(sp, t.len, 0);
634 return &tr;
638 * expand a builtin name
640 void
641 builtin(Tokenrow * trp, int biname)
643 char *op;
644 Token *tp;
645 Source *s;
647 tp = trp->tp;
648 trp->tp++;
649 /* need to find the real source */
650 s = cursource;
651 while (s && s->fd == -1)
652 s = s->next;
653 if (s == NULL)
654 s = cursource;
655 /* most are strings */
656 tp->type = STRING;
657 if (tp->wslen)
659 *outptr++ = ' ';
660 tp->wslen = 1;
662 op = outptr;
663 *op++ = '"';
664 switch (biname)
667 case KLINENO:
668 tp->type = NUMBER;
669 op = outnum(op - 1, s->line);
670 break;
672 case KFILE:
674 char *src = s->filename;
676 while ((*op++ = *src++) != 0)
677 if (src[-1] == '\\')
678 *op++ = '\\';
679 op--;
680 break;
683 case KDATE:
684 strncpy(op, curtime + 4, 7);
685 strncpy(op + 7, curtime + 20, 4);
686 op += 11;
687 break;
689 case KTIME:
690 strncpy(op, curtime + 11, 8);
691 op += 8;
692 break;
694 default:
695 error(ERROR, "cpp botch: unknown internal macro");
696 return;
698 if (tp->type == STRING)
699 *op++ = '"';
700 tp->t = (uchar *) outptr;
701 tp->len = op - outptr;
702 outptr = op;