#include "config.h"
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
#undef abort
static int comp_def_part PARAMS ((int, U_CHAR *, int, U_CHAR *,
int, int));
static int change_newlines PARAMS ((U_CHAR *, int));
static void push_macro_expansion PARAMS ((cpp_reader *,
U_CHAR *, int, HASHNODE *));
static int unsafe_chars PARAMS ((int, int));
#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
#define CPP_IS_MACRO_BUFFER(PBUF) ((PBUF)->data != NULL)
#define FORWARD(N) CPP_FORWARD (CPP_BUFFER (pfile), (N))
extern char *version_string;
struct arglist
{
struct arglist *next;
U_CHAR *name;
int length;
int argno;
char rest_args;
};
#define ARG_BASE ((pfile)->token_buffer)
struct argdata
{
long raw, expanded, stringified;
int raw_length, expand_length;
int stringified_length;
char newlines;
char use_count;
};
int
hashf (name, len, hashsize)
register const U_CHAR *name;
register int len;
int hashsize;
{
register int r = 0;
while (len--)
r = HASHSTEP (r, *name++);
return MAKE_POS (r) % hashsize;
}
HASHNODE *
cpp_lookup (pfile, name, len, hash)
cpp_reader *pfile ATTRIBUTE_UNUSED;
const U_CHAR *name;
int len;
int hash;
{
register const U_CHAR *bp;
register HASHNODE *bucket;
if (len < 0)
{
for (bp = name; is_idchar[*bp]; bp++);
len = bp - name;
}
if (hash < 0)
hash = hashf (name, len, HASHSIZE);
bucket = pfile->hashtab[hash];
while (bucket)
{
if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
return bucket;
bucket = bucket->next;
}
return (HASHNODE *) 0;
}
void
delete_macro (hp)
HASHNODE *hp;
{
if (hp->prev != NULL)
hp->prev->next = hp->next;
if (hp->next != NULL)
hp->next->prev = hp->prev;
if (hp == *hp->bucket_hdr)
*hp->bucket_hdr = hp->next;
if (hp->type == T_MACRO)
{
DEFINITION *d = hp->value.defn;
struct reflist *ap, *nextap;
for (ap = d->pattern; ap != NULL; ap = nextap)
{
nextap = ap->next;
free (ap);
}
if (d->nargs >= 0)
free (d->args.argnames);
free (d);
}
free (hp);
}
HASHNODE *
cpp_install (pfile, name, len, type, value, hash)
cpp_reader *pfile;
U_CHAR *name;
int len;
enum node_type type;
const char *value;
int hash;
{
register HASHNODE *hp;
register int i, bucket;
register U_CHAR *p;
if (len < 0)
{
p = name;
while (is_idchar[*p])
p++;
len = p - name;
}
if (hash < 0)
hash = hashf (name, len, HASHSIZE);
i = sizeof (HASHNODE) + len + 1;
hp = (HASHNODE *) xmalloc (i);
bucket = hash;
hp->bucket_hdr = &pfile->hashtab[bucket];
hp->next = pfile->hashtab[bucket];
pfile->hashtab[bucket] = hp;
hp->prev = NULL;
if (hp->next != NULL)
hp->next->prev = hp;
hp->type = type;
hp->length = len;
hp->value.cpval = value;
hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
bcopy (name, hp->name, len);
hp->name[len] = 0;
return hp;
}
static int
macro_cleanup (pbuf, pfile)
cpp_buffer *pbuf;
cpp_reader *pfile ATTRIBUTE_UNUSED;
{
HASHNODE *macro = (HASHNODE *) pbuf->data;
if (macro->type == T_DISABLED)
macro->type = T_MACRO;
if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion)
free (pbuf->buf);
return 0;
}
static DEFINITION *
collect_expansion (pfile, buf, limit, nargs, arglist)
cpp_reader *pfile;
U_CHAR *buf, *limit;
int nargs;
struct arglist *arglist;
{
DEFINITION *defn;
register U_CHAR *p, *lastp, *exp_p;
struct reflist *endpat = NULL;
U_CHAR *concat = 0;
U_CHAR *stringify = 0;
int maxsize;
int expected_delimiter = '\0';
if (limit < buf)
{
cpp_fatal (pfile, "internal error: limit < buf in collect_expansion");
limit = buf;
}
p = buf;
while (p < limit && is_space[limit[-1]])
limit--;
maxsize = (sizeof (DEFINITION)
+ (limit - p) + 5);
defn = (DEFINITION *) xcalloc (1, maxsize);
defn->nargs = nargs;
exp_p = defn->expansion = (U_CHAR *) defn + sizeof (DEFINITION);
lastp = exp_p;
p = buf;
*exp_p++ = '\r';
*exp_p++ = ' ';
if (limit - p >= 2 && p[0] == '#' && p[1] == '#')
{
cpp_error (pfile, "`##' at start of macro definition");
p += 2;
}
while (p < limit)
{
int skipped_arg = 0;
register U_CHAR c = *p++;
*exp_p++ = c;
if (!CPP_TRADITIONAL (pfile))
{
switch (c)
{
case '\'':
case '\"':
if (expected_delimiter != '\0')
{
if (c == expected_delimiter)
expected_delimiter = '\0';
}
else
expected_delimiter = c;
break;
case '\\':
if (p < limit && expected_delimiter)
{
*exp_p++ = *p++;
}
break;
case '#':
if (expected_delimiter)
break;
if (p < limit && *p == '#')
{
exp_p--;
while (exp_p > lastp && is_hor_space[exp_p[-1]])
--exp_p;
p++;
SKIP_WHITE_SPACE (p);
concat = p;
if (p == limit)
cpp_error (pfile, "`##' at end of macro definition");
}
else if (nargs >= 0)
{
exp_p--;
SKIP_WHITE_SPACE (p);
if (p == limit || !is_idstart[*p]
|| (*p == 'L' && p + 1 < limit && (p[1] == '\'' ||
p[1] == '"')))
cpp_error (pfile,
"`#' operator is not followed by a macro argument name");
else
stringify = p;
}
break;
}
}
else
{
switch (c)
{
case '\'':
case '\"':
if (expected_delimiter != '\0')
{
if (c == expected_delimiter)
expected_delimiter = '\0';
}
else
expected_delimiter = c;
break;
case '\\':
if (expected_delimiter != 0 && p < limit
&& (*p == expected_delimiter || *p == '\\'))
{
*exp_p++ = *p++;
continue;
}
break;
case '/':
if (expected_delimiter != '\0')
break;
if (*p == '*')
{
exp_p--;
p += 1;
while (p < limit && !(p[-2] == '*' && p[-1] == '/'))
p++;
#if 0
concat = p;
#endif
}
break;
}
}
if (is_idchar[c] && nargs > 0)
{
U_CHAR *id_beg = p - 1;
int id_len;
--exp_p;
while (p != limit && is_idchar[*p])
p++;
id_len = p - id_beg;
if (is_idstart[c]
&& !(id_len == 1 && c == 'L' && (*p == '\'' || *p == '"')))
{
register struct arglist *arg;
for (arg = arglist; arg != NULL; arg = arg->next)
{
struct reflist *tpat;
if (arg->name[0] == c
&& arg->length == id_len
&& strncmp (arg->name, id_beg, id_len) == 0)
{
if (expected_delimiter && CPP_OPTIONS
(pfile)->warn_stringify)
{
if (CPP_TRADITIONAL (pfile))
{
cpp_warning (pfile,
"macro argument `%.*s' is stringified.",
id_len, arg->name);
}
else
{
cpp_warning (pfile,
"macro arg `%.*s' would be stringified with -traditional.",
id_len, arg->name);
}
}
if (!CPP_TRADITIONAL (pfile) && expected_delimiter)
break;
tpat = (struct reflist *)
xmalloc (sizeof (struct reflist));
tpat->next = NULL;
tpat->raw_before = concat == id_beg;
tpat->raw_after = 0;
tpat->rest_args = arg->rest_args;
tpat->stringify = (CPP_TRADITIONAL (pfile)
? expected_delimiter != '\0'
: stringify == id_beg);
if (endpat == NULL)
defn->pattern = tpat;
else
endpat->next = tpat;
endpat = tpat;
tpat->argno = arg->argno;
tpat->nchars = exp_p - lastp;
{
register U_CHAR *p1 = p;
SKIP_WHITE_SPACE (p1);
if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#')
tpat->raw_after = 1;
}
lastp = exp_p;
skipped_arg = 1;
break;
}
}
}
if (!skipped_arg)
{
register U_CHAR *lim1 = p;
p = id_beg;
while (p != lim1)
*exp_p++ = *p++;
if (stringify == id_beg)
cpp_error (pfile,
"`#' operator should be followed by a macro argument name");
}
}
}
if (!CPP_TRADITIONAL (pfile) && expected_delimiter == 0)
{
*exp_p++ = '\r';
*exp_p++ = ' ';
}
*exp_p = '\0';
defn->length = exp_p - defn->expansion;
if (defn->length + 1 > maxsize)
abort ();
#if 0
defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1);
#endif
return defn;
}
static char rest_extension[] = "...";
#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)
MACRODEF
create_definition (buf, limit, pfile, predefinition)
U_CHAR *buf, *limit;
cpp_reader *pfile;
int predefinition;
{
U_CHAR *bp;
U_CHAR *symname;
int sym_length;
int rest_args = 0;
long line, col;
char *file = CPP_BUFFER (pfile) ? CPP_BUFFER (pfile)->nominal_fname : "";
DEFINITION *defn;
int arglengths = 0;
MACRODEF mdef;
cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col);
bp = buf;
while (is_hor_space[*bp])
bp++;
symname = bp;
sym_length = check_macro_name (pfile, bp, 0);
bp += sym_length;
if (*bp == '(')
{
struct arglist *arg_ptrs = NULL;
int argno = 0;
bp++;
SKIP_WHITE_SPACE (bp);
while (*bp != ')')
{
struct arglist *temp;
temp = (struct arglist *) alloca (sizeof (struct arglist));
temp->name = bp;
temp->next = arg_ptrs;
temp->argno = argno++;
temp->rest_args = 0;
arg_ptrs = temp;
if (rest_args)
cpp_pedwarn (pfile, "another parameter follows `%s'",
rest_extension);
if (!is_idstart[*bp])
cpp_pedwarn (pfile, "invalid character in macro parameter name");
while (is_idchar[*bp])
{
bp++;
if ((size_t) (limit - bp) > REST_EXTENSION_LENGTH
&& !strncmp (rest_extension, bp, REST_EXTENSION_LENGTH))
{
rest_args = 1;
temp->rest_args = 1;
break;
}
}
temp->length = bp - temp->name;
if (rest_args == 1)
bp += REST_EXTENSION_LENGTH;
arglengths += temp->length + 2;
SKIP_WHITE_SPACE (bp);
if (temp->length == 0 || (*bp != ',' && *bp != ')'))
{
cpp_error (pfile,
"badly punctuated parameter list in `#define'");
goto nope;
}
if (*bp == ',')
{
bp++;
SKIP_WHITE_SPACE (bp);
}
if (bp >= limit)
{
cpp_error (pfile, "unterminated parameter list in `#define'");
goto nope;
}
{
struct arglist *otemp;
for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
if (temp->length == otemp->length
&& strncmp (temp->name, otemp->name, temp->length) == 0)
{
U_CHAR *name;
name = (U_CHAR *) alloca (temp->length + 1);
(void) strncpy (name, temp->name, temp->length);
name[temp->length] = '\0';
cpp_error (pfile,
"duplicate argument name `%s' in `#define'",
name);
goto nope;
}
}
}
++bp;
SKIP_WHITE_SPACE (bp);
defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs);
defn->rest_args = rest_args;
defn->args.argnames = (U_CHAR *) xmalloc (arglengths + 1);
{
struct arglist *temp;
int i = 0;
for (temp = arg_ptrs; temp; temp = temp->next)
{
bcopy (temp->name, &defn->args.argnames[i], temp->length);
i += temp->length;
if (temp->next != 0)
{
defn->args.argnames[i++] = ',';
defn->args.argnames[i++] = ' ';
}
}
defn->args.argnames[i] = 0;
}
}
else
{
if (bp < limit)
{
if (is_hor_space[*bp])
{
bp++;
SKIP_WHITE_SPACE (bp);
}
else
cpp_pedwarn (pfile,
"missing white space after `#define %.*s'",
sym_length, symname);
}
defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR);
defn->args.argnames = (U_CHAR *) "";
}
defn->line = line;
defn->file = file;
defn->predefined = predefinition;
mdef.defn = defn;
mdef.symnam = symname;
mdef.symlen = sym_length;
return mdef;
nope:
mdef.defn = 0;
return mdef;
}
static enum cpp_token
macarg (pfile, rest_args)
cpp_reader *pfile;
int rest_args;
{
int paren = 0;
enum cpp_token token;
char save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments;
CPP_OPTIONS (pfile)->put_out_comments = 0;
pfile->no_macro_expand++;
CPP_OPTIONS (pfile)->no_line_commands++;
for (;;)
{
token = cpp_get_token (pfile);
switch (token)
{
case CPP_EOF:
goto done;
case CPP_POP:
if (!CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
goto done;
break;
case CPP_LPAREN:
paren++;
break;
case CPP_RPAREN:
if (--paren < 0)
goto found;
break;
case CPP_COMMA:
if (paren == 0 && rest_args == 0)
goto found;
break;
found:
CPP_ADJUST_WRITTEN (pfile, -1);
goto done;
default:;
}
}
done:
CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments;
CPP_OPTIONS (pfile)->no_line_commands--;
pfile->no_macro_expand--;
return token;
}
static int
change_newlines (start, length)
U_CHAR *start;
int length;
{
register U_CHAR *ibp;
register U_CHAR *obp;
register U_CHAR *limit;
register int c;
ibp = start;
limit = start + length;
obp = start;
while (ibp < limit)
{
*obp++ = c = *ibp++;
switch (c)
{
case '\'':
case '\"':
{
int quotec = c;
while (ibp < limit)
{
*obp++ = c = *ibp++;
if (c == quotec)
break;
if (c == '\n' && quotec == '\'')
break;
}
}
break;
}
}
return obp - start;
}
static struct tm *
timestamp (pfile)
cpp_reader *pfile;
{
if (!pfile->timebuf)
{
time_t t = time ((time_t *) 0);
pfile->timebuf = localtime (&t);
}
return pfile->timebuf;
}
static char *monthnames[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
static void
special_symbol (hp, pfile)
HASHNODE *hp;
cpp_reader *pfile;
{
const char *buf;
int len;
cpp_buffer *ip;
switch (hp->type)
{
case T_FILE:
case T_BASE_FILE:
{
ip = CPP_BUFFER (pfile);
if (hp->type == T_BASE_FILE)
{
while (CPP_PREV_BUFFER (ip) != CPP_NULL_BUFFER (pfile))
ip = CPP_PREV_BUFFER (ip);
}
else
{
ip = CPP_BUFFER (pfile);
while (!ip->nominal_fname && ip != CPP_NULL_BUFFER (pfile))
ip = CPP_PREV_BUFFER (ip);
}
buf = ip->nominal_fname;
if (!buf)
buf = "";
CPP_RESERVE (pfile, 3 + 4 * strlen (buf));
quote_string (pfile, buf);
return;
}
case T_INCLUDE_LEVEL:
{
int true_indepth = 0;
ip = CPP_BUFFER (pfile);
for (; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip))
if (ip->fname != NULL)
true_indepth++;
CPP_RESERVE (pfile, 10);
sprintf (CPP_PWRITTEN (pfile), "%d", true_indepth);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
return;
}
case T_VERSION:
len = strlen (version_string);
CPP_RESERVE (pfile, 3 + len);
CPP_PUTC_Q (pfile, '"');
CPP_PUTS_Q (pfile, version_string, len);
CPP_PUTC_Q (pfile, '"');
CPP_NUL_TERMINATE_Q (pfile);
return;
case T_CONST:
buf = hp->value.cpval;
if (!buf)
return;
if (*buf == '\0')
buf = "\r ";
len = strlen (buf);
CPP_RESERVE (pfile, len + 1);
CPP_PUTS_Q (pfile, buf, len);
CPP_NUL_TERMINATE_Q (pfile);
return;
case T_STDC:
CPP_RESERVE (pfile, 2);
#ifdef STDC_0_IN_SYSTEM_HEADERS
ip = CPP_BUFFER (pfile);
while (!ip->nominal_fname && ip != CPP_NULL_BUFFER (pfile))
ip = CPP_PREV_BUFFER (ip);
if (ip->system_header_p
&& !cpp_lookup (pfile, (U_CHAR *) "__STRICT_ANSI__", 15, -1))
CPP_PUTC_Q (pfile, '0');
else
#endif
CPP_PUTC_Q (pfile, '1');
CPP_NUL_TERMINATE_Q (pfile);
return;
case T_SPECLINE:
{
long line;
cpp_buf_line_and_col (cpp_file_buffer (pfile), &line, NULL);
CPP_RESERVE (pfile, 10);
sprintf (CPP_PWRITTEN (pfile), "%ld", line);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
return;
}
case T_DATE:
case T_TIME:
{
struct tm *timebuf;
CPP_RESERVE (pfile, 20);
timebuf = timestamp (pfile);
if (hp->type == T_DATE)
sprintf (CPP_PWRITTEN (pfile), "\"%s %2d %4d\"",
monthnames[timebuf->tm_mon],
timebuf->tm_mday, timebuf->tm_year + 1900);
else
sprintf (CPP_PWRITTEN (pfile), "\"%02d:%02d:%02d\"",
timebuf->tm_hour, timebuf->tm_min, timebuf->tm_sec);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
return;
}
default:
cpp_fatal (pfile, "cpplib internal error: invalid special hash type");
return;
}
}
void
macroexpand (pfile, hp)
cpp_reader *pfile;
HASHNODE *hp;
{
int nargs;
DEFINITION *defn;
register U_CHAR *xbuf;
long start_line, start_column;
int xbuf_len;
struct argdata *args;
long old_written = CPP_WRITTEN (pfile);
#if 0
int start_line = instack[indepth].lineno;
#endif
int rest_args, rest_zero;
register int i;
#if 0
if (pcp_inside_if && pcp_outfile && defn->predefined)
dump_single_macro (hp, pcp_outfile);
#endif
cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
if (hp->type != T_MACRO)
{
special_symbol (hp, pfile);
xbuf_len = CPP_WRITTEN (pfile) - old_written;
xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
CPP_SET_WRITTEN (pfile, old_written);
bcopy (CPP_PWRITTEN (pfile), xbuf, xbuf_len + 1);
push_macro_expansion (pfile, xbuf, xbuf_len, hp);
CPP_BUFFER (pfile)->has_escapes = 1;
return;
}
defn = hp->value.defn;
nargs = defn->nargs;
pfile->output_escapes++;
if (nargs >= 0)
{
enum cpp_token token = CPP_EOF;
args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
for (i = 0; i < nargs; i++)
{
args[i].raw = args[i].expanded = 0;
args[i].raw_length = 0;
args[i].expand_length = args[i].stringified_length = -1;
args[i].use_count = 0;
}
i = 0;
rest_args = 0;
rest_args = 0;
FORWARD (1);
do
{
if (rest_args)
continue;
if (i < nargs || (nargs == 0 && i == 0))
{
if (i == nargs - 1 && defn->rest_args)
rest_args = 1;
args[i].raw = CPP_WRITTEN (pfile);
token = macarg (pfile, rest_args);
args[i].raw_length = CPP_WRITTEN (pfile) - args[i].raw;
args[i].newlines = 0;
}
else
token = macarg (pfile, 0);
if (token == CPP_EOF || token == CPP_POP)
{
cpp_error_with_line (pfile, start_line, start_column,
"unterminated macro call");
return;
}
i++;
}
while (token == CPP_COMMA);
if (i == 1)
{
register U_CHAR *bp = ARG_BASE + args[0].raw;
register U_CHAR *lim = bp + args[0].raw_length;
if (nargs == 0)
while (bp != lim && is_space[*bp])
bp++;
if (bp == lim)
i = 0;
}
rest_zero = 0;
if (nargs == 0 && i > 0)
{
cpp_error (pfile, "arguments given to macro `%s'", hp->name);
}
else if (i < nargs)
{
if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile))
;
else if (i == nargs - 1 && defn->rest_args)
rest_zero = 1;
else if (i == 0)
cpp_error (pfile, "macro `%s' used without args", hp->name);
else if (i == 1)
cpp_error (pfile, "macro `%s' used with just one arg", hp->name);
else
cpp_error (pfile, "macro `%s' used with only %d args",
hp->name, i);
}
else if (i > nargs)
{
cpp_error (pfile,
"macro `%s' used with too many (%d) args", hp->name, i);
}
}
if (nargs <= 0)
{
xbuf = defn->expansion;
xbuf_len = defn->length;
}
else
{
register U_CHAR *exp = defn->expansion;
register int offset;
register int totlen;
register struct reflist *ap, *last_ap;
xbuf_len = defn->length;
for (ap = defn->pattern; ap != NULL; ap = ap->next)
{
if (ap->stringify)
{
register struct argdata *arg = &args[ap->argno];
if (arg->stringified_length < 0)
{
int arglen = arg->raw_length;
int escaped = 0;
int in_string = 0;
int c;
int need_space = -1;
i = 0;
arg->stringified = CPP_WRITTEN (pfile);
if (!CPP_TRADITIONAL (pfile))
CPP_PUTC (pfile, '\"');
for (; i < arglen; i++)
{
c = (ARG_BASE + arg->raw)[i];
if (!in_string)
{
if (is_space[c])
{
if (CPP_WRITTEN (pfile) > (unsigned) arg->stringified
&& (CPP_PWRITTEN (pfile))[-1] == '\r')
{
CPP_ADJUST_WRITTEN (pfile, -1);
continue;
}
if (need_space == 0)
need_space = 1;
continue;
}
else if (need_space > 0)
CPP_PUTC (pfile, ' ');
need_space = 0;
}
if (escaped)
escaped = 0;
else
{
if (c == '\\')
escaped = 1;
if (in_string)
{
if (c == in_string)
in_string = 0;
}
else if (c == '\"' || c == '\'')
in_string = c;
}
if (c == '\"' || (in_string && c == '\\'))
CPP_PUTC (pfile, '\\');
if (ISPRINT (c))
CPP_PUTC (pfile, c);
else
{
CPP_RESERVE (pfile, 4);
sprintf ((char *) CPP_PWRITTEN (pfile), "\\%03o",
(unsigned int) c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
}
if (!CPP_TRADITIONAL (pfile))
CPP_PUTC (pfile, '\"');
arg->stringified_length
= CPP_WRITTEN (pfile) - arg->stringified;
}
xbuf_len += args[ap->argno].stringified_length;
}
else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
xbuf_len += args[ap->argno].raw_length + 4;
else
{
if (args[ap->argno].expand_length < 0)
{
args[ap->argno].expanded = CPP_WRITTEN (pfile);
cpp_expand_to_buffer (pfile,
ARG_BASE + args[ap->argno].raw,
args[ap->argno].raw_length);
args[ap->argno].expand_length
= CPP_WRITTEN (pfile) - args[ap->argno].expanded;
}
xbuf_len += args[ap->argno].expand_length + 4;
}
if (args[ap->argno].use_count < 10)
args[ap->argno].use_count++;
}
xbuf = (U_CHAR *) xmalloc (xbuf_len + 1);
offset = totlen = 0;
for (last_ap = NULL, ap = defn->pattern; ap != NULL;
last_ap = ap, ap = ap->next)
{
register struct argdata *arg = &args[ap->argno];
int count_before = totlen;
for (i = 0; i < ap->nchars; i++, offset++)
xbuf[totlen++] = exp[offset];
if (rest_zero && totlen > count_before
&& ((ap->rest_args && ap->raw_before)
|| (last_ap != NULL && last_ap->rest_args
&& last_ap->raw_after)))
{
while (totlen > count_before && is_space[xbuf[totlen - 1]])
totlen--;
while (totlen > count_before && !is_space[xbuf[totlen - 1]])
totlen--;
}
if (ap->stringify != 0)
{
bcopy (ARG_BASE + arg->stringified,
xbuf + totlen, arg->stringified_length);
totlen += arg->stringified_length;
}
else if (ap->raw_before || ap->raw_after || CPP_TRADITIONAL (pfile))
{
U_CHAR *p1 = ARG_BASE + arg->raw;
U_CHAR *l1 = p1 + arg->raw_length;
if (ap->raw_before)
{
while (p1 != l1 && is_space[*p1])
p1++;
while (p1 != l1 && is_idchar[*p1])
xbuf[totlen++] = *p1++;
}
if (ap->raw_after)
{
while (p1 != l1)
{
if (is_space[l1[-1]])
l1--;
else if (l1[-1] == '\r')
l1--;
else if (l1[-1] == '-')
{
if (l1 != p1 + 1 && l1[-2] == '\r')
l1 -= 2;
else
break;
}
else
break;
}
}
if (p1[0] == '\r' && p1[1] == '-')
p1 += 2;
bcopy (p1, xbuf + totlen, l1 - p1);
totlen += l1 - p1;
}
else
{
U_CHAR *expanded = ARG_BASE + arg->expanded;
if (!ap->raw_before && totlen > 0 && arg->expand_length
&& !CPP_TRADITIONAL (pfile)
&& unsafe_chars (xbuf[totlen - 1], expanded[0]))
{
xbuf[totlen++] = '\r';
xbuf[totlen++] = ' ';
}
bcopy (expanded, xbuf + totlen, arg->expand_length);
totlen += arg->expand_length;
if (!ap->raw_after && totlen > 0 && offset < defn->length
&& !CPP_TRADITIONAL (pfile)
&& unsafe_chars (xbuf[totlen - 1], exp[offset]))
{
xbuf[totlen++] = '\r';
xbuf[totlen++] = ' ';
}
if (arg->use_count > 1 && arg->newlines > 0)
{
arg->use_count = 1;
arg->expand_length
= change_newlines (expanded, arg->expand_length);
}
}
if (totlen > xbuf_len)
{
cpp_fatal (pfile, "internal_error: buffer overrun in macroexpand");
return;
}
}
for (i = offset; i < defn->length; i++)
{
if (exp[i] == ')')
rest_zero = 0;
if (!(rest_zero && last_ap != NULL && last_ap->rest_args
&& last_ap->raw_after))
xbuf[totlen++] = exp[i];
}
xbuf[totlen] = 0;
xbuf_len = totlen;
}
pfile->output_escapes--;
push_macro_expansion (pfile, xbuf, xbuf_len, hp);
CPP_BUFFER (pfile)->has_escapes = 1;
CPP_SET_WRITTEN (pfile, old_written);
if (!CPP_TRADITIONAL (pfile))
hp->type = T_DISABLED;
}
static int
unsafe_chars (c1, c2)
int c1, c2;
{
switch (c1)
{
case '+':
case '-':
if (c2 == c1 || c2 == '=')
return 1;
goto letter;
case '.': case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': case '8':
case '9': case 'e': case 'E': case 'p': case 'P':
if (c2 == '-' || c2 == '+')
return 1;
goto letter;
case 'L':
if (c2 == '\'' || c2 == '\"')
return 1;
goto letter;
case '_': case 'a': case 'b': case 'c': case 'd': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'q': case 'r': case 's':
case 't': case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z': case 'A': case 'B': case 'C': case 'D': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'M':
case 'N': case 'O': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
letter:
return (is_idchar[c2] || c2 == '.');
case '<': case '>': case '!': case '%': case '#': case ':':
case '^': case '&': case '|': case '*': case '/': case '=':
return (c2 == c1 || c2 == '=');
}
return 0;
}
static void
push_macro_expansion (pfile, xbuf, xbuf_len, hp)
cpp_reader *pfile;
register U_CHAR *xbuf;
int xbuf_len;
HASHNODE *hp;
{
register cpp_buffer *mbuf = cpp_push_buffer (pfile, xbuf, xbuf_len);
if (mbuf == NULL)
return;
mbuf->cleanup = macro_cleanup;
mbuf->data = hp;
if (xbuf[0] == '\r' && xbuf[1] == ' '
&& (is_idchar[xbuf[2]] || xbuf[2] == '(' || xbuf[2] == '\''
|| xbuf[2] == '\"'))
mbuf->cur += 2;
if (xbuf_len >= 3
&& mbuf->rlimit[-2] == '\r'
&& mbuf->rlimit[-1] == ' ')
{
int c1 = mbuf->rlimit[-3];
int c2 = CPP_BUF_PEEK (CPP_PREV_BUFFER (CPP_BUFFER (pfile)));
if (c2 == EOF || !unsafe_chars (c1, c2))
mbuf->rlimit -= 2;
}
}
int
compare_defs (pfile, d1, d2)
cpp_reader *pfile;
DEFINITION *d1, *d2;
{
register struct reflist *a1, *a2;
register U_CHAR *p1 = d1->expansion;
register U_CHAR *p2 = d2->expansion;
int first = 1;
if (d1->nargs != d2->nargs)
return 1;
if (CPP_PEDANTIC (pfile)
&& strcmp ((char *) d1->args.argnames, (char *) d2->args.argnames))
return 1;
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
a1 = a1->next, a2 = a2->next)
{
if (!((a1->nchars == a2->nchars && !strncmp (p1, p2, a1->nchars))
|| !comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
|| a1->argno != a2->argno
|| a1->stringify != a2->stringify
|| a1->raw_before != a2->raw_before
|| a1->raw_after != a2->raw_after)
return 1;
first = 0;
p1 += a1->nchars;
p2 += a2->nchars;
}
if (a1 != a2)
return 1;
return comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
p2, d2->length - (p2 - d2->expansion), 1);
}
static int
comp_def_part (first, beg1, len1, beg2, len2, last)
int first;
U_CHAR *beg1, *beg2;
int len1, len2;
int last;
{
register U_CHAR *end1 = beg1 + len1;
register U_CHAR *end2 = beg2 + len2;
if (first)
{
while (beg1 != end1 && is_space[*beg1])
beg1++;
while (beg2 != end2 && is_space[*beg2])
beg2++;
}
if (last)
{
while (beg1 != end1 && is_space[end1[-1]])
end1--;
while (beg2 != end2 && is_space[end2[-1]])
end2--;
}
while (beg1 != end1 && beg2 != end2)
{
if (is_space[*beg1] && is_space[*beg2])
{
while (beg1 != end1 && is_space[*beg1])
beg1++;
while (beg2 != end2 && is_space[*beg2])
beg2++;
}
else if (*beg1 == *beg2)
{
beg1++;
beg2++;
}
else
break;
}
return (beg1 != end1) || (beg2 != end2);
}
void
dump_definition (pfile, macro)
cpp_reader *pfile;
MACRODEF macro;
{
DEFINITION *defn = macro.defn;
CPP_RESERVE (pfile, macro.symlen + sizeof "#define ");
CPP_PUTS_Q (pfile, "#define ", sizeof "#define " -1);
CPP_PUTS_Q (pfile, macro.symnam, macro.symlen);
if (defn->nargs == -1)
{
CPP_PUTC_Q (pfile, ' ');
CPP_RESERVE (pfile, defn->length - 4 + 1);
CPP_PUTS_Q (pfile, defn->expansion + 2, defn->length - 4);
CPP_NUL_TERMINATE_Q (pfile);
}
else
{
struct reflist *r;
unsigned char *argnames = xstrdup (defn->args.argnames);
unsigned char **argv = alloca (defn->nargs * sizeof(char *));
int *argl = alloca (defn->nargs * sizeof(int));
unsigned char *x;
int i;
x = argnames;
i = defn->nargs;
while (i--)
{
argv[i] = x;
while (*x != ',' && *x != '\0') x++;
argl[i] = x - argv[i];
if (*x == ',')
{
*x = '\0';
x += 2;
}
}
CPP_PUTC_Q (pfile, '(');
for (i = 0; i < defn->nargs; i++)
{
CPP_RESERVE (pfile, argl[i] + 2);
CPP_PUTS_Q (pfile, argv[i], argl[i]);
if (i < defn->nargs-1)
CPP_PUTS_Q (pfile, ", ", 2);
}
if (defn->rest_args)
CPP_PUTS (pfile, "...) ", 5);
else
CPP_PUTS (pfile, ") ", 2);
x = defn->expansion;
for (r = defn->pattern; r; r = r->next)
{
i = r->nchars;
if (*x == '\r') x += 2, i -= 2;
CPP_RESERVE (pfile,
i + argl[r->argno] + r->stringify
+ (r->raw_before + r->raw_after) * 2);
if (i > 0) CPP_PUTS_Q (pfile, x, i);
if (r->raw_before)
CPP_PUTS_Q (pfile, "##", 2);
if (r->stringify)
CPP_PUTC_Q (pfile, '#');
CPP_PUTS_Q (pfile, argv[r->argno], argl[r->argno]);
if (r->raw_after && !(r->next && r->next->nchars == 0
&& r->next->raw_before))
CPP_PUTS_Q (pfile, "##", 2);
x += i;
}
i = defn->length - (x - defn->expansion) - 2;
if (*x == '\r') x += 2, i -= 2;
if (i > 0) CPP_PUTS (pfile, x, i);
CPP_NUL_TERMINATE (pfile);
}
}