diff options
author | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
commit | 0126e157b87f137fc08dc7f46f6c291b9d06ac5d (patch) | |
tree | f8555e3e504eb82b4cd3cba5cec20ae4ce8124ff /gnu/egcs/gcc/cpphash.c | |
parent | ff8e9a4356e55ed142306c3a375fa280800abc86 (diff) |
egcs projects compiler system
Exact copy of the snapshot, except for the removal of
texinfo/
gcc/ch/
libchill/
Diffstat (limited to 'gnu/egcs/gcc/cpphash.c')
-rw-r--r-- | gnu/egcs/gcc/cpphash.c | 1735 |
1 files changed, 1735 insertions, 0 deletions
diff --git a/gnu/egcs/gcc/cpphash.c b/gnu/egcs/gcc/cpphash.c new file mode 100644 index 00000000000..1d8a104460e --- /dev/null +++ b/gnu/egcs/gcc/cpphash.c @@ -0,0 +1,1735 @@ +/* Part of CPP library. (Macro handling.) + Copyright (C) 1986, 87, 89, 92-95, 1996, 1998 Free Software Foundation, Inc. + Written by Per Bothner, 1994. + Based on CCCP program by Paul Rubin, June 1986 + Adapted to ANSI C, Richard Stallman, Jan 1987 + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +#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; + +/* The arglist structure is built by create_definition to tell + collect_expansion where the argument names begin. That + is, for a define like "#define f(x,y,z) foo+x-bar*y", the arglist + would contain pointers to the strings x, y, and z. + collect_expansion would then build a DEFINITION node, + with reflist nodes pointing to the places x, y, and z had + appeared. So the arglist is just convenience data passed + between these two routines. It is not kept around after + the current #define has been processed and entered into the + hash table. */ + +struct arglist +{ + struct arglist *next; + U_CHAR *name; + int length; + int argno; + char rest_args; +}; + +/* This structure represents one parsed argument in a macro call. + `raw' points to the argument text as written (`raw_length' is its length). + `expanded' points to the argument's macro-expansion + (its length is `expand_length'). + `stringified_length' is the length the argument would have + if stringified. + `use_count' is the number of times this macro arg is substituted + into the macro. If the actual use count exceeds 10, + the value stored is 10. */ + +/* raw and expanded are relative to ARG_BASE */ +#define ARG_BASE ((pfile)->token_buffer) + +struct argdata +{ + /* Strings relative to pfile->token_buffer */ + long raw, expanded, stringified; + int raw_length, expand_length; + int stringified_length; + char newlines; + char use_count; +}; + + +/* Return hash function on name. must be compatible with the one + computed a step at a time, elsewhere */ + +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; +} + +/* Find the most recent hash node for name "name" (ending with first + non-identifier char) installed by cpp_install + + If LEN is >= 0, it is the length of the name. + Otherwise, compute the length by scanning the entire name. + + If HASH is >= 0, it is the precomputed hash code. + Otherwise, compute the hash code. */ + +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; +} + +/* + * Delete a hash node. Some weirdness to free junk from macros. + * More such weirdness will have to be added if you define more hash + * types that need it. + */ + +/* Note that the DEFINITION of a macro is removed from the hash table + but its storage is not freed. This would be a storage leak + except that it is not reasonable to keep undefining and redefining + large numbers of macros many times. + In any case, this is necessary, because a macro can be #undef'd + in the middle of reading the arguments to a call to it. + If #undef freed the DEFINITION, that would crash. */ + +void +delete_macro (hp) + HASHNODE *hp; +{ + + if (hp->prev != NULL) + hp->prev->next = hp->next; + if (hp->next != NULL) + hp->next->prev = hp->prev; + + /* make sure that the bucket chain header that + the deleted guy was on points to the right thing afterwards. */ + 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); +} + +/* Install a name in the main hash table, even if it is already there. + Name stops with first non alphanumeric, except leading '#'. + Caller must check against redefinition if that is desired. + delete_macro () removes things installed by cpp_install () in fifo order. + this is important because of the `defined' special symbol used + in #if, and also if pushdef/popdef directives are ever implemented. + + If LEN is >= 0, it is the length of the name. + Otherwise, compute the length by scanning the entire name. + + If HASH is >= 0, it is the precomputed hash code. + Otherwise, compute the hash code. */ + +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; +} + + +/* Read a replacement list for a macro with parameters. + Build the DEFINITION structure. + Reads characters of text starting at BUF until END. + ARGLIST specifies the formal parameters to look for + in the text of the definition; NARGS is the number of args + in that list, or -1 for a macro name that wants no argument list. + MACRONAME is the macro name itself (so we can avoid recursive expansion) + and NAMELEN is its length in characters. + + Note that comments, backslash-newlines, and leading white space + have already been deleted from the argument. */ + +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; + /* Pointer to first nonspace after last ## seen. */ + U_CHAR *concat = 0; + /* Pointer to first nonspace after last single-# seen. */ + U_CHAR *stringify = 0; + int maxsize; + int expected_delimiter = '\0'; + + /* Scan thru the replacement list, ignoring comments and quoted + strings, picking up on the macro calls. It does a linear search + thru the arg list on every potential symbol. Profiling might say + that something smarter should happen. */ + + if (limit < buf) + { + cpp_fatal (pfile, "internal error: limit < buf in collect_expansion"); + limit = buf; /* treat it like a null defn */ + } + + /* Find the beginning of the trailing whitespace. */ + p = buf; + while (p < limit && is_space[limit[-1]]) + limit--; + + /* Allocate space for the text in the macro definition. + Leading and trailing whitespace chars need 2 bytes each. + Each other input char may or may not need 1 byte, + so this is an upper bound. The extra 5 are for invented + leading and trailing newline-marker and final null. */ + 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; + + /* Add one initial space escape-marker to prevent accidental + token-pasting (often removed by macroexpand). */ + *exp_p++ = '\r'; + *exp_p++ = ' '; + + if (limit - p >= 2 && p[0] == '#' && p[1] == '#') + { + cpp_error (pfile, "`##' at start of macro definition"); + p += 2; + } + + /* Process the main body of the definition. */ + 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) + { + /* In a string, backslash goes through + and makes next char ordinary. */ + *exp_p++ = *p++; + } + break; + + case '#': + /* # is ordinary inside a string. */ + if (expected_delimiter) + break; + if (p < limit && *p == '#') + { + /* ##: concatenate preceding and following tokens. */ + /* Take out the first #, discard preceding whitespace. */ + exp_p--; + while (exp_p > lastp && is_hor_space[exp_p[-1]]) + --exp_p; + /* Skip the second #. */ + p++; + /* Discard following whitespace. */ + SKIP_WHITE_SPACE (p); + concat = p; + if (p == limit) + cpp_error (pfile, "`##' at end of macro definition"); + } + else if (nargs >= 0) + { + /* Single #: stringify following argument ref. + Don't leave the # in the expansion. */ + 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 + { + /* In -traditional mode, recognize arguments inside strings and + character constants, and ignore special properties of #. + Arguments inside strings are considered "stringified", but no + extra quote marks are supplied. */ + switch (c) + { + case '\'': + case '\"': + if (expected_delimiter != '\0') + { + if (c == expected_delimiter) + expected_delimiter = '\0'; + } + else + expected_delimiter = c; + break; + + case '\\': + /* Backslash quotes delimiters and itself, + but not macro args. */ + if (expected_delimiter != 0 && p < limit + && (*p == expected_delimiter || *p == '\\')) + { + *exp_p++ = *p++; + continue; + } + break; + + case '/': + if (expected_delimiter != '\0') + /* No comments inside strings. */ + break; + if (*p == '*') + { + /* If we find a comment that wasn't removed by + handle_directive, this must be -traditional. + So replace the comment with nothing at all. */ + exp_p--; + p += 1; + while (p < limit && !(p[-2] == '*' && p[-1] == '/')) + p++; +#if 0 + /* Mark this as a concatenation-point, + as if it had been ##. */ + concat = p; +#endif + } + break; + } + } + + /* Handle the start of a symbol. */ + 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 ANSI, don't actually substitute + inside a string. */ + if (!CPP_TRADITIONAL (pfile) && expected_delimiter) + break; + /* make a pat node for this arg and append it + to the end of the pat list */ + 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 this was not a macro arg, copy it into the expansion. */ + 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) + { + /* If ANSI, put in a "\r " marker to prevent token pasting. + But not if "inside a string" (which in ANSI mode + happens only for -D option). */ + *exp_p++ = '\r'; + *exp_p++ = ' '; + } + + *exp_p = '\0'; + + defn->length = exp_p - defn->expansion; + + /* Crash now if we overrun the allocated size. */ + if (defn->length + 1 > maxsize) + abort (); + +#if 0 +/* This isn't worth the time it takes. */ + /* give back excess storage */ + defn->expansion = (U_CHAR *) xrealloc (defn->expansion, defn->length + 1); +#endif + + return defn; +} + +/* + * special extension string that can be added to the last macro argument to + * allow it to absorb the "rest" of the arguments when expanded. Ex: + * #define wow(a, b...) process (b, a, b) + * { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); } + * { wow (one, two); } -> { process (two, one, two); } + * if this "rest_arg" is used with the concat token '##' and if it is not + * supplied then the token attached to with ## will not be outputted. Ex: + * #define wow (a, b...) process (b ## , a, ## b) + * { wow (1, 2); } -> { process (2, 1, 2); } + * { wow (one); } -> { process (one); { + */ +static char rest_extension[] = "..."; +#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1) + +/* Create a DEFINITION node from a #define directive. Arguments are + as for do_define. */ + +MACRODEF +create_definition (buf, limit, pfile, predefinition) + U_CHAR *buf, *limit; + cpp_reader *pfile; + int predefinition; +{ + U_CHAR *bp; /* temp ptr into input buffer */ + U_CHAR *symname; /* remember where symbol name starts */ + int sym_length; /* and how long it is */ + int rest_args = 0; + long line, col; + char *file = CPP_BUFFER (pfile) ? CPP_BUFFER (pfile)->nominal_fname : ""; + DEFINITION *defn; + int arglengths = 0; /* Accumulate lengths of arg names + plus number of args. */ + MACRODEF mdef; + cpp_buf_line_and_col (CPP_BUFFER (pfile), &line, &col); + + bp = buf; + + while (is_hor_space[*bp]) + bp++; + + symname = bp; /* remember where it starts */ + + sym_length = check_macro_name (pfile, bp, 0); + bp += sym_length; + + /* Lossage will occur if identifiers or control keywords are broken + across lines using backslash. This is not the right place to take + care of that. */ + + if (*bp == '(') + { + struct arglist *arg_ptrs = NULL; + int argno = 0; + + bp++; /* skip '(' */ + SKIP_WHITE_SPACE (bp); + + /* Loop over macro argument names. */ + 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"); + + /* Find the end of the arg name. */ + while (is_idchar[*bp]) + { + bp++; + /* do we have a "special" rest-args extension here? */ + 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 paren */ + SKIP_WHITE_SPACE (bp); + /* now everything from bp before limit is the definition. */ + defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs); + defn->rest_args = rest_args; + + /* Now set defn->args.argnames to the result of concatenating + the argument names in reverse order + with comma-space between them. */ + 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 + { + /* Simple expansion or empty definition. */ + + if (bp < limit) + { + if (is_hor_space[*bp]) + { + bp++; + SKIP_WHITE_SPACE (bp); + } + else + /* Per C9x, missing white space after the name in a #define + of an object-like macro is always a constraint violation. */ + cpp_pedwarn (pfile, + "missing white space after `#define %.*s'", + sym_length, symname); + } + /* now everything from bp before limit is the definition. */ + defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR); + defn->args.argnames = (U_CHAR *) ""; + } + + defn->line = line; + defn->file = file; + + /* OP is null if this is a predefinition */ + defn->predefined = predefinition; + mdef.defn = defn; + mdef.symnam = symname; + mdef.symlen = sym_length; + + return mdef; + +nope: + mdef.defn = 0; + return mdef; +} + +/* + * Parse a macro argument and append the info on PFILE's token_buffer. + * REST_ARGS means to absorb the rest of the args. + * Return nonzero to indicate a syntax error. + */ + +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; + + /* Try to parse as much of the argument as exists at this + input stack level. */ + 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 we've hit end of file, it's an error (reported by caller). + Ditto if it's the end of cpp_expand_to_buffer text. + If we've hit end of macro, just continue. */ + 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 we've returned to lowest level and + we aren't absorbing all args */ + if (paren == 0 && rest_args == 0) + goto found; + break; + found: + /* Remove ',' or ')' from argument buffer. */ + 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; +} + +/* Turn newlines to spaces in the string of length LENGTH at START, + except inside of string constants. + The string is copied into itself with its beginning staying fixed. */ + +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 '\"': + /* Notice and skip strings, so that we don't + delete newlines in them. */ + { + 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", +}; + +/* + * expand things like __FILE__. Place the expansion into the output + * buffer *without* rescanning. + */ + +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; + } +} + +/* Expand a macro call. + HP points to the symbol that is the macro being called. + Put the result of expansion onto the input stack + so that subsequent input by our caller will use it. + + If macro wants arguments, caller has already verified that + an argument list follows; arguments come from the input stack. */ + +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 + /* This macro is being used inside a #if, which means it must be */ + /* recorded as a precondition. */ + 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); + + /* Check for and handle special symbols. */ + 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; + } + + /* Parse all the macro args that are supplied. I counts them. + The first NARGS args are stored in ARGS. + The rest are discarded. If rest_args is set then we assume + macarg absorbed the rest of the args. */ + i = 0; + rest_args = 0; + rest_args = 0; + FORWARD (1); /* Discard open-parenthesis before first arg. */ + do + { + if (rest_args) + continue; + if (i < nargs || (nargs == 0 && i == 0)) + { + /* if we are working on last arg which absorbs rest of args... */ + 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; /* FIXME */ + } + 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 we got one arg but it was just whitespace, call that 0 args. */ + if (i == 1) + { + register U_CHAR *bp = ARG_BASE + args[0].raw; + register U_CHAR *lim = bp + args[0].raw_length; + /* cpp.texi says for foo ( ) we provide one argument. + However, if foo wants just 0 arguments, treat this as 0. */ + if (nargs == 0) + while (bp != lim && is_space[*bp]) + bp++; + if (bp == lim) + i = 0; + } + + /* Don't output an error message if we have already output one for + a parse error above. */ + rest_zero = 0; + if (nargs == 0 && i > 0) + { + cpp_error (pfile, "arguments given to macro `%s'", hp->name); + } + else if (i < nargs) + { + /* traditional C allows foo() if foo wants one argument. */ + if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile)) + ; + /* the rest args token is allowed to absorb 0 tokens */ + 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 macro wants zero args, we parsed the arglist for checking only. + Read directly from the macro definition. */ + if (nargs <= 0) + { + xbuf = defn->expansion; + xbuf_len = defn->length; + } + else + { + register U_CHAR *exp = defn->expansion; + register int offset; /* offset in expansion, + copied a piece at a time */ + register int totlen; /* total amount of exp buffer filled so far */ + + register struct reflist *ap, *last_ap; + + /* Macro really takes args. Compute the expansion of this call. */ + + /* Compute length in characters of the macro's expansion. + Also count number of times each arg is used. */ + xbuf_len = defn->length; + for (ap = defn->pattern; ap != NULL; ap = ap->next) + { + if (ap->stringify) + { + register struct argdata *arg = &args[ap->argno]; + /* Stringify if it hasn't already been */ + if (arg->stringified_length < 0) + { + int arglen = arg->raw_length; + int escaped = 0; + int in_string = 0; + int c; + /* Initially need_space is -1. Otherwise, 1 means the + previous character was a space, but we suppressed it; + 0 means the previous character was a non-space. */ + int need_space = -1; + i = 0; + arg->stringified = CPP_WRITTEN (pfile); + if (!CPP_TRADITIONAL (pfile)) + CPP_PUTC (pfile, '\"'); /* insert beginning quote */ + for (; i < arglen; i++) + { + c = (ARG_BASE + arg->raw)[i]; + + if (!in_string) + { + /* Internal sequences of whitespace are + replaced by one space except within + a string or char token. */ + if (is_space[c]) + { + if (CPP_WRITTEN (pfile) > (unsigned) arg->stringified + && (CPP_PWRITTEN (pfile))[-1] == '\r') + { + /* "\r " escape markers are removed */ + 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; + } + + /* Escape these chars */ + 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, '\"'); /* insert ending quote */ + 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)) + /* Add 4 for two newline-space markers to prevent + token concatenation. */ + xbuf_len += args[ap->argno].raw_length + 4; + else + { + /* We have an ordinary (expanded) occurrence of the arg. + So compute its expansion, if we have not already. */ + 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; + } + + /* Add 4 for two newline-space markers to prevent + token concatenation. */ + 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); + + /* Generate in XBUF the complete expansion + with arguments substituted in. + TOTLEN is the total size generated so far. + OFFSET is the index in the definition + of where we are copying from. */ + 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; + + /* Add chars to XBUF. */ + for (i = 0; i < ap->nchars; i++, offset++) + xbuf[totlen++] = exp[offset]; + + /* If followed by an empty rest arg with concatenation, + delete the last run of nonwhite chars. */ + if (rest_zero && totlen > count_before + && ((ap->rest_args && ap->raw_before) + || (last_ap != NULL && last_ap->rest_args + && last_ap->raw_after))) + { + /* Delete final whitespace. */ + while (totlen > count_before && is_space[xbuf[totlen - 1]]) + totlen--; + + /* Delete the nonwhites before them. */ + 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) + { + /* Arg is concatenated after: delete trailing whitespace, + whitespace markers, and no-reexpansion markers. */ + 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; + } + } + + /* Delete any no-reexpansion marker that precedes + an identifier at the beginning of the argument. */ + 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 a macro argument with newlines is used multiple times, + then only expand the newlines once. This avoids creating + output lines which don't correspond to any input line, + which confuses gdb and gcov. */ + if (arg->use_count > 1 && arg->newlines > 0) + { + /* Don't bother doing change_newlines for subsequent + uses of arg. */ + 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; + } + } + + /* if there is anything left of the definition + after handling the arg list, copy that in too. */ + + for (i = offset; i < defn->length; i++) + { + /* if we've reached the end of the macro */ + 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--; + + /* Now put the expansion on the input stack + so our caller will commence reading from it. */ + push_macro_expansion (pfile, xbuf, xbuf_len, hp); + CPP_BUFFER (pfile)->has_escapes = 1; + + /* Pop the space we've used in the token_buffer for argument expansion. */ + CPP_SET_WRITTEN (pfile, old_written); + + /* Recursive macro use sometimes works traditionally. + #define foo(x,y) bar (x (y,0), y) + foo (foo, baz) */ + + if (!CPP_TRADITIONAL (pfile)) + hp->type = T_DISABLED; +} + +/* Return 1 iff a token ending in C1 followed directly by a token C2 + could cause mis-tokenization. */ + +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; /* could extend a pre-processing number */ + goto letter; + + case 'L': + if (c2 == '\'' || c2 == '\"') + return 1; /* Could turn into L"xxx" or L'xxx'. */ + 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: + /* We're in the middle of either a name or a pre-processing number. */ + 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; + + /* The first chars of the expansion should be a "\r " added by + collect_expansion. This is to prevent accidental token-pasting + between the text preceding the macro invocation, and the macro + expansion text. + + We would like to avoid adding unneeded spaces (for the sake of + tools that use cpp, such as imake). In some common cases we can + tell that it is safe to omit the space. + + The character before the macro invocation cannot have been an + idchar (or else it would have been pasted with the idchars of + the macro name). Therefore, if the first non-space character + of the expansion is an idchar, we do not need the extra space + to prevent token pasting. + + Also, we don't need the extra space if the first char is '(', + or some other (less common) characters. */ + + if (xbuf[0] == '\r' && xbuf[1] == ' ' + && (is_idchar[xbuf[2]] || xbuf[2] == '(' || xbuf[2] == '\'' + || xbuf[2] == '\"')) + mbuf->cur += 2; + + /* Likewise, avoid the extra space at the end of the macro expansion + if this is safe. We can do a better job here since we can know + what the next char will be. */ + 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; + } +} + +/* Return zero if two DEFINITIONs are isomorphic. */ + +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); +} + +/* Return 1 if two parts of two macro definitions are effectively different. + One of the parts starts at BEG1 and has LEN1 chars; + the other has LEN2 chars at BEG2. + Any sequence of whitespace matches any other sequence of whitespace. + FIRST means these parts are the first of a macro definition; + so ignore leading whitespace entirely. + LAST means these parts are the last of a macro definition; + so ignore trailing whitespace entirely. */ + +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); +} + +/* Dump the definition of macro MACRO on stdout. The format is suitable + to be read back in again. */ + +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, ' '); + + /* The first and last two characters of a macro expansion are + always "\r "; this needs to be trimmed out. + So we need length-4 chars of space, plus one for the NUL. */ + 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; + + /* First extract the argument list. */ + 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; /* skip the space after the comma */ + } + } + + /* Now print out the argument list. */ + 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); + + /* Now the definition. */ + x = defn->expansion; + for (r = defn->pattern; r; r = r->next) + { + i = r->nchars; + if (*x == '\r') x += 2, i -= 2; + /* i chars for macro text, plus the length of the macro + argument name, plus one for a stringify marker, plus two for + each concatenation marker. */ + 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); + } +} |