/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
/* * 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; static uchar location[(PATH_MAX + 8) * NINC], *cp;
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)
{
tp += 1;
args = new(Tokenrow);
maketokenrow(2, args); if (tp->type != RP)
{ /* macro with args */
size_t narg = 0; 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)))
{ if ( np->loc )
error(ERROR, "Macro redefinition of %t (already defined at %s)",
trp->bp + 2, np->loc); else
error(ERROR, "Macro redefinition of %t (already defined at %s)",
trp->bp + 2, "commandline" );
}
} if (args)
{
Tokenrow *tap;
/* * 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;
MacroValidatorList validators;
mvl_init(&validators); /* Sets all token-identifiers to 0 because tokens may not be initialised (never use C!) */
tokenrow_zeroTokenIdentifiers(trp);
if (flag)
setsource(flag, -1, -1, "", 0); for (tp = trp->tp; tp < trp->lp;)
{
mvl_check(&validators, tp);
if (np->flag & ISMAC)
builtin(trp, np->val); else
{ // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself
expand(trp, np, &validators);
}
tp = trp->tp;
} // end for if (flag)
unsetsource();
mvl_destruct(&validators);
}
/* * 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) * I.e.: the same position as before! * Only one expansion is performed, then we return to the expandrow() * loop and start at same position.
*/ void
expand(Tokenrow * trp, Nlist * np, MacroValidatorList * pValidators)
{
Tokenrow ntr; int ntokc, narg;
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
{ int i;
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;
}
/** If gatherargs passed a macro validating token, this token must become valid here. trp->tp+0 was checked in expandrow(), so we don't need to do it again here:
*/ for (i = 1; i < ntokc; i++)
{
mvl_check(pValidators,trp->tp+i);
}
substargs(np, &ntr, atr); /* put args into replacement */ for (i = 0; i < narg; i++)
{
dofree(atr[i]->bp);
dofree(atr[i]);
}
}
/* add validator for just invalidated macro:
*/
np->flag |= ISACTIVE; if (trp->tp != trp->lp)
{ /* tp is a valid pointer: */
mvl_add(pValidators,np,trp->tp);
} else
{ /* tp is == lp, therefore does not point to valid memory: */
mvl_add(pValidators,np,NULL);
} /* reset trp->tp to original position:
*/
trp->tp -= ntr.lp - ntr.bp; /* so the result will be tested for macros from the same position again */
dofree(ntr.bp);
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)
{ // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself
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)
{ // coverity[overrun-buffer-arg: FALSE] - a multiple of trp->max is allocated, not trp->max itself
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;
/* * 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 const * 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 (int)(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, NULL, 0}; static Tokenrow tr = {&t, &t, &t + 1, 1};
Token *tp;
uchar s[STRLEN];
uchar *sp = s, *cp; int i, instring;
/* * 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;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.