static void collect_arguments (symbol *sym, struct obstack *argptr, struct obstack *arguments) { token_data td; token_data *tdp; bool more_args; bool groks_macro_args = SYMBOL_MACRO_ARGS (sym); TOKEN_DATA_TYPE (&td) = TOKEN_TEXT; TOKEN_DATA_TEXT (&td) = SYMBOL_NAME (sym); tdp = (token_data *) obstack_copy (arguments, &td, sizeof td); obstack_ptr_grow (argptr, tdp); if (peek_token () == TOKEN_OPEN) { next_token (&td, NULL); /* gobble parenthesis */ do { more_args = expand_argument (arguments, &td); if (!groks_macro_args && TOKEN_DATA_TYPE (&td) == TOKEN_FUNC) { TOKEN_DATA_TYPE (&td) = TOKEN_TEXT; TOKEN_DATA_TEXT (&td) = (char *) ""; } tdp = (token_data *) obstack_copy (arguments, &td, sizeof td); obstack_ptr_grow (argptr, tdp); } while (more_args); } }
const char * predefined_attribute (const char *key, int *ptr_argc, token_data **argv, boolean lowercase) { var_stack *next; char *cp, *sp, *lower; int i, j, special_chars; boolean found = FALSE; i = 1; while (i<*ptr_argc) { special_chars = 0; sp = TOKEN_DATA_TEXT (argv[i]); while (IS_GROUP (*sp)) { sp++; special_chars++; } cp = strchr (sp, '='); if ((cp == NULL && strcasecmp (sp, key) == 0) || (cp != NULL && strncasecmp (sp, key, strlen (key)) == 0 && *(sp + strlen (key)) == '=')) { found = TRUE; next = (var_stack *) xmalloc (sizeof (var_stack)); next->prev = tag_attr; if (cp) { next->text = (char *) xmalloc (special_chars + strlen (cp+1) + 1); if (special_chars) strncpy (next->text, TOKEN_DATA_TEXT (argv[i]), special_chars); strcpy (next->text+special_chars, cp+1); } else next->text = xstrdup (key); tag_attr = next; if (lowercase) for (lower=tag_attr->text; *lower != '\0'; lower++) *lower = tolower (*lower); /* remove this attribute from argv[]. */ for (j=i+1; j<=*ptr_argc; j++) argv[j-1] = argv[j]; (*ptr_argc)--; } i++; } return (found ? tag_attr->text : NULL ); }
static void print_token (const char *s, token_type t, token_data *td) { fprintf (stderr, "%s: ", s); switch (t) { /* TOKSW */ case TOKEN_SIMPLE: fprintf (stderr, "char:"); break; case TOKEN_WORD: fprintf (stderr, "word:"); break; case TOKEN_STRING: fprintf (stderr, "string:"); break; case TOKEN_MACDEF: fprintf (stderr, "macro: 0x%x\n", TOKEN_DATA_FUNC (td)); break; case TOKEN_EOF: fprintf (stderr, "eof\n"); break; } fprintf (stderr, "\t\"%s\"\n", TOKEN_DATA_TEXT (td)); }
const char * push_string_finish (read_type expansion) { const char *ret = NULL; if (next == NULL) return NULL; if (obstack_object_size (current_input) > 0) { obstack_1grow (current_input, '\0'); next->u.u_s.start = (unsigned char *) obstack_finish (current_input); if (expansion == READ_ATTR_VERB || expansion == READ_ATTR_ASIS || expansion == READ_BODY) { TOKEN_DATA_TYPE (&token_read) = TOKEN_TEXT; TOKEN_DATA_TEXT (&token_read) = xstrdup ((char *) next->u.u_s.start); next->u.u_s.current = next->u.u_s.start + strlen ((char *) next->u.u_s.start); } else next->u.u_s.current = next->u.u_s.start; next->prev = isp; isp = next; ret = (char *) isp->u.u_s.start; /* for immediate use only */ } else obstack_free (current_input, next); /* people might leave garbage on it. */ next = NULL; return ret; }
static void expand_token (struct obstack *obs, token_type t, token_data *td, int line) { symbol *sym; switch (t) { /* TOKSW */ case TOKEN_EOF: case TOKEN_MACDEF: break; case TOKEN_OPEN: case TOKEN_COMMA: case TOKEN_CLOSE: case TOKEN_SIMPLE: case TOKEN_STRING: shipout_text (obs, TOKEN_DATA_TEXT (td), strlen (TOKEN_DATA_TEXT (td)), line); break; case TOKEN_WORD: sym = lookup_symbol (TOKEN_DATA_TEXT (td), SYMBOL_LOOKUP); if (sym == NULL || SYMBOL_TYPE (sym) == TOKEN_VOID || (SYMBOL_TYPE (sym) == TOKEN_FUNC && SYMBOL_BLIND_NO_ARGS (sym) && peek_token () != TOKEN_OPEN)) { #ifdef ENABLE_CHANGEWORD shipout_text (obs, TOKEN_DATA_ORIG_TEXT (td), strlen (TOKEN_DATA_ORIG_TEXT (td)), line); #else shipout_text (obs, TOKEN_DATA_TEXT (td), strlen (TOKEN_DATA_TEXT (td)), line); #endif } else expand_macro (sym); break; default: M4ERROR ((warning_status, 0, "INTERNAL ERROR: bad token type in expand_token ()")); abort (); } }
boolean bad_argc (token_data *name, int argc, int min, int max) { boolean isbad = FALSE; if (min > 0 && argc < min) { if (!suppress_warnings) MP4HERROR ((warning_status, 0, _("Warning:%s:%d: Too few arguments to built-in `%s'"), CURRENT_FILE_LINE, TOKEN_DATA_TEXT (name))); isbad = TRUE; } else if (max > 0 && argc > max && !suppress_warnings) { MP4HERROR ((warning_status, 0, _("Warning:%s:%d: Excess arguments to built-in `%s' ignored"), CURRENT_FILE_LINE, TOKEN_DATA_TEXT (name))); } return isbad; }
boolean numeric_arg (token_data *macro, const char *arg, boolean warn, int *valuep) { char *endp; if (*arg == 0 || (*valuep = strtol (skip_space (arg), &endp, 10), *skip_space (endp) != 0)) { if (warn) MP4HERROR ((warning_status, 0, _("Warning:%s:%d: Argument `%s' non-numeric in the <%s> tag"), CURRENT_FILE_LINE, arg, TOKEN_DATA_TEXT (macro))); return FALSE; } return TRUE; }
void trace_pre (const char *name, int id, int argc, token_data **argv) { int i; const builtin *bp; trace_header (id); trace_format ("%s", name); if (argc > 1 && (debug_level & DEBUG_TRACE_ARGS)) { trace_format ("("); for (i = 1; i < argc; i++) { if (i != 1) trace_format (", "); switch (TOKEN_DATA_TYPE (argv[i])) { case TOKEN_TEXT: trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv[i])); break; case TOKEN_FUNC: bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[i])); if (bp == NULL) { M4ERROR ((warning_status, 0, "\ INTERNAL ERROR: builtin not found in builtin table! (trace_pre ())")); abort (); } trace_format ("<%s>", bp->name); break; case TOKEN_VOID: default: M4ERROR ((warning_status, 0, "INTERNAL ERROR: bad token data type (trace_pre ())")); abort (); } }
token_type next_token (token_data *td) { int ch; int quote_level; token_type type; #ifdef ENABLE_CHANGEWORD int startpos; char *orig_text = 0; #endif obstack_free (&token_stack, token_bottom); obstack_1grow (&token_stack, '\0'); token_bottom = obstack_finish (&token_stack); ch = peek_input (); if (ch == CHAR_EOF) { return TOKEN_EOF; #ifdef DEBUG_INPUT fprintf (stderr, "next_token -> EOF\n"); #endif } if (ch == CHAR_MACRO) { init_macro_token (td); (void) next_char (); return TOKEN_MACDEF; } (void) next_char (); if (MATCH (ch, bcomm.string)) { obstack_grow (&token_stack, bcomm.string, bcomm.length); while ((ch = next_char ()) != CHAR_EOF && !MATCH (ch, ecomm.string)) obstack_1grow (&token_stack, ch); if (ch != CHAR_EOF) obstack_grow (&token_stack, ecomm.string, ecomm.length); type = TOKEN_STRING; } #ifdef ENABLE_CHANGEWORD else if (default_word_regexp && (isalpha (ch) || ch == '_')) #else else if (isalpha (ch) || ch == '_') #endif { obstack_1grow (&token_stack, ch); while ((ch = peek_input ()) != CHAR_EOF && (isalnum (ch) || ch == '_')) { obstack_1grow (&token_stack, ch); (void) next_char (); } type = TOKEN_WORD; } #ifdef ENABLE_CHANGEWORD else if (!default_word_regexp && strchr (word_start, ch)) { obstack_1grow (&token_stack, ch); while (1) { ch = peek_input (); if (ch == CHAR_EOF) break; obstack_1grow (&token_stack, ch); startpos = re_search (&word_regexp, obstack_base (&token_stack), obstack_object_size (&token_stack), 0, 0, ®s); if (startpos != 0 || regs.end [0] != obstack_object_size (&token_stack)) { *(((char *) obstack_base (&token_stack) + obstack_object_size (&token_stack)) - 1) = '\0'; break; } next_char (); } obstack_1grow (&token_stack, '\0'); orig_text = obstack_finish (&token_stack); if (regs.start[1] != -1) obstack_grow (&token_stack,orig_text + regs.start[1], regs.end[1] - regs.start[1]); else obstack_grow (&token_stack, orig_text,regs.end[0]); type = TOKEN_WORD; } #endif /* ENABLE_CHANGEWORD */ else if (!MATCH (ch, lquote.string)) { type = TOKEN_SIMPLE; obstack_1grow (&token_stack, ch); } else { quote_level = 1; while (1) { ch = next_char (); if (ch == CHAR_EOF) M4ERROR ((EXIT_FAILURE, 0, "ERROR: EOF in string")); if (MATCH (ch, rquote.string)) { if (--quote_level == 0) break; obstack_grow (&token_stack, rquote.string, rquote.length); } else if (MATCH (ch, lquote.string)) { quote_level++; obstack_grow (&token_stack, lquote.string, lquote.length); } else obstack_1grow (&token_stack, ch); } type = TOKEN_STRING; } obstack_1grow (&token_stack, '\0'); TOKEN_DATA_TYPE (td) = TOKEN_TEXT; TOKEN_DATA_TEXT (td) = obstack_finish (&token_stack); #ifdef ENABLE_CHANGEWORD if (orig_text == NULL) orig_text = TOKEN_DATA_TEXT (td); TOKEN_DATA_ORIG_TEXT (td) = orig_text; #endif #ifdef DEBUG_INPUT fprintf (stderr, "next_token -> %d (%s)\n", type, TOKEN_DATA_TEXT (td)); #endif return type; }
token_type next_token (token_data *td) { int ch; int quote_level; token_type type; obstack_free (&token_stack, token_bottom); obstack_1grow (&token_stack, '\0'); token_bottom = obstack_finish (&token_stack); ch = peek_input (); if (ch == CHAR_EOF) { return TOKEN_EOF; #ifdef DEBUG_INPUT fprintf (stderr, "next_token -> EOF\n"); #endif } if (ch == CHAR_MACRO) { init_macro_token (td); (void) next_char (); return TOKEN_MACDEF; } (void) next_char (); if (MATCH (ch, bcomm)) { obstack_grow (&token_stack, bcomm, len_bcomm); while ((ch = next_char ()) != CHAR_EOF && !MATCH (ch, ecomm)) obstack_1grow (&token_stack, ch); if (ch != CHAR_EOF) obstack_grow (&token_stack, ecomm, len_ecomm); type = TOKEN_STRING; } else if (isalpha (ch) || ch == '_') { obstack_1grow (&token_stack, ch); while ((ch = peek_input ()) != CHAR_EOF && (isalnum (ch) || ch == '_')) { obstack_1grow (&token_stack, ch); (void) next_char (); } type = TOKEN_WORD; } else if (!MATCH (ch, lquote)) { type = TOKEN_SIMPLE; obstack_1grow (&token_stack, ch); } else { quote_level = 1; while (1) { ch = next_char (); if (ch == CHAR_EOF) fatal ("EOF in string"); if (MATCH (ch, rquote)) { if (--quote_level == 0) break; obstack_grow (&token_stack, rquote, len_rquote); } else if (MATCH (ch, lquote)) { quote_level++; obstack_grow (&token_stack, lquote, len_lquote); } else obstack_1grow (&token_stack, ch); } type = TOKEN_STRING; } obstack_1grow (&token_stack, '\0'); TOKEN_DATA_TYPE (td) = TOKEN_TEXT; TOKEN_DATA_TEXT (td) = obstack_finish (&token_stack); #ifdef DEBUG_INPUT fprintf (stderr, "next_token -> %d (%s)\n", type, TOKEN_DATA_TEXT (td)); #endif return type; }
token_type next_token (token_data *td, read_type expansion, boolean in_string) { int ch; token_type type = TOKEN_NONE; int quote_level; if (TOKEN_DATA_TYPE (&token_read) != TOKEN_VOID) { type = TOKEN_STRING; obstack_grow (&token_stack, TOKEN_DATA_TEXT (&token_read), strlen (TOKEN_DATA_TEXT (&token_read))); xfree ((voidstar) TOKEN_DATA_TEXT (&token_read)); TOKEN_DATA_TYPE (&token_read) = TOKEN_VOID; } while (type == TOKEN_NONE) { obstack_free (&token_stack, token_bottom); obstack_1grow (&token_stack, '\0'); token_bottom = obstack_finish (&token_stack); ch = peek_input (); if (ch == CHAR_EOF) /* EOF */ { #ifdef DEBUG_INPUT fprintf (stderr, "next_token -> EOF\n"); #endif return TOKEN_EOF; } if (ch == CHAR_MACRO) /* MACRO TOKEN */ { init_macro_token (td); (void) next_char (); #ifdef DEBUG_INPUT print_token("next_token", TOKEN_MACDEF, td); #endif return TOKEN_MACDEF; } (void) next_char (); if (IS_TAG(ch)) /* ESCAPED WORD */ { if (lquote.length > 0 && MATCH (ch, lquote.string)) { if (visible_quotes || expansion == READ_ATTR_VERB || expansion == READ_ATTR_ASIS || expansion == READ_BODY) obstack_grow (&token_stack, lquote.string, lquote.length); while ((ch = next_char ()) != CHAR_EOF) { if (rquote.length > 0 && MATCH (ch, rquote.string)) break; obstack_1grow (&token_stack, ch); } if (visible_quotes || expansion == READ_ATTR_VERB || expansion == READ_ATTR_ASIS || expansion == READ_BODY) { obstack_grow (&token_stack, rquote.string, rquote.length); type = TOKEN_STRING; } else type = TOKEN_QUOTED; } else { obstack_1grow (&token_stack, ch); if ((ch = peek_input ()) != CHAR_EOF) { if (ch == '/') { obstack_1grow (&token_stack, '/'); (void) next_char (); ch = peek_input (); } if (IS_ALPHA(ch)) { ch = next_char (); obstack_1grow (&token_stack, ch); while ((ch = next_char ()) != CHAR_EOF && IS_ALNUM(ch)) { obstack_1grow (&token_stack, ch); } if (ch == '*') { obstack_1grow (&token_stack, ch); ch = peek_input (); } else unget_input(ch); if (IS_SPACE(ch) || IS_CLOSE(ch) || IS_SLASH (ch)) type = TOKEN_WORD; else type = TOKEN_STRING; } else type = TOKEN_STRING; } else type = TOKEN_SIMPLE; /* escape before eof */ } } else if (IS_CLOSE(ch)) { obstack_1grow (&token_stack, ch); type = TOKEN_SIMPLE; } else if (IS_ENTITY(ch)) /* entity */ { obstack_1grow (&token_stack, ch); if ((ch = peek_input ()) != CHAR_EOF) { if (IS_ALPHA(ch)) { ch = next_char (); obstack_1grow (&token_stack, ch); while ((ch = next_char ()) != CHAR_EOF && IS_ALNUM(ch)) { obstack_1grow (&token_stack, ch); } if (ch == ';') { obstack_1grow (&token_stack, ch); type = TOKEN_ENTITY; } else { type = TOKEN_STRING; unget_input(ch); } } else type = TOKEN_STRING; } else type = TOKEN_SIMPLE; /* escape before eof */ } else if (eolcomm.length > 0 && MATCH (ch, eolcomm.string)) skip_line (); else if (expansion == READ_BODY) { if (ch == '"') obstack_1grow (&token_stack, CHAR_QUOTE); else obstack_1grow (&token_stack, ch); while ((ch = next_char ()) != CHAR_EOF && ! IS_TAG(ch) && ! IS_CLOSE (ch)) { if (eolcomm.length > 0 && MATCH (ch, eolcomm.string)) { skip_line (); ch = CHAR_EOF; break; } if (ch == '"') obstack_1grow (&token_stack, CHAR_QUOTE); else obstack_1grow (&token_stack, ch); } unget_input(ch); type = TOKEN_STRING; } /* Below we know that expansion != READ_BODY */ else if (IS_ALPHA(ch)) { obstack_1grow (&token_stack, ch); while ((ch = next_char ()) != CHAR_EOF && (IS_ALNUM(ch))) { obstack_1grow (&token_stack, ch); } if (ch == '*') { obstack_1grow (&token_stack, ch); ch = peek_input (); } else unget_input(ch); type = TOKEN_STRING; } else if (IS_RQUOTE(ch)) { MP4HERROR ((EXIT_FAILURE, 0, "INTERNAL ERROR: CHAR_RQUOTE found.")); } else if (IS_LQUOTE(ch)) /* QUOTED STRING */ { quote_level = 1; while (1) { ch = next_char (); if (ch == CHAR_EOF) MP4HERROR ((EXIT_FAILURE, 0, "INTERNAL ERROR: EOF in string")); if (IS_BGROUP(ch) || IS_EGROUP(ch)) continue; else if (IS_RQUOTE(ch)) { quote_level--; if (quote_level == 0) break; } else if (IS_LQUOTE(ch)) quote_level++; else obstack_1grow (&token_stack, ch); } type = TOKEN_QUOTED; } else if (IS_BGROUP(ch)) /* BEGIN GROUP */ type = TOKEN_BGROUP; else if (IS_EGROUP(ch)) /* END GROUP */ type = TOKEN_EGROUP; else if (ch == '"') /* QUOTED STRING */ { switch (expansion) { case READ_NORMAL: obstack_1grow (&token_stack, CHAR_QUOTE); type = TOKEN_SIMPLE; break; case READ_ATTRIBUTE: case READ_ATTR_VERB: type = TOKEN_QUOTE; break; case READ_ATTR_ASIS: case READ_ATTR_QUOT: obstack_1grow (&token_stack, '"'); type = TOKEN_QUOTE; break; default: MP4HERROR ((warning_status, 0, "INTERNAL ERROR: Unknown expansion type")); exit (1); } } else if (ch == '\\') { switch (expansion) { case READ_NORMAL: obstack_1grow (&token_stack, ch); type = TOKEN_SIMPLE; break; case READ_ATTRIBUTE: case READ_ATTR_QUOT: ch = next_char(); if (ch == 'n') obstack_1grow (&token_stack, '\n'); else if (ch == 't') obstack_1grow (&token_stack, '\t'); else if (ch == 'r') obstack_1grow (&token_stack, '\r'); else if (ch == '\\') obstack_1grow (&token_stack, ch); else if (ch == '"' && in_string) obstack_1grow (&token_stack, CHAR_QUOTE); else { if (!(exp_flags & EXP_STD_BSLASH)) obstack_1grow (&token_stack, '\\'); obstack_1grow (&token_stack, ch); } type = TOKEN_STRING; break; case READ_ATTR_VERB: ch = next_char(); if (ch == '"' && in_string) obstack_1grow (&token_stack, CHAR_QUOTE); else { obstack_1grow (&token_stack, '\\'); obstack_1grow (&token_stack, ch); } type = TOKEN_STRING; break; case READ_ATTR_ASIS: obstack_1grow (&token_stack, ch); ch = next_char(); obstack_1grow (&token_stack, ch); type = TOKEN_STRING; break; default: MP4HERROR ((warning_status, 0, "INTERNAL ERROR: Unknown expansion type")); exit (1); } } else /* EVERYTHING ELSE */ { obstack_1grow (&token_stack, ch); if (IS_OTHER(ch) || IS_NUM(ch)) type = TOKEN_STRING; else if (IS_SPACE(ch)) { while ((ch = next_char ()) != CHAR_EOF && IS_SPACE(ch)) obstack_1grow (&token_stack, ch); unget_input(ch); type = TOKEN_SPACE; } else type = TOKEN_SIMPLE; } } obstack_1grow (&token_stack, '\0'); TOKEN_DATA_TYPE (td) = TOKEN_TEXT; TOKEN_DATA_TEXT (td) = obstack_finish (&token_stack); #ifdef DEBUG_INPUT print_token("next_token", type, td); #endif return type; }
static int print_token (const char *s, token_type t, token_data *td) { fprintf (stderr, "%s: ", s); switch (t) { /* TOKSW */ case TOKEN_SIMPLE: fprintf (stderr, "char\t\"%s\"\n", TOKEN_DATA_TEXT (td)); break; case TOKEN_WORD: fprintf (stderr, "word\t\"%s\"\n", TOKEN_DATA_TEXT (td)); break; case TOKEN_ENTITY: fprintf (stderr, "entity\t\"%s\"\n", TOKEN_DATA_TEXT (td)); break; case TOKEN_STRING: fprintf (stderr, "string\t\"%s\"\n", TOKEN_DATA_TEXT (td)); break; case TOKEN_QUOTED: fprintf (stderr, "quoted\t\"%s\"\n", TOKEN_DATA_TEXT (td)); break; case TOKEN_BGROUP: fprintf (stderr, "bgroup\n"); break; case TOKEN_EGROUP: fprintf (stderr, "egroup\n"); break; case TOKEN_QUOTE: fprintf (stderr, "quote\n"); break; case TOKEN_SPACE: fprintf (stderr, "space\t\"%s\"\n", TOKEN_DATA_TEXT (td)); break; case TOKEN_MACDEF: fprintf (stderr, "macro 0x%x\n", (int)TOKEN_DATA_FUNC (td)); break; case TOKEN_EOF: fprintf (stderr, "eof\n"); break; case TOKEN_NONE: fprintf (stderr, "none\n"); break; default: MP4HERROR ((warning_status, 0, "INTERNAL ERROR: unknown token in print_token")); break; } return 0; }
token_type next_token (token_data *td, int *line) { int ch; int quote_level; token_type type; #ifdef ENABLE_CHANGEWORD int startpos; char *orig_text = NULL; #endif const char *file; int dummy; obstack_free (&token_stack, token_bottom); if (!line) line = &dummy; /* Can't consume character until after CHAR_MACRO is handled. */ ch = peek_input (); if (ch == CHAR_EOF) { #ifdef DEBUG_INPUT xfprintf (stderr, "next_token -> EOF\n"); #endif next_char (); return TOKEN_EOF; } if (ch == CHAR_MACRO) { init_macro_token (td); next_char (); #ifdef DEBUG_INPUT xfprintf (stderr, "next_token -> MACDEF (%s)\n", find_builtin_by_addr (TOKEN_DATA_FUNC (td))->name); #endif return TOKEN_MACDEF; } next_char (); /* Consume character we already peeked at. */ file = current_file; *line = current_line; if (MATCH (ch, bcomm.string, true)) { obstack_grow (&token_stack, bcomm.string, bcomm.length); while ((ch = next_char ()) != CHAR_EOF && !MATCH (ch, ecomm.string, true)) obstack_1grow (&token_stack, ch); if (ch != CHAR_EOF) obstack_grow (&token_stack, ecomm.string, ecomm.length); else /* current_file changed to "" if we see CHAR_EOF, use the previous value we stored earlier. */ M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, *line, "ERROR: end of file in comment")); type = TOKEN_STRING; } else if (default_word_regexp && (isalpha (ch) || ch == '_')) { obstack_1grow (&token_stack, ch); while ((ch = peek_input ()) != CHAR_EOF && (isalnum (ch) || ch == '_')) { obstack_1grow (&token_stack, ch); next_char (); } type = TOKEN_WORD; } #ifdef ENABLE_CHANGEWORD else if (!default_word_regexp && word_regexp.fastmap[ch]) { obstack_1grow (&token_stack, ch); while (1) { ch = peek_input (); if (ch == CHAR_EOF) break; obstack_1grow (&token_stack, ch); startpos = re_search (&word_regexp, (char *) obstack_base (&token_stack), obstack_object_size (&token_stack), 0, 0, ®s); if (startpos || regs.end [0] != (regoff_t) obstack_object_size (&token_stack)) { *(((char *) obstack_base (&token_stack) + obstack_object_size (&token_stack)) - 1) = '\0'; break; } next_char (); } obstack_1grow (&token_stack, '\0'); orig_text = (char *) obstack_finish (&token_stack); if (regs.start[1] != -1) obstack_grow (&token_stack,orig_text + regs.start[1], regs.end[1] - regs.start[1]); else obstack_grow (&token_stack, orig_text,regs.end[0]); type = TOKEN_WORD; } #endif /* ENABLE_CHANGEWORD */ else if (!MATCH (ch, lquote.string, true)) { switch (ch) { case '(': type = TOKEN_OPEN; break; case ',': type = TOKEN_COMMA; break; case ')': type = TOKEN_CLOSE; break; default: type = TOKEN_SIMPLE; break; } obstack_1grow (&token_stack, ch); } else { bool fast = lquote.length == 1 && rquote.length == 1; quote_level = 1; while (1) { /* Try scanning a buffer first. */ const char *buffer = (isp && isp->type == INPUT_STRING ? isp->u.u_s.string : NULL); if (buffer && *buffer) { size_t len = isp->u.u_s.end - buffer; const char *p = buffer; do { p = (char *) memchr2 (p, *lquote.string, *rquote.string, buffer + len - p); } while (p && fast && (*p++ == *rquote.string ? --quote_level : ++quote_level)); if (p) { if (fast) { assert (!quote_level); obstack_grow (&token_stack, buffer, p - buffer - 1); isp->u.u_s.string += p - buffer; break; } obstack_grow (&token_stack, buffer, p - buffer); ch = to_uchar (*p); isp->u.u_s.string += p - buffer + 1; } else { obstack_grow (&token_stack, buffer, len); isp->u.u_s.string += len; continue; } } /* Fall back to a byte. */ else ch = next_char (); if (ch == CHAR_EOF) /* current_file changed to "" if we see CHAR_EOF, use the previous value we stored earlier. */ M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, *line, "ERROR: end of file in string")); if (MATCH (ch, rquote.string, true)) { if (--quote_level == 0) break; obstack_grow (&token_stack, rquote.string, rquote.length); } else if (MATCH (ch, lquote.string, true)) { quote_level++; obstack_grow (&token_stack, lquote.string, lquote.length); } else obstack_1grow (&token_stack, ch); } type = TOKEN_STRING; } obstack_1grow (&token_stack, '\0'); TOKEN_DATA_TYPE (td) = TOKEN_TEXT; TOKEN_DATA_TEXT (td) = (char *) obstack_finish (&token_stack); #ifdef ENABLE_CHANGEWORD if (orig_text == NULL) orig_text = TOKEN_DATA_TEXT (td); TOKEN_DATA_ORIG_TEXT (td) = orig_text; #endif #ifdef DEBUG_INPUT xfprintf (stderr, "next_token -> %s (%s)\n", token_type_string (type), TOKEN_DATA_TEXT (td)); #endif return type; }
static bool expand_argument (struct obstack *obs, token_data *argp) { token_type t; token_data td; char *text; int paren_level; const char *file = current_file; int line = current_line; TOKEN_DATA_TYPE (argp) = TOKEN_VOID; /* Skip leading white space. */ do { t = next_token (&td, NULL); } while (t == TOKEN_SIMPLE && isspace (to_uchar (*TOKEN_DATA_TEXT (&td)))); paren_level = 0; while (1) { switch (t) { /* TOKSW */ case TOKEN_COMMA: case TOKEN_CLOSE: if (paren_level == 0) { /* The argument MUST be finished, whether we want it or not. */ obstack_1grow (obs, '\0'); text = (char *) obstack_finish (obs); if (TOKEN_DATA_TYPE (argp) == TOKEN_VOID) { TOKEN_DATA_TYPE (argp) = TOKEN_TEXT; TOKEN_DATA_TEXT (argp) = text; } return t == TOKEN_COMMA; } /* fallthru */ case TOKEN_OPEN: case TOKEN_SIMPLE: text = TOKEN_DATA_TEXT (&td); if (*text == '(') paren_level++; else if (*text == ')') paren_level--; expand_token (obs, t, &td, line); break; case TOKEN_EOF: /* current_file changed to "" if we see TOKEN_EOF, use the previous value we stored earlier. */ M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, line, "ERROR: end of file in argument list")); break; case TOKEN_WORD: case TOKEN_STRING: expand_token (obs, t, &td, line); break; case TOKEN_MACDEF: if (obstack_object_size (obs) == 0) { TOKEN_DATA_TYPE (argp) = TOKEN_FUNC; TOKEN_DATA_FUNC (argp) = TOKEN_DATA_FUNC (&td); } break; default: M4ERROR ((warning_status, 0, "INTERNAL ERROR: bad token type in expand_argument ()")); abort (); } t = next_token (&td, NULL); } }