/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ #ifdef _MSC_VER # define _POSIX_ #endif #include #include #include #ifdef __hpux # define _HPUX_SOURCE #endif #ifdef SCO # define _IBCS2 #endif #include #include "cpp.h" #define NCONCAT 16384 /* * do a macro definition. tp points to the name being defined in the line */ void dodefine(Tokenrow * trp) { Token *tp; Nlist *np; Source *s; Tokenrow *def, *args; #ifdef OS2 static uchar location[(_MAX_PATH + 8) * NINC], *cp; #else static uchar location[(PATH_MAX + 8) * NINC], *cp; #endif tp = trp->tp + 1; if (tp >= trp->lp || tp->type != NAME) { error(ERROR, "#defined token is not a name"); return; } np = lookup(tp, 1); if (np->flag & ISUNCHANGE) { error(ERROR, "#defined token %t can't be redefined", tp); return; } /* collect arguments */ tp += 1; args = NULL; if (tp < trp->lp && tp->type == LP && tp->wslen == 0) { /* macro with args */ int narg = 0; tp += 1; args = new(Tokenrow); maketokenrow(2, args); if (tp->type != RP) { int err = 0; for (;;) { Token *atp; if (tp->type != NAME) { err++; break; } if (narg >= args->max) growtokenrow(args); for (atp = args->bp; atp < args->lp; atp++) if (atp->len == tp->len && strncmp((char *) atp->t, (char *) tp->t, tp->len) == 0) error(ERROR, "Duplicate macro argument"); *args->lp++ = *tp; narg++; tp += 1; if (tp->type == RP) break; if (tp->type != COMMA) { err++; break; } tp += 1; } if (err) { error(ERROR, "Syntax error in macro parameters"); return; } } tp += 1; } trp->tp = tp; if (((trp->lp) - 1)->type == NL) trp->lp -= 1; def = normtokenrow(trp); if (np->flag & ISDEFINED) { if (comparetokens(def, np->vp) || (np->ap == NULL) != (args == NULL) || (np->ap && comparetokens(args, np->ap))) error(ERROR, "Macro redefinition of %t (already defined at %s)", trp->bp + 2, np->loc); } if (args) { Tokenrow *tap; tap = normtokenrow(args); dofree(args->bp); args = tap; } np->ap = args; np->vp = def; np->flag |= ISDEFINED; /* build location string of macro definition */ for (cp = location, s = cursource; s; s = s->next) if (*s->filename) { if (cp != location) *cp++ = ' '; sprintf((char *)cp, "%s:%d", s->filename, s->line); cp += strlen((char *)cp); } np->loc = newstring(location, strlen((char *)location), 0); if (Mflag) { if (np->ap) error(INFO, "Macro definition of %s(%r) [%r]", np->name, np->ap, np->vp); else error(INFO, "Macro definition of %s [%r]", np->name, np->vp); } } /* * Definition received via -D or -U */ void doadefine(Tokenrow * trp, int type) { Nlist *np; static uchar onestr[2] = "1"; static Token onetoken[1] = {{NUMBER, 0, 0, 1, onestr}}; static Tokenrow onetr = {onetoken, onetoken, onetoken + 1, 1}; trp->tp = trp->bp; if (type == 'U') { if (trp->lp - trp->tp != 2 || trp->tp->type != NAME) goto syntax; if ((np = lookup(trp->tp, 0)) == NULL) return; np->flag &= ~ISDEFINED; return; } if (type == 'A') { if (trp->tp >= trp->lp || trp->tp->type != NAME) goto syntax; trp->tp->type = ARCHITECTURE; np = lookup(trp->tp, 1); np->flag |= ISARCHITECTURE; trp->tp += 1; if (trp->tp >= trp->lp || trp->tp->type == END) { np->vp = &onetr; return; } else error(FATAL, "Illegal -A argument %r", trp); } if (trp->tp >= trp->lp || trp->tp->type != NAME) goto syntax; np = lookup(trp->tp, 1); np->flag |= ISDEFINED; trp->tp += 1; if (trp->tp >= trp->lp || trp->tp->type == END) { np->vp = &onetr; return; } if (trp->tp->type != ASGN) goto syntax; trp->tp += 1; if ((trp->lp - 1)->type == END) trp->lp -= 1; np->vp = normtokenrow(trp); return; syntax: error(FATAL, "Illegal -D or -U argument %r", trp); } /* * Do macro expansion in a row of tokens. * Flag is NULL if more input can be gathered. */ void expandrow(Tokenrow * trp, char *flag) { Token *tp; Nlist *np; if (flag) setsource(flag, -1, -1, "", 0); for (tp = trp->tp; tp < trp->lp;) { if (tp->type != NAME || quicklook(tp->t[0], tp->len > 1 ? tp->t[1] : 0) == 0 || (np = lookup(tp, 0)) == NULL || (np->flag & (ISDEFINED | ISMAC)) == 0 || (np->flag & ISACTIVE) != 0) { tp++; continue; } trp->tp = tp; if (np->val == KDEFINED) { tp->type = DEFINED; if ((tp + 1) < trp->lp && (tp + 1)->type == NAME) (tp + 1)->type = NAME1; else if ((tp + 3) < trp->lp && (tp + 1)->type == LP && (tp + 2)->type == NAME && (tp + 3)->type == RP) (tp + 2)->type = NAME1; else error(ERROR, "Incorrect syntax for `defined'"); tp++; continue; } else if (np->val == KMACHINE) { if (((tp - 1) >= trp->bp) && ((tp - 1)->type == SHARP)) { tp->type = ARCHITECTURE; if ((tp + 1) < trp->lp && (tp + 1)->type == NAME) (tp + 1)->type = NAME2; else if ((tp + 3) < trp->lp && (tp + 1)->type == LP && (tp + 2)->type == NAME && (tp + 3)->type == RP) (tp + 2)->type = NAME2; else error(ERROR, "Incorrect syntax for `#machine'"); } tp++; continue; } if (np->flag & ISMAC) builtin(trp, np->val); else expand(trp, np); tp = trp->tp; } if (flag) unsetsource(); } /* * Expand the macro whose name is np, at token trp->tp, in the tokenrow. * Return trp->tp at the first token next to be expanded * (ordinarily the beginning of the expansion) */ void expand(Tokenrow * trp, Nlist * np) { Tokenrow ntr; int ntokc, narg, i; Tokenrow *atr[NARG + 1]; if (Mflag == 2) { if (np->ap) error(INFO, "Macro expansion of %t with %s(%r)", trp->tp, np->name, np->ap); else error(INFO, "Macro expansion of %t with %s", trp->tp, np->name); } copytokenrow(&ntr, np->vp); /* copy macro value */ if (np->ap == NULL) /* parameterless */ ntokc = 1; else { ntokc = gatherargs(trp, atr, &narg); if (narg < 0) { /* not actually a call (no '(') */ trp->tp++; return; } if (narg != rowlen(np->ap)) { error(ERROR, "Disagreement in number of macro arguments"); trp->tp += ntokc; return; } substargs(np, &ntr, atr); /* put args into replacement */ for (i = 0; i < narg; i++) { dofree(atr[i]->bp); dofree(atr[i]); } } np->flag |= ISACTIVE; doconcat(&ntr); /* execute ## operators */ ntr.tp = ntr.bp; makespace(&ntr, trp->tp); expandrow(&ntr, ""); insertrow(trp, ntokc, &ntr); dofree(ntr.bp); np->flag &= ~ISACTIVE; return; } /* * Gather an arglist, starting in trp with tp pointing at the macro name. * Return total number of tokens passed, stash number of args found. * trp->tp is not changed relative to the tokenrow. */ int gatherargs(Tokenrow * trp, Tokenrow ** atr, int *narg) { int parens = 1; int ntok = 0; Token *bp, *lp; Tokenrow ttr; int ntokp; int needspace; *narg = -1; /* means that there is no macro * call */ /* look for the ( */ for (;;) { trp->tp++; ntok++; if (trp->tp >= trp->lp) { gettokens(trp, 0); if ((trp->lp - 1)->type == END) { trp->lp -= 1; trp->tp -= ntok; return ntok; } } if (trp->tp->type == LP) break; if (trp->tp->type != NL) return ntok; } *narg = 0; ntok++; ntokp = ntok; trp->tp++; /* search for the terminating ), possibly extending the row */ needspace = 0; while (parens > 0) { if (trp->tp >= trp->lp) gettokens(trp, 0); if (needspace) { needspace = 0; /* makespace(trp); [rh] */ } if (trp->tp->type == END) { trp->lp -= 1; trp->tp -= ntok; error(ERROR, "EOF in macro arglist"); return ntok; } if (trp->tp->type == NL) { trp->tp += 1; adjustrow(trp, -1); trp->tp -= 1; /* makespace(trp); [rh] */ needspace = 1; continue; } if (trp->tp->type == LP) parens++; else if (trp->tp->type == RP) parens--; trp->tp++; ntok++; } trp->tp -= ntok; /* Now trp->tp won't move underneath us */ lp = bp = trp->tp + ntokp; for (; parens >= 0; lp++) { if (lp->type == LP) { parens++; continue; } if (lp->type == RP) parens--; if (lp->type == DSHARP) lp->type = DSHARP1; /* ## not special in arg */ if ((lp->type == COMMA && parens == 0) || (parens < 0 && (lp - 1)->type != LP)) { if (*narg >= NARG - 1) error(FATAL, "Sorry, too many macro arguments"); ttr.bp = ttr.tp = bp; ttr.lp = lp; atr[(*narg)++] = normtokenrow(&ttr); bp = lp + 1; } } return ntok; } /* * substitute the argument list into the replacement string * This would be simple except for ## and # */ void substargs(Nlist * np, Tokenrow * rtr, Tokenrow ** atr) { Tokenrow tatr; Token *tp; int ntok, argno; for (rtr->tp = rtr->bp; rtr->tp < rtr->lp;) { if (rtr->tp->type == SHARP) { /* string operator */ tp = rtr->tp; rtr->tp += 1; if ((argno = lookuparg(np, rtr->tp)) < 0) { error(ERROR, "# not followed by macro parameter"); continue; } ntok = 1 + (rtr->tp - tp); rtr->tp = tp; insertrow(rtr, ntok, stringify(atr[argno])); continue; } if (rtr->tp->type == NAME && (argno = lookuparg(np, rtr->tp)) >= 0) { if (((rtr->tp + 1) < rtr->lp && (rtr->tp + 1)->type == DSHARP) || (rtr->tp != rtr->bp && (rtr->tp - 1)->type == DSHARP)) { copytokenrow(&tatr, atr[argno]); makespace(&tatr, rtr->tp); insertrow(rtr, 1, &tatr); dofree(tatr.bp); } else { copytokenrow(&tatr, atr[argno]); makespace(&tatr, rtr->tp); expandrow(&tatr, ""); insertrow(rtr, 1, &tatr); dofree(tatr.bp); } continue; } rtr->tp++; } } /* * Evaluate the ## operators in a tokenrow */ void doconcat(Tokenrow * trp) { Token *ltp, *ntp; Tokenrow ntr; int len; for (trp->tp = trp->bp; trp->tp < trp->lp; trp->tp++) { if (trp->tp->type == DSHARP1) trp->tp->type = DSHARP; else if (trp->tp->type == DSHARP) { int i; char tt[NCONCAT]; ltp = trp->tp - 1; ntp = trp->tp + 1; if (ltp < trp->bp || ntp >= trp->lp) { error(ERROR, "## occurs at border of replacement"); continue; } ntp = ltp; i = 1; len = 0; do { if (len + ntp->len + ntp->wslen > sizeof(tt)) { error(ERROR, "## string concatination buffer overrun"); break; } strncpy((char *) tt + len, (char *) ntp->t - ntp->wslen, ntp->len + ntp->wslen); len += ntp->len + ntp->wslen; ntp = trp->tp + i; i++; } while (ntp < trp->lp); tt[len] = '\0'; setsource("<##>", -1, -1, tt, 0); maketokenrow(3, &ntr); gettokens(&ntr, 1); unsetsource(); if (ntr.bp->type == UNCLASS) error(WARNING, "Bad token %r produced by ##", &ntr); doconcat(&ntr); trp->tp = ltp; makespace(&ntr, ltp); insertrow(trp, ntp - ltp, &ntr); dofree(ntr.bp); trp->tp--; } } } /* * tp is a potential parameter name of macro mac; * look it up in mac's arglist, and if found, return the * corresponding index in the argname array. Return -1 if not found. */ int lookuparg(Nlist * mac, Token * tp) { Token *ap; if (tp->type != NAME || mac->ap == NULL) return -1; for (ap = mac->ap->bp; ap < mac->ap->lp; ap++) { if (ap->len == tp->len && strncmp((char *) ap->t, (char *) tp->t, ap->len) == 0) return ap - mac->ap->bp; } return -1; } /* * Return a quoted version of the tokenrow (from # arg) */ #define STRLEN 512 Tokenrow * stringify(Tokenrow * vp) { static Token t = {STRING, 0, 0, 0, NULL}; static Tokenrow tr = {&t, &t, &t + 1, 1}; Token *tp; uchar s[STRLEN]; uchar *sp = s, *cp; int i, instring; *sp++ = '"'; for (tp = vp->bp; tp < vp->lp; tp++) { instring = tp->type == STRING || tp->type == CCON; if (sp + 2 * tp->len >= &s[STRLEN - 10]) { error(ERROR, "Stringified macro arg is too long"); break; } for (i = 0, cp = tp->t; (unsigned int)i < tp->len; i++) { if (instring && (*cp == '"' || *cp == '\\')) *sp++ = '\\'; *sp++ = *cp++; } } *sp++ = '"'; *sp = '\0'; sp = s; t.len = strlen((char *) sp); t.t = newstring(sp, t.len, 0); return &tr; } /* * expand a builtin name */ void builtin(Tokenrow * trp, int biname) { char *op; Token *tp; Source *s; tp = trp->tp; trp->tp++; /* need to find the real source */ s = cursource; while (s && s->fd == -1) s = s->next; if (s == NULL) s = cursource; /* most are strings */ tp->type = STRING; if (tp->wslen) { *outptr++ = ' '; tp->wslen = 1; } op = outptr; *op++ = '"'; switch (biname) { case KLINENO: tp->type = NUMBER; op = outnum(op - 1, s->line); break; case KFILE: { char *src = s->filename; while ((*op++ = *src++) != 0) if (src[-1] == '\\') *op++ = '\\'; op--; break; } case KDATE: strncpy(op, curtime + 4, 7); strncpy(op + 7, curtime + 20, 4); op += 11; break; case KTIME: strncpy(op, curtime + 11, 8); op += 8; break; default: error(ERROR, "cpp botch: unknown internal macro"); return; } if (tp->type == STRING) *op++ = '"'; tp->t = (uchar *) outptr; tp->len = op - outptr; outptr = op; }