Print this page
cpp: if a macro with parameters is invoked without any, don't destroy state
Previously, we would parse a macro foo() presuming that we would always
see the opening parenthesis indicating the begining of the parameter
list. If we saw 'foo' we would consume the token _following_ 'foo'
presuming it would be the parenthesis, and if it was not, would not
paste it to the output.
@@ -74,10 +74,11 @@
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <stdarg.h>
+#include <ctype.h>
#include "cpp.h"
#define SYMLEN 128
static int symlen = SYMLEN;
@@ -634,10 +635,15 @@
if (isslo) return(p);
} /* end of infinite loop */
}
+/*
+ * XXX: This unconditionally consumes one token (presuming it's blank? that we
+ * already consumed it?). That's pretty terrible, but it's also very fragile,
+ * and I don't want to change it.
+ */
char *
skipbl(p) register char *p; {/* get next non-blank token */
do {
outp=inp=p;
p=cotoken(p);
@@ -1191,17 +1197,30 @@
vp=acttxt; *vp++='\0';
sprintf(vp,"\"%s\"",fnames[ifno]); while (*vp++);
}
if (0!=(params= *--vp&0xFF)) {/* definition calls for params */
register char **pa;
+ char *savp, *savinp, *savoutp;
ca=acttxt; pa=actual;
if (params==0xFF)
params=1; /* #define foo() ... */
sloscan();
++flslvl; /* no expansion during search for actuals */
plvl= -1;
- do p=skipbl(p); while (*inp=='\n'); /* skip \n too */
+ /*
+ * Skip any blanks (including \n), until we hit the macro
+ * arguments.
+ *
+ * save our state so we can roll back if none are called.
+ */
+ savp = p;
+ savinp = inp;
+ savoutp = outp;
+ do {
+ p=skipbl(p);
+ } while (*inp=='\n'); /* skip \n too */
+
if (*inp=='(') {
maclin=lineno[ifno]; macfil=fnames[ifno];
for (plvl=1; plvl!=0; ) {
*ca++='\0';
for (;;) {
@@ -1253,10 +1272,18 @@
ppwarn("%s: argument mismatch" ,
sp->name);
else
*pa++=ca;
}
+ } else {
+ /*
+ * Didn't find any parameters, rollback our state so
+ * we don't chew more output than necessary
+ */
+ p = savp;
+ inp = savinp;
+ outp = savoutp;
}
if (params!=0)
ppwarn("%s: argument mismatch", sp->name);
while (--params>=0)
*pa++=""+1; /* null string for missing actuals */