diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-05-17 18:21:10 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-05-17 18:31:30 +0300 |
commit | 6ca1d898180d9f6a6b4b08ce72607c3d7971f4e9 (patch) | |
tree | 865a89ca2e0dbdf633d0138f7d799f6d8ca63f4d /contrib/tools/bison | |
parent | ce74f15f22c2159c7fbb402a2804cc463fb7698b (diff) | |
download | ydb-6ca1d898180d9f6a6b4b08ce72607c3d7971f4e9.tar.gz |
Move bison/m4 and bison/induced out of contrib/tools/bison
520961d4315ab4738f60613278b7e63765341b85
Diffstat (limited to 'contrib/tools/bison')
-rw-r--r-- | contrib/tools/bison/induced/ya.make | 14 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/builtin.c | 2258 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/cpp.cpp | 3 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/debug.c | 442 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/eval.c | 855 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/format.c | 394 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/freeze.c | 398 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/input.c | 1156 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/m4.c | 695 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/m4.h | 491 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/macro.c | 391 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/output.c | 1017 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/path.c | 205 | ||||
-rw-r--r-- | contrib/tools/bison/m4/src/symtab.c | 401 | ||||
-rw-r--r-- | contrib/tools/bison/m4/ya.make | 36 |
15 files changed, 0 insertions, 8756 deletions
diff --git a/contrib/tools/bison/induced/ya.make b/contrib/tools/bison/induced/ya.make deleted file mode 100644 index a6893e34d6..0000000000 --- a/contrib/tools/bison/induced/ya.make +++ /dev/null @@ -1,14 +0,0 @@ -# This is a special library used to induce licenses onto bison-generated code -# It is intentionally empty. - -LIBRARY() - -LICENSE(GPL-3.0-or-later WITH Bison-exception-2.2) - -LICENSE_TEXTS(.yandex_meta/licenses.list.txt) - -NO_UTIL() - -NO_RUNTIME() - -END() diff --git a/contrib/tools/bison/m4/src/builtin.c b/contrib/tools/bison/m4/src/builtin.c deleted file mode 100644 index 01ede38017..0000000000 --- a/contrib/tools/bison/m4/src/builtin.c +++ /dev/null @@ -1,2258 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2000, 2004, 2006-2013 Free Software - Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* Code for all builtin macros, initialization of symbol table, and - expansion of user defined macros. */ - -#include "m4.h" - -#include "execute.h" -#include "memchr2.h" -#include "progname.h" -#include <contrib/tools/bison/gnulib/src/regex.h> -#include "spawn-pipe.h" -#include "wait-process.h" - -#define ARG(i) (argc > (i) ? TOKEN_DATA_TEXT (argv[i]) : "") - -/* Initialization of builtin and predefined macros. The table - "builtin_tab" is both used for initialization, and by the "builtin" - builtin. */ - -#define DECLARE(name) \ - static void name (struct obstack *, int, token_data **) - -DECLARE (m4___file__); -DECLARE (m4___line__); -DECLARE (m4___program__); -DECLARE (m4_builtin); -DECLARE (m4_changecom); -DECLARE (m4_changequote); -#ifdef ENABLE_CHANGEWORD -DECLARE (m4_changeword); -#endif -DECLARE (m4_debugmode); -DECLARE (m4_debugfile); -DECLARE (m4_decr); -DECLARE (m4_define); -DECLARE (m4_defn); -DECLARE (m4_divert); -DECLARE (m4_divnum); -DECLARE (m4_dnl); -DECLARE (m4_dumpdef); -DECLARE (m4_errprint); -DECLARE (m4_esyscmd); -DECLARE (m4_eval); -DECLARE (m4_format); -DECLARE (m4_ifdef); -DECLARE (m4_ifelse); -DECLARE (m4_include); -DECLARE (m4_incr); -DECLARE (m4_index); -DECLARE (m4_indir); -DECLARE (m4_len); -DECLARE (m4_m4exit); -DECLARE (m4_m4wrap); -DECLARE (m4_maketemp); -DECLARE (m4_mkstemp); -DECLARE (m4_patsubst); -DECLARE (m4_popdef); -DECLARE (m4_pushdef); -DECLARE (m4_regexp); -DECLARE (m4_shift); -DECLARE (m4_sinclude); -DECLARE (m4_substr); -DECLARE (m4_syscmd); -DECLARE (m4_sysval); -DECLARE (m4_traceoff); -DECLARE (m4_traceon); -DECLARE (m4_translit); -DECLARE (m4_undefine); -DECLARE (m4_undivert); - -#undef DECLARE - -static builtin const builtin_tab[] = -{ - - /* name GNUext macros blind function */ - - { "__file__", true, false, false, m4___file__ }, - { "__line__", true, false, false, m4___line__ }, - { "__program__", true, false, false, m4___program__ }, - { "builtin", true, true, true, m4_builtin }, - { "changecom", false, false, false, m4_changecom }, - { "changequote", false, false, false, m4_changequote }, -#ifdef ENABLE_CHANGEWORD - { "changeword", true, false, true, m4_changeword }, -#endif - { "debugmode", true, false, false, m4_debugmode }, - { "debugfile", true, false, false, m4_debugfile }, - { "decr", false, false, true, m4_decr }, - { "define", false, true, true, m4_define }, - { "defn", false, false, true, m4_defn }, - { "divert", false, false, false, m4_divert }, - { "divnum", false, false, false, m4_divnum }, - { "dnl", false, false, false, m4_dnl }, - { "dumpdef", false, false, false, m4_dumpdef }, - { "errprint", false, false, true, m4_errprint }, - { "esyscmd", true, false, true, m4_esyscmd }, - { "eval", false, false, true, m4_eval }, - { "format", true, false, true, m4_format }, - { "ifdef", false, false, true, m4_ifdef }, - { "ifelse", false, false, true, m4_ifelse }, - { "include", false, false, true, m4_include }, - { "incr", false, false, true, m4_incr }, - { "index", false, false, true, m4_index }, - { "indir", true, true, true, m4_indir }, - { "len", false, false, true, m4_len }, - { "m4exit", false, false, false, m4_m4exit }, - { "m4wrap", false, false, true, m4_m4wrap }, - { "maketemp", false, false, true, m4_maketemp }, - { "mkstemp", false, false, true, m4_mkstemp }, - { "patsubst", true, false, true, m4_patsubst }, - { "popdef", false, false, true, m4_popdef }, - { "pushdef", false, true, true, m4_pushdef }, - { "regexp", true, false, true, m4_regexp }, - { "shift", false, false, true, m4_shift }, - { "sinclude", false, false, true, m4_sinclude }, - { "substr", false, false, true, m4_substr }, - { "syscmd", false, false, true, m4_syscmd }, - { "sysval", false, false, false, m4_sysval }, - { "traceoff", false, false, false, m4_traceoff }, - { "traceon", false, false, false, m4_traceon }, - { "translit", false, false, true, m4_translit }, - { "undefine", false, false, true, m4_undefine }, - { "undivert", false, false, false, m4_undivert }, - - { 0, false, false, false, 0 }, - - /* placeholder is intentionally stuck after the table end delimiter, - so that we can easily find it, while not treating it as a real - builtin. */ - { "placeholder", true, false, false, m4_placeholder }, -}; - -static predefined const predefined_tab[] = -{ -#if UNIX - { "unix", "__unix__", "" }, -#endif -#if W32_NATIVE - { "windows", "__windows__", "" }, -#endif -#if OS2 - { "os2", "__os2__", "" }, -#endif -#if !UNIX && !W32_NATIVE && !OS2 -# warning Platform macro not provided -#endif - { NULL, "__gnu__", "" }, - - { NULL, NULL, NULL }, -}; - -/*----------------------------------------. -| Find the builtin, which lives on ADDR. | -`----------------------------------------*/ - -const builtin * M4_GNUC_PURE -find_builtin_by_addr (builtin_func *func) -{ - const builtin *bp; - - for (bp = &builtin_tab[0]; bp->name != NULL; bp++) - if (bp->func == func) - return bp; - if (func == m4_placeholder) - return bp + 1; - return NULL; -} - -/*----------------------------------------------------------. -| Find the builtin, which has NAME. On failure, return the | -| placeholder builtin. | -`----------------------------------------------------------*/ - -const builtin * M4_GNUC_PURE -find_builtin_by_name (const char *name) -{ - const builtin *bp; - - for (bp = &builtin_tab[0]; bp->name != NULL; bp++) - if (STREQ (bp->name, name)) - return bp; - return bp + 1; -} - -/*----------------------------------------------------------------. -| Install a builtin macro with name NAME, bound to the C function | -| given in BP. MODE is SYMBOL_INSERT or SYMBOL_PUSHDEF. | -`----------------------------------------------------------------*/ - -void -define_builtin (const char *name, const builtin *bp, symbol_lookup mode) -{ - symbol *sym; - - sym = lookup_symbol (name, mode); - SYMBOL_TYPE (sym) = TOKEN_FUNC; - SYMBOL_MACRO_ARGS (sym) = bp->groks_macro_args; - SYMBOL_BLIND_NO_ARGS (sym) = bp->blind_if_no_args; - SYMBOL_FUNC (sym) = bp->func; -} - -/* Storage for the compiled regular expression of - --warn-macro-sequence. */ -static struct re_pattern_buffer macro_sequence_buf; - -/* Storage for the matches of --warn-macro-sequence. */ -static struct re_registers macro_sequence_regs; - -/* True if --warn-macro-sequence is in effect. */ -static bool macro_sequence_inuse; - -/*----------------------------------------. -| Clean up regular expression variables. | -`----------------------------------------*/ - -static void -free_pattern_buffer (struct re_pattern_buffer *buf, struct re_registers *regs) -{ - regfree (buf); - free (regs->start); - free (regs->end); -} - -/*-----------------------------------------------------------------. -| Set the regular expression of --warn-macro-sequence that will be | -| checked during define and pushdef. Exit on failure. | -`-----------------------------------------------------------------*/ -void -set_macro_sequence (const char *regexp) -{ - const char *msg; - - if (! regexp) - regexp = DEFAULT_MACRO_SEQUENCE; - else if (regexp[0] == '\0') - { - macro_sequence_inuse = false; - return; - } - - msg = re_compile_pattern (regexp, strlen (regexp), ¯o_sequence_buf); - if (msg != NULL) - { - M4ERROR ((EXIT_FAILURE, 0, - "--warn-macro-sequence: bad regular expression `%s': %s", - regexp, msg)); - } - re_set_registers (¯o_sequence_buf, ¯o_sequence_regs, - macro_sequence_regs.num_regs, - macro_sequence_regs.start, macro_sequence_regs.end); - macro_sequence_inuse = true; -} - -/*-----------------------------------------------------------. -| Free dynamic memory utilized by the macro sequence regular | -| expression during the define builtin. | -`-----------------------------------------------------------*/ -void -free_macro_sequence (void) -{ - free_pattern_buffer (¯o_sequence_buf, ¯o_sequence_regs); -} - -/*-----------------------------------------------------------------. -| Define a predefined or user-defined macro, with name NAME, and | -| expansion TEXT. MODE destinguishes between the "define" and the | -| "pushdef" case. It is also used from main. | -`-----------------------------------------------------------------*/ - -void -define_user_macro (const char *name, const char *text, symbol_lookup mode) -{ - symbol *s; - char *defn = xstrdup (text ? text : ""); - - s = lookup_symbol (name, mode); - if (SYMBOL_TYPE (s) == TOKEN_TEXT) - free (SYMBOL_TEXT (s)); - - SYMBOL_TYPE (s) = TOKEN_TEXT; - SYMBOL_TEXT (s) = defn; - - /* Implement --warn-macro-sequence. */ - if (macro_sequence_inuse && text) - { - regoff_t offset = 0; - size_t len = strlen (defn); - - while ((offset = re_search (¯o_sequence_buf, defn, len, offset, - len - offset, ¯o_sequence_regs)) >= 0) - { - /* Skip empty matches. */ - if (macro_sequence_regs.start[0] == macro_sequence_regs.end[0]) - offset++; - else - { - char tmp; - offset = macro_sequence_regs.end[0]; - tmp = defn[offset]; - defn[offset] = '\0'; - M4ERROR ((warning_status, 0, - "Warning: definition of `%s' contains sequence `%s'", - name, defn + macro_sequence_regs.start[0])); - defn[offset] = tmp; - } - } - if (offset == -2) - M4ERROR ((warning_status, 0, - "error checking --warn-macro-sequence for macro `%s'", - name)); - } -} - -/*-----------------------------------------------. -| Initialize all builtin and predefined macros. | -`-----------------------------------------------*/ - -void -builtin_init (void) -{ - const builtin *bp; - const predefined *pp; - char *string; - - for (bp = &builtin_tab[0]; bp->name != NULL; bp++) - if (!no_gnu_extensions || !bp->gnu_extension) - { - if (prefix_all_builtins) - { - string = (char *) xmalloc (strlen (bp->name) + 4); - strcpy (string, "m4_"); - strcat (string, bp->name); - define_builtin (string, bp, SYMBOL_INSERT); - free (string); - } - else - define_builtin (bp->name, bp, SYMBOL_INSERT); - } - - for (pp = &predefined_tab[0]; pp->func != NULL; pp++) - if (no_gnu_extensions) - { - if (pp->unix_name != NULL) - define_user_macro (pp->unix_name, pp->func, SYMBOL_INSERT); - } - else - { - if (pp->gnu_name != NULL) - define_user_macro (pp->gnu_name, pp->func, SYMBOL_INSERT); - } -} - -/*-------------------------------------------------------------------. -| Give friendly warnings if a builtin macro is passed an | -| inappropriate number of arguments. NAME is the macro name for | -| messages, ARGC is actual number of arguments, MIN is the minimum | -| number of acceptable arguments, negative if not applicable, MAX is | -| the maximum number, negative if not applicable. | -`-------------------------------------------------------------------*/ - -static bool -bad_argc (token_data *name, int argc, int min, int max) -{ - bool isbad = false; - - if (min > 0 && argc < min) - { - if (!suppress_warnings) - M4ERROR ((warning_status, 0, - "Warning: too few arguments to builtin `%s'", - TOKEN_DATA_TEXT (name))); - isbad = true; - } - else if (max > 0 && argc > max && !suppress_warnings) - M4ERROR ((warning_status, 0, - "Warning: excess arguments to builtin `%s' ignored", - TOKEN_DATA_TEXT (name))); - - return isbad; -} - -/*-----------------------------------------------------------------. -| The function numeric_arg () converts ARG to an int pointed to by | -| VALUEP. If the conversion fails, print error message for macro | -| MACRO. Return true iff conversion succeeds. | -`-----------------------------------------------------------------*/ - -static bool -numeric_arg (token_data *macro, const char *arg, int *valuep) -{ - char *endp; - - if (*arg == '\0') - { - *valuep = 0; - M4ERROR ((warning_status, 0, - "empty string treated as 0 in builtin `%s'", - TOKEN_DATA_TEXT (macro))); - } - else - { - errno = 0; - *valuep = strtol (arg, &endp, 10); - if (*endp != '\0') - { - M4ERROR ((warning_status, 0, - "non-numeric argument to builtin `%s'", - TOKEN_DATA_TEXT (macro))); - return false; - } - if (isspace (to_uchar (*arg))) - M4ERROR ((warning_status, 0, - "leading whitespace ignored in builtin `%s'", - TOKEN_DATA_TEXT (macro))); - else if (errno == ERANGE) - M4ERROR ((warning_status, 0, - "numeric overflow detected in builtin `%s'", - TOKEN_DATA_TEXT (macro))); - } - return true; -} - -/*------------------------------------------------------. -| The function ntoa () converts VALUE to a signed ASCII | -| representation in radix RADIX. | -`------------------------------------------------------*/ - -/* Digits for number to ASCII conversions. */ -static char const digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - -const char * -ntoa (int32_t value, int radix) -{ - bool negative; - uint32_t uvalue; - static char str[256]; - char *s = &str[sizeof str]; - - *--s = '\0'; - - if (value < 0) - { - negative = true; - uvalue = -(uint32_t) value; - } - else - { - negative = false; - uvalue = (uint32_t) value; - } - - do - { - *--s = digits[uvalue % radix]; - uvalue /= radix; - } - while (uvalue > 0); - - if (negative) - *--s = '-'; - return s; -} - -/*---------------------------------------------------------------. -| Format an int VAL, and stuff it into an obstack OBS. Used for | -| macros expanding to numbers. | -`---------------------------------------------------------------*/ - -static void -shipout_int (struct obstack *obs, int val) -{ - const char *s; - - s = ntoa ((int32_t) val, 10); - obstack_grow (obs, s, strlen (s)); -} - -/*-------------------------------------------------------------------. -| Print ARGC arguments from the table ARGV to obstack OBS, separated | -| by SEP, and quoted by the current quotes if QUOTED is true. | -`-------------------------------------------------------------------*/ - -static void -dump_args (struct obstack *obs, int argc, token_data **argv, - const char *sep, bool quoted) -{ - int i; - size_t len = strlen (sep); - - for (i = 1; i < argc; i++) - { - if (i > 1) - obstack_grow (obs, sep, len); - if (quoted) - obstack_grow (obs, lquote.string, lquote.length); - obstack_grow (obs, TOKEN_DATA_TEXT (argv[i]), - strlen (TOKEN_DATA_TEXT (argv[i]))); - if (quoted) - obstack_grow (obs, rquote.string, rquote.length); - } -} - -/* The rest of this file is code for builtins and expansion of user - defined macros. All the functions for builtins have a prototype as: - - void m4_MACRONAME (struct obstack *obs, int argc, char *argv[]); - - The function are expected to leave their expansion on the obstack OBS, - as an unfinished object. ARGV is a table of ARGC pointers to the - individual arguments to the macro. Please note that in general - argv[argc] != NULL. */ - -/* The first section are macros for definining, undefining, examining, - changing, ... other macros. */ - -/*-------------------------------------------------------------------. -| The function define_macro is common for the builtins "define", | -| "undefine", "pushdef" and "popdef". ARGC and ARGV is as for the | -| caller, and MODE argument determines how the macro name is entered | -| into the symbol table. | -`-------------------------------------------------------------------*/ - -static void -define_macro (int argc, token_data **argv, symbol_lookup mode) -{ - const builtin *bp; - - if (bad_argc (argv[0], argc, 2, 3)) - return; - - if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT) - { - M4ERROR ((warning_status, 0, - "Warning: %s: invalid macro name ignored", ARG (0))); - return; - } - - if (argc == 2) - { - define_user_macro (ARG (1), "", mode); - return; - } - - switch (TOKEN_DATA_TYPE (argv[2])) - { - case TOKEN_TEXT: - define_user_macro (ARG (1), ARG (2), mode); - break; - - case TOKEN_FUNC: - bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[2])); - if (bp == NULL) - return; - else - define_builtin (ARG (1), bp, mode); - break; - - case TOKEN_VOID: - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad token data type in define_macro ()")); - abort (); - } -} - -static void -m4_define (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - define_macro (argc, argv, SYMBOL_INSERT); -} - -static void -m4_undefine (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - int i; - if (bad_argc (argv[0], argc, 2, -1)) - return; - for (i = 1; i < argc; i++) - lookup_symbol (ARG (i), SYMBOL_DELETE); -} - -static void -m4_pushdef (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - define_macro (argc, argv, SYMBOL_PUSHDEF); -} - -static void -m4_popdef (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - int i; - if (bad_argc (argv[0], argc, 2, -1)) - return; - for (i = 1; i < argc; i++) - lookup_symbol (ARG (i), SYMBOL_POPDEF); -} - -/*---------------------. -| Conditionals of m4. | -`---------------------*/ - -static void -m4_ifdef (struct obstack *obs, int argc, token_data **argv) -{ - symbol *s; - const char *result; - - if (bad_argc (argv[0], argc, 3, 4)) - return; - s = lookup_symbol (ARG (1), SYMBOL_LOOKUP); - - if (s != NULL && SYMBOL_TYPE (s) != TOKEN_VOID) - result = ARG (2); - else if (argc >= 4) - result = ARG (3); - else - result = NULL; - - if (result != NULL) - obstack_grow (obs, result, strlen (result)); -} - -static void -m4_ifelse (struct obstack *obs, int argc, token_data **argv) -{ - const char *result; - token_data *me = argv[0]; - - if (argc == 2) - return; - - if (bad_argc (me, argc, 4, -1)) - return; - else - /* Diagnose excess arguments if 5, 8, 11, etc., actual arguments. */ - bad_argc (me, (argc + 2) % 3, -1, 1); - - argv++; - argc--; - - result = NULL; - while (result == NULL) - - if (STREQ (ARG (0), ARG (1))) - result = ARG (2); - - else - switch (argc) - { - case 3: - return; - - case 4: - case 5: - result = ARG (3); - break; - - default: - argc -= 3; - argv += 3; - } - - obstack_grow (obs, result, strlen (result)); -} - -/*-------------------------------------------------------------------. -| The function dump_symbol () is for use by "dumpdef". It builds up | -| a table of all defined, un-shadowed, symbols. | -`-------------------------------------------------------------------*/ - -/* The structure dump_symbol_data is used to pass the information needed - from call to call to dump_symbol. */ - -struct dump_symbol_data -{ - struct obstack *obs; /* obstack for table */ - symbol **base; /* base of table */ - int size; /* size of table */ -}; - -static void -dump_symbol (symbol *sym, void *arg) -{ - struct dump_symbol_data *data = (struct dump_symbol_data *) arg; - if (!SYMBOL_SHADOWED (sym) && SYMBOL_TYPE (sym) != TOKEN_VOID) - { - obstack_blank (data->obs, sizeof (symbol *)); - data->base = (symbol **) obstack_base (data->obs); - data->base[data->size++] = sym; - } -} - -/*------------------------------------------------------------------------. -| qsort comparison routine, for sorting the table made in m4_dumpdef (). | -`------------------------------------------------------------------------*/ - -static int -dumpdef_cmp (const void *s1, const void *s2) -{ - return strcmp (SYMBOL_NAME (* (symbol *const *) s1), - SYMBOL_NAME (* (symbol *const *) s2)); -} - -/*-------------------------------------------------------------. -| Implementation of "dumpdef" itself. It builds up a table of | -| pointers to symbols, sorts it and prints the sorted table. | -`-------------------------------------------------------------*/ - -static void -m4_dumpdef (struct obstack *obs, int argc, token_data **argv) -{ - symbol *s; - int i; - struct dump_symbol_data data; - const builtin *bp; - - data.obs = obs; - data.base = (symbol **) obstack_base (obs); - data.size = 0; - - if (argc == 1) - { - hack_all_symbols (dump_symbol, &data); - } - else - { - for (i = 1; i < argc; i++) - { - s = lookup_symbol (TOKEN_DATA_TEXT (argv[i]), SYMBOL_LOOKUP); - if (s != NULL && SYMBOL_TYPE (s) != TOKEN_VOID) - dump_symbol (s, &data); - else - M4ERROR ((warning_status, 0, - "undefined macro `%s'", TOKEN_DATA_TEXT (argv[i]))); - } - } - - /* Make table of symbols invisible to expand_macro (). */ - - obstack_finish (obs); - - qsort (data.base, data.size, sizeof (symbol *), dumpdef_cmp); - - for (; data.size > 0; --data.size, data.base++) - { - DEBUG_PRINT1 ("%s:\t", SYMBOL_NAME (data.base[0])); - - switch (SYMBOL_TYPE (data.base[0])) - { - case TOKEN_TEXT: - if (debug_level & DEBUG_TRACE_QUOTE) - DEBUG_PRINT3 ("%s%s%s\n", - lquote.string, SYMBOL_TEXT (data.base[0]), rquote.string); - else - DEBUG_PRINT1 ("%s\n", SYMBOL_TEXT (data.base[0])); - break; - - case TOKEN_FUNC: - bp = find_builtin_by_addr (SYMBOL_FUNC (data.base[0])); - if (bp == NULL) - { - M4ERROR ((warning_status, 0, "\ -INTERNAL ERROR: builtin not found in builtin table")); - abort (); - } - DEBUG_PRINT1 ("<%s>\n", bp->name); - break; - - case TOKEN_VOID: - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad token data type in m4_dumpdef ()")); - abort (); - break; - } - } -} - -/*-----------------------------------------------------------------. -| The builtin "builtin" allows calls to builtin macros, even if | -| their definition has been overridden or shadowed. It is thus | -| possible to redefine builtins, and still access their original | -| definition. This macro is not available in compatibility mode. | -`-----------------------------------------------------------------*/ - -static void -m4_builtin (struct obstack *obs, int argc, token_data **argv) -{ - const builtin *bp; - const char *name; - - if (bad_argc (argv[0], argc, 2, -1)) - return; - if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT) - { - M4ERROR ((warning_status, 0, - "Warning: %s: invalid macro name ignored", ARG (0))); - return; - } - - name = ARG (1); - bp = find_builtin_by_name (name); - if (bp->func == m4_placeholder) - M4ERROR ((warning_status, 0, - "undefined builtin `%s'", name)); - else - { - int i; - if (! bp->groks_macro_args) - for (i = 2; i < argc; i++) - if (TOKEN_DATA_TYPE (argv[i]) != TOKEN_TEXT) - { - TOKEN_DATA_TYPE (argv[i]) = TOKEN_TEXT; - TOKEN_DATA_TEXT (argv[i]) = (char *) ""; - } - bp->func (obs, argc - 1, argv + 1); - } -} - -/*-------------------------------------------------------------------. -| The builtin "indir" allows indirect calls to macros, even if their | -| name is not a proper macro name. It is thus possible to define | -| macros with ill-formed names for internal use in larger macro | -| packages. This macro is not available in compatibility mode. | -`-------------------------------------------------------------------*/ - -static void -m4_indir (struct obstack *obs, int argc, token_data **argv) -{ - symbol *s; - const char *name; - - if (bad_argc (argv[0], argc, 2, -1)) - return; - if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT) - { - M4ERROR ((warning_status, 0, - "Warning: %s: invalid macro name ignored", ARG (0))); - return; - } - - name = ARG (1); - s = lookup_symbol (name, SYMBOL_LOOKUP); - if (s == NULL || SYMBOL_TYPE (s) == TOKEN_VOID) - M4ERROR ((warning_status, 0, - "undefined macro `%s'", name)); - else - { - int i; - if (! SYMBOL_MACRO_ARGS (s)) - for (i = 2; i < argc; i++) - if (TOKEN_DATA_TYPE (argv[i]) != TOKEN_TEXT) - { - TOKEN_DATA_TYPE (argv[i]) = TOKEN_TEXT; - TOKEN_DATA_TEXT (argv[i]) = (char *) ""; - } - call_macro (s, argc - 1, argv + 1, obs); - } -} - -/*------------------------------------------------------------------. -| The macro "defn" returns the quoted definition of the macro named | -| by the first argument. If the macro is builtin, it will push a | -| special macro-definition token on the input stack. | -`------------------------------------------------------------------*/ - -static void -m4_defn (struct obstack *obs, int argc, token_data **argv) -{ - symbol *s; - builtin_func *b; - unsigned int i; - - if (bad_argc (argv[0], argc, 2, -1)) - return; - - assert (0 < argc); - for (i = 1; i < (unsigned) argc; i++) - { - const char *arg = ARG((int) i); - s = lookup_symbol (arg, SYMBOL_LOOKUP); - if (s == NULL) - continue; - - switch (SYMBOL_TYPE (s)) - { - case TOKEN_TEXT: - obstack_grow (obs, lquote.string, lquote.length); - obstack_grow (obs, SYMBOL_TEXT (s), strlen (SYMBOL_TEXT (s))); - obstack_grow (obs, rquote.string, rquote.length); - break; - - case TOKEN_FUNC: - b = SYMBOL_FUNC (s); - if (b == m4_placeholder) - M4ERROR ((warning_status, 0, "\ -builtin `%s' requested by frozen file is not supported", arg)); - else if (argc != 2) - M4ERROR ((warning_status, 0, - "Warning: cannot concatenate builtin `%s'", - arg)); - else - push_macro (b); - break; - - case TOKEN_VOID: - /* Nothing to do for traced but undefined macro. */ - break; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad symbol type in m4_defn ()")); - abort (); - } - } -} - -/*--------------------------------------------------------------. -| This section contains macros to handle the builtins "syscmd", | -| "esyscmd" and "sysval". "esyscmd" is GNU specific. | -`--------------------------------------------------------------*/ - -/* Exit code from last "syscmd" command. */ -static int sysval; - -static void -m4_syscmd (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - const char *cmd = ARG (1); - int status; - int sig_status; - const char *prog_args[4] = { "sh", "-c" }; - if (bad_argc (argv[0], argc, 2, 2) || !*cmd) - { - /* The empty command is successful. */ - sysval = 0; - return; - } - - debug_flush_files (); -#if W32_NATIVE - if (strstr (SYSCMD_SHELL, "cmd")) - { - prog_args[0] = "cmd"; - prog_args[1] = "/c"; - } -#endif - prog_args[2] = cmd; - errno = 0; - status = execute (ARG (0), SYSCMD_SHELL, (char **) prog_args, false, - false, false, false, true, false, &sig_status); - if (sig_status) - { - assert (status == 127); - sysval = sig_status << 8; - } - else - { - if (status == 127 && errno) - M4ERROR ((warning_status, errno, "cannot run command `%s'", cmd)); - sysval = status; - } -} - -static void -m4_esyscmd (struct obstack *obs, int argc, token_data **argv) -{ - const char *cmd = ARG (1); - const char *prog_args[4] = { "sh", "-c" }; - pid_t child; - int fd; - FILE *pin; - int status; - int sig_status; - - if (bad_argc (argv[0], argc, 2, 2) || !*cmd) - { - /* The empty command is successful. */ - sysval = 0; - return; - } - - debug_flush_files (); -#if W32_NATIVE - if (strstr (SYSCMD_SHELL, "cmd")) - { - prog_args[0] = "cmd"; - prog_args[1] = "/c"; - } -#endif - prog_args[2] = cmd; - errno = 0; - child = create_pipe_in (ARG (0), SYSCMD_SHELL, (char **) prog_args, - NULL, false, true, false, &fd); - if (child == -1) - { - M4ERROR ((warning_status, errno, "cannot run command `%s'", cmd)); - sysval = 127; - return; - } - pin = fdopen (fd, "r"); - if (pin == NULL) - { - M4ERROR ((warning_status, errno, "cannot run command `%s'", cmd)); - sysval = 127; - close (fd); - return; - } - while (1) - { - size_t avail = obstack_room (obs); - size_t len; - if (!avail) - { - int ch = getc (pin); - if (ch == EOF) - break; - obstack_1grow (obs, ch); - continue; - } - len = fread (obstack_next_free (obs), 1, avail, pin); - if (len <= 0) - break; - obstack_blank_fast (obs, len); - } - if (ferror (pin) || fclose (pin)) - M4ERROR ((EXIT_FAILURE, errno, "cannot read pipe")); - errno = 0; - status = wait_subprocess (child, ARG (0), false, true, true, false, - &sig_status); - if (sig_status) - { - assert (status == 127); - sysval = sig_status << 8; - } - else - { - if (status == 127 && errno) - M4ERROR ((warning_status, errno, "cannot run command `%s'", cmd)); - sysval = status; - } -} - -static void -m4_sysval (struct obstack *obs, int argc M4_GNUC_UNUSED, - token_data **argv M4_GNUC_UNUSED) -{ - shipout_int (obs, sysval); -} - -/*------------------------------------------------------------------. -| This section contains the top level code for the "eval" builtin. | -| The actual work is done in the function evaluate (), which lives | -| in eval.c. | -`------------------------------------------------------------------*/ - -static void -m4_eval (struct obstack *obs, int argc, token_data **argv) -{ - int32_t value = 0; - int radix = 10; - int min = 1; - const char *s; - - if (bad_argc (argv[0], argc, 2, 4)) - return; - - if (*ARG (2) && !numeric_arg (argv[0], ARG (2), &radix)) - return; - - if (radix < 1 || radix > (int) strlen (digits)) - { - M4ERROR ((warning_status, 0, - "radix %d in builtin `%s' out of range", - radix, ARG (0))); - return; - } - - if (argc >= 4 && !numeric_arg (argv[0], ARG (3), &min)) - return; - if (min < 0) - { - M4ERROR ((warning_status, 0, - "negative width to builtin `%s'", ARG (0))); - return; - } - - if (!*ARG (1)) - M4ERROR ((warning_status, 0, - "empty string treated as 0 in builtin `%s'", ARG (0))); - else if (evaluate (ARG (1), &value)) - return; - - if (radix == 1) - { - if (value < 0) - { - obstack_1grow (obs, '-'); - value = -value; - } - /* This assumes 2's-complement for correctly handling INT_MIN. */ - while (min-- - value > 0) - obstack_1grow (obs, '0'); - while (value-- != 0) - obstack_1grow (obs, '1'); - obstack_1grow (obs, '\0'); - return; - } - - s = ntoa (value, radix); - - if (*s == '-') - { - obstack_1grow (obs, '-'); - s++; - } - for (min -= strlen (s); --min >= 0;) - obstack_1grow (obs, '0'); - - obstack_grow (obs, s, strlen (s)); -} - -static void -m4_incr (struct obstack *obs, int argc, token_data **argv) -{ - int value; - - if (bad_argc (argv[0], argc, 2, 2)) - return; - - if (!numeric_arg (argv[0], ARG (1), &value)) - return; - - shipout_int (obs, value + 1); -} - -static void -m4_decr (struct obstack *obs, int argc, token_data **argv) -{ - int value; - - if (bad_argc (argv[0], argc, 2, 2)) - return; - - if (!numeric_arg (argv[0], ARG (1), &value)) - return; - - shipout_int (obs, value - 1); -} - -/* This section contains the macros "divert", "undivert" and "divnum" for - handling diversion. The utility functions used lives in output.c. */ - -/*-----------------------------------------------------------------. -| Divert further output to the diversion given by ARGV[1]. Out of | -| range means discard further output. | -`-----------------------------------------------------------------*/ - -static void -m4_divert (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - int i = 0; - - if (bad_argc (argv[0], argc, 1, 2)) - return; - - if (argc >= 2 && !numeric_arg (argv[0], ARG (1), &i)) - return; - - make_diversion (i); -} - -/*-----------------------------------------------------. -| Expand to the current diversion number, -1 if none. | -`-----------------------------------------------------*/ - -static void -m4_divnum (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 1, 1)) - return; - shipout_int (obs, current_diversion); -} - -/*------------------------------------------------------------------. -| Bring back the diversion given by the argument list. If none is | -| specified, bring back all diversions. GNU specific is the option | -| of undiverting named files, by passing a non-numeric argument to | -| undivert (). | -`------------------------------------------------------------------*/ - -static void -m4_undivert (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - int i, file; - FILE *fp; - char *endp; - - if (argc == 1) - undivert_all (); - else - for (i = 1; i < argc; i++) - { - file = strtol (ARG (i), &endp, 10); - if (*endp == '\0' && !isspace (to_uchar (*ARG (i)))) - insert_diversion (file); - else if (no_gnu_extensions) - M4ERROR ((warning_status, 0, - "non-numeric argument to builtin `%s'", ARG (0))); - else - { - fp = m4_path_search (ARG (i), NULL); - if (fp != NULL) - { - insert_file (fp); - if (fclose (fp) == EOF) - M4ERROR ((warning_status, errno, - "error undiverting `%s'", ARG (i))); - } - else - M4ERROR ((warning_status, errno, - "cannot undivert `%s'", ARG (i))); - } - } -} - -/* This section contains various macros, which does not fall into any - specific group. These are "dnl", "shift", "changequote", "changecom" - and "changeword". */ - -/*-----------------------------------------------------------. -| Delete all subsequent whitespace from input. The function | -| skip_line () lives in input.c. | -`-----------------------------------------------------------*/ - -static void -m4_dnl (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 1, 1)) - return; - - skip_line (); -} - -/*--------------------------------------------------------------------. -| Shift all arguments one to the left, discarding the first | -| argument. Each output argument is quoted with the current quotes. | -`--------------------------------------------------------------------*/ - -static void -m4_shift (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 2, -1)) - return; - dump_args (obs, argc - 1, argv + 1, ",", true); -} - -/*--------------------------------------------------------------------------. -| Change the current quotes. The function set_quotes () lives in input.c. | -`--------------------------------------------------------------------------*/ - -static void -m4_changequote (struct obstack *obs M4_GNUC_UNUSED, int argc, - token_data **argv) -{ - if (bad_argc (argv[0], argc, 1, 3)) - return; - - /* Explicit NULL distinguishes between empty and missing argument. */ - set_quotes ((argc >= 2) ? TOKEN_DATA_TEXT (argv[1]) : NULL, - (argc >= 3) ? TOKEN_DATA_TEXT (argv[2]) : NULL); -} - -/*-----------------------------------------------------------------. -| Change the current comment delimiters. The function set_comment | -| () lives in input.c. | -`-----------------------------------------------------------------*/ - -static void -m4_changecom (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 1, 3)) - return; - - /* Explicit NULL distinguishes between empty and missing argument. */ - set_comment ((argc >= 2) ? TOKEN_DATA_TEXT (argv[1]) : NULL, - (argc >= 3) ? TOKEN_DATA_TEXT (argv[2]) : NULL); -} - -#ifdef ENABLE_CHANGEWORD - -/*---------------------------------------------------------------. -| Change the regular expression used for breaking the input into | -| words. The function set_word_regexp () lives in input.c. | -`---------------------------------------------------------------*/ - -static void -m4_changeword (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 2, 2)) - return; - - set_word_regexp (TOKEN_DATA_TEXT (argv[1])); -} - -#endif /* ENABLE_CHANGEWORD */ - -/* This section contains macros for inclusion of other files -- "include" - and "sinclude". This differs from bringing back diversions, in that - the input is scanned before being copied to the output. */ - -/*---------------------------------------------------------------. -| Generic include function. Include the file given by the first | -| argument, if it exists. Complain about inaccessible files iff | -| SILENT is false. | -`---------------------------------------------------------------*/ - -static void -include (int argc, token_data **argv, bool silent) -{ - FILE *fp; - char *name; - - if (bad_argc (argv[0], argc, 2, 2)) - return; - - fp = m4_path_search (ARG (1), &name); - if (fp == NULL) - { - if (!silent) - { - M4ERROR ((warning_status, errno, "cannot open `%s'", ARG (1))); - retcode = EXIT_FAILURE; - } - return; - } - - push_file (fp, name, true); - free (name); -} - -/*------------------------------------------------. -| Include a file, complaining in case of errors. | -`------------------------------------------------*/ - -static void -m4_include (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - include (argc, argv, false); -} - -/*----------------------------------. -| Include a file, ignoring errors. | -`----------------------------------*/ - -static void -m4_sinclude (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - include (argc, argv, true); -} - -/* More miscellaneous builtins -- "maketemp", "errprint", "__file__", - "__line__", and "__program__". The last three are GNU specific. */ - -/*------------------------------------------------------------------. -| Use the first argument as at template for a temporary file name. | -`------------------------------------------------------------------*/ - -/* Add trailing 'X' to PATTERN of length LEN as necessary, then - securely create the file, and place the quoted new file name on - OBS. Report errors on behalf of ME. */ -static void -mkstemp_helper (struct obstack *obs, const char *me, const char *pattern, - size_t len) -{ - int fd; - size_t i; - char *name; - - /* Guarantee that there are six trailing 'X' characters, even if the - user forgot to supply them. Output must be quoted if - successful. */ - obstack_grow (obs, lquote.string, lquote.length); - obstack_grow (obs, pattern, len); - for (i = 0; len > 0 && i < 6; i++) - if (pattern[len - i - 1] != 'X') - break; - obstack_grow0 (obs, "XXXXXX", 6 - i); - name = (char *) obstack_base (obs) + lquote.length; - - errno = 0; - fd = mkstemp (name); - if (fd < 0) - { - M4ERROR ((0, errno, "%s: cannot create tempfile `%s'", me, pattern)); - obstack_free (obs, obstack_finish (obs)); - } - else - { - close (fd); - /* Remove NUL, then finish quote. */ - obstack_blank (obs, -1); - obstack_grow (obs, rquote.string, rquote.length); - } -} - -static void -m4_maketemp (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 2, 2)) - return; - if (no_gnu_extensions) - { - /* POSIX states "any trailing 'X' characters [are] replaced with - the current process ID as a string", without referencing the - file system. Horribly insecure, but we have to do it when we - are in traditional mode. - - For reference, Solaris m4 does: - maketemp() -> `' - maketemp(X) -> `X' - maketemp(XX) -> `Xn', where n is last digit of pid - maketemp(XXXXXXXX) -> `X00nnnnn', where nnnnn is 16-bit pid - */ - const char *str = ARG (1); - int len = strlen (str); - int i; - int len2; - - M4ERROR ((warning_status, 0, "recommend using mkstemp instead")); - for (i = len; i > 1; i--) - if (str[i - 1] != 'X') - break; - obstack_grow (obs, str, i); - str = ntoa ((int32_t) getpid (), 10); - len2 = strlen (str); - if (len2 > len - i) - obstack_grow0 (obs, str + len2 - (len - i), len - i); - else - { - while (i++ < len - len2) - obstack_1grow (obs, '0'); - obstack_grow0 (obs, str, len2); - } - } - else - mkstemp_helper (obs, ARG (0), ARG (1), strlen (ARG (1))); -} - -static void -m4_mkstemp (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 2, 2)) - return; - mkstemp_helper (obs, ARG (0), ARG (1), strlen (ARG (1))); -} - -/*----------------------------------------. -| Print all arguments on standard error. | -`----------------------------------------*/ - -static void -m4_errprint (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 2, -1)) - return; - dump_args (obs, argc, argv, " ", false); - obstack_1grow (obs, '\0'); - debug_flush_files (); - xfprintf (stderr, "%s", (char *) obstack_finish (obs)); - fflush (stderr); -} - -static void -m4___file__ (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 1, 1)) - return; - obstack_grow (obs, lquote.string, lquote.length); - obstack_grow (obs, current_file, strlen (current_file)); - obstack_grow (obs, rquote.string, rquote.length); -} - -static void -m4___line__ (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 1, 1)) - return; - shipout_int (obs, current_line); -} - -static void -m4___program__ (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 1, 1)) - return; - obstack_grow (obs, lquote.string, lquote.length); - obstack_grow (obs, program_name, strlen (program_name)); - obstack_grow (obs, rquote.string, rquote.length); -} - -/* This section contains various macros for exiting, saving input until - EOF is seen, and tracing macro calls. That is: "m4exit", "m4wrap", - "traceon" and "traceoff". */ - -/*----------------------------------------------------------. -| Exit immediately, with exit status specified by the first | -| argument, or 0 if no arguments are present. | -`----------------------------------------------------------*/ - -static void M4_GNUC_NORETURN -m4_m4exit (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - int exit_code = EXIT_SUCCESS; - - /* Warn on bad arguments, but still exit. */ - bad_argc (argv[0], argc, 1, 2); - if (argc >= 2 && !numeric_arg (argv[0], ARG (1), &exit_code)) - exit_code = EXIT_FAILURE; - if (exit_code < 0 || exit_code > 255) - { - M4ERROR ((warning_status, 0, - "exit status out of range: `%d'", exit_code)); - exit_code = EXIT_FAILURE; - } - /* Change debug stream back to stderr, to force flushing debug stream and - detect any errors it might have encountered. */ - debug_set_output (NULL); - debug_flush_files (); - if (exit_code == EXIT_SUCCESS && retcode != EXIT_SUCCESS) - exit_code = retcode; - /* Propagate non-zero status to atexit handlers. */ - if (exit_code != EXIT_SUCCESS) - exit_failure = exit_code; - exit (exit_code); -} - -/*------------------------------------------------------------------. -| Save the argument text until EOF has been seen, allowing for user | -| specified cleanup action. GNU version saves all arguments, the | -| standard version only the first. | -`------------------------------------------------------------------*/ - -static void -m4_m4wrap (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 2, -1)) - return; - if (no_gnu_extensions) - obstack_grow (obs, ARG (1), strlen (ARG (1))); - else - dump_args (obs, argc, argv, " ", false); - obstack_1grow (obs, '\0'); - push_wrapup ((char *) obstack_finish (obs)); -} - -/* Enable tracing of all specified macros, or all, if none is specified. - Tracing is disabled by default, when a macro is defined. This can be - overridden by the "t" debug flag. */ - -/*------------------------------------------------------------------. -| Set_trace () is used by "traceon" and "traceoff" to enable and | -| disable tracing of a macro. It disables tracing if DATA is NULL, | -| otherwise it enables tracing. | -`------------------------------------------------------------------*/ - -static void -set_trace (symbol *sym, void *data) -{ - SYMBOL_TRACED (sym) = data != NULL; - /* Remove placeholder from table if macro is undefined and untraced. */ - if (SYMBOL_TYPE (sym) == TOKEN_VOID && data == NULL) - lookup_symbol (SYMBOL_NAME (sym), SYMBOL_POPDEF); -} - -static void -m4_traceon (struct obstack *obs, int argc, token_data **argv) -{ - symbol *s; - int i; - - if (argc == 1) - hack_all_symbols (set_trace, obs); - else - for (i = 1; i < argc; i++) - { - s = lookup_symbol (ARG (i), SYMBOL_LOOKUP); - if (!s) - s = lookup_symbol (ARG (i), SYMBOL_INSERT); - set_trace (s, obs); - } -} - -/*------------------------------------------------------------------------. -| Disable tracing of all specified macros, or all, if none is specified. | -`------------------------------------------------------------------------*/ - -static void -m4_traceoff (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - symbol *s; - int i; - - if (argc == 1) - hack_all_symbols (set_trace, NULL); - else - for (i = 1; i < argc; i++) - { - s = lookup_symbol (TOKEN_DATA_TEXT (argv[i]), SYMBOL_LOOKUP); - if (s != NULL) - set_trace (s, NULL); - } -} - -/*------------------------------------------------------------------. -| On-the-fly control of the format of the tracing output. It takes | -| one argument, which is a character string like given to the -d | -| option, or none in which case the debug_level is zeroed. | -`------------------------------------------------------------------*/ - -static void -m4_debugmode (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - int new_debug_level; - int change_flag; - - if (bad_argc (argv[0], argc, 1, 2)) - return; - - if (argc == 1) - debug_level = 0; - else - { - if (ARG (1)[0] == '+' || ARG (1)[0] == '-') - { - change_flag = ARG (1)[0]; - new_debug_level = debug_decode (ARG (1) + 1); - } - else - { - change_flag = 0; - new_debug_level = debug_decode (ARG (1)); - } - - if (new_debug_level < 0) - M4ERROR ((warning_status, 0, - "Debugmode: bad debug flags: `%s'", ARG (1))); - else - { - switch (change_flag) - { - case 0: - debug_level = new_debug_level; - break; - - case '+': - debug_level |= new_debug_level; - break; - - case '-': - debug_level &= ~new_debug_level; - break; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad flag in m4_debugmode ()")); - abort (); - } - } - } -} - -/*-------------------------------------------------------------------------. -| Specify the destination of the debugging output. With one argument, the | -| argument is taken as a file name, with no arguments, revert to stderr. | -`-------------------------------------------------------------------------*/ - -static void -m4_debugfile (struct obstack *obs M4_GNUC_UNUSED, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 1, 2)) - return; - - if (argc == 1) - debug_set_output (NULL); - else if (!debug_set_output (ARG (1))) - M4ERROR ((warning_status, errno, - "cannot set debug file `%s'", ARG (1))); -} - -/* This section contains text processing macros: "len", "index", - "substr", "translit", "format", "regexp" and "patsubst". The last - three are GNU specific. */ - -/*---------------------------------------------. -| Expand to the length of the first argument. | -`---------------------------------------------*/ - -static void -m4_len (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 2, 2)) - return; - shipout_int (obs, strlen (ARG (1))); -} - -/*-------------------------------------------------------------------. -| The macro expands to the first index of the second argument in the | -| first argument. | -`-------------------------------------------------------------------*/ - -static void -m4_index (struct obstack *obs, int argc, token_data **argv) -{ - const char *haystack; - const char *result; - int retval; - - if (bad_argc (argv[0], argc, 3, 3)) - { - /* builtin(`index') is blank, but index(`abc') is 0. */ - if (argc == 2) - shipout_int (obs, 0); - return; - } - - haystack = ARG (1); - result = strstr (haystack, ARG (2)); - retval = result ? result - haystack : -1; - - shipout_int (obs, retval); -} - -/*-----------------------------------------------------------------. -| The macro "substr" extracts substrings from the first argument, | -| starting from the index given by the second argument, extending | -| for a length given by the third argument. If the third argument | -| is missing, the substring extends to the end of the first | -| argument. | -`-----------------------------------------------------------------*/ - -static void -m4_substr (struct obstack *obs, int argc, token_data **argv) -{ - int start = 0; - int length, avail; - - if (bad_argc (argv[0], argc, 3, 4)) - { - /* builtin(`substr') is blank, but substr(`abc') is abc. */ - if (argc == 2) - obstack_grow (obs, ARG (1), strlen (ARG (1))); - return; - } - - length = avail = strlen (ARG (1)); - if (!numeric_arg (argv[0], ARG (2), &start)) - return; - - if (argc >= 4 && !numeric_arg (argv[0], ARG (3), &length)) - return; - - if (start < 0 || length <= 0 || start >= avail) - return; - - if (start + length > avail) - length = avail - start; - obstack_grow (obs, ARG (1) + start, length); -} - -/*------------------------------------------------------------------. -| For "translit", ranges are allowed in the second and third | -| argument. They are expanded in the following function, and the | -| expanded strings, without any ranges left, are used to translate | -| the characters of the first argument. A single - (dash) can be | -| included in the strings by being the first or the last character | -| in the string. If the first character in a range is after the | -| first in the character set, the range is made backwards, thus 9-0 | -| is the string 9876543210. | -`------------------------------------------------------------------*/ - -static const char * -expand_ranges (const char *s, struct obstack *obs) -{ - unsigned char from; - unsigned char to; - - for (from = '\0'; *s != '\0'; from = to_uchar (*s++)) - { - if (*s == '-' && from != '\0') - { - to = to_uchar (*++s); - if (to == '\0') - { - /* trailing dash */ - obstack_1grow (obs, '-'); - break; - } - else if (from <= to) - { - while (from++ < to) - obstack_1grow (obs, from); - } - else - { - while (--from >= to) - obstack_1grow (obs, from); - } - } - else - obstack_1grow (obs, *s); - } - obstack_1grow (obs, '\0'); - return (char *) obstack_finish (obs); -} - -/*-----------------------------------------------------------------. -| The macro "translit" translates all characters in the first | -| argument, which are present in the second argument, into the | -| corresponding character from the third argument. If the third | -| argument is shorter than the second, the extra characters in the | -| second argument are deleted from the first. | -`-----------------------------------------------------------------*/ - -static void -m4_translit (struct obstack *obs, int argc, token_data **argv) -{ - const char *data = ARG (1); - const char *from = ARG (2); - const char *to; - char map[UCHAR_MAX + 1]; - char found[UCHAR_MAX + 1]; - unsigned char ch; - - if (bad_argc (argv[0], argc, 3, 4) || !*data || !*from) - { - /* builtin(`translit') is blank, but translit(`abc') is abc. */ - if (2 <= argc) - obstack_grow (obs, data, strlen (data)); - return; - } - - to = ARG (3); - if (strchr (to, '-') != NULL) - { - to = expand_ranges (to, obs); - assert (to && *to); - } - - /* If there are only one or two bytes to replace, it is faster to - use memchr2. Using expand_ranges does nothing unless there are - at least three bytes. */ - if (!from[1] || !from[2]) - { - const char *p; - size_t len = strlen (data); - while ((p = (char *) memchr2 (data, from[0], from[1], len))) - { - obstack_grow (obs, data, p - data); - len -= p - data; - if (!len) - return; - data = p + 1; - len--; - if (*p == from[0] && to[0]) - obstack_1grow (obs, to[0]); - else if (*p == from[1] && to[0] && to[1]) - obstack_1grow (obs, to[1]); - } - obstack_grow (obs, data, len); - return; - } - - if (strchr (from, '-') != NULL) - { - from = expand_ranges (from, obs); - assert (from && *from); - } - - /* Calling strchr(from) for each character in data is quadratic, - since both strings can be arbitrarily long. Instead, create a - from-to mapping in one pass of from, then use that map in one - pass of data, for linear behavior. Traditional behavior is that - only the first instance of a character in from is consulted, - hence the found map. */ - memset (map, 0, sizeof map); - memset (found, 0, sizeof found); - for ( ; (ch = *from) != '\0'; from++) - { - if (! found[ch]) - { - found[ch] = 1; - map[ch] = *to; - } - if (*to != '\0') - to++; - } - - for (data = ARG (1); (ch = *data) != '\0'; data++) - { - if (! found[ch]) - obstack_1grow (obs, ch); - else if (map[ch]) - obstack_1grow (obs, map[ch]); - } -} - -/*-------------------------------------------------------------------. -| Frontend for printf like formatting. The function format () lives | -| in the file format.c. | -`-------------------------------------------------------------------*/ - -static void -m4_format (struct obstack *obs, int argc, token_data **argv) -{ - if (bad_argc (argv[0], argc, 2, -1)) - return; - expand_format (obs, argc - 1, argv + 1); -} - -/*------------------------------------------------------------------. -| Function to perform substitution by regular expressions. Used by | -| the builtins regexp and patsubst. The changed text is placed on | -| the obstack. The substitution is REPL, with \& substituted by | -| this part of VICTIM matched by the last whole regular expression, | -| taken from REGS[0], and \N substituted by the text matched by the | -| Nth parenthesized sub-expression, taken from REGS[N]. | -`------------------------------------------------------------------*/ - -static int substitute_warned = 0; - -static void -substitute (struct obstack *obs, const char *victim, const char *repl, - struct re_registers *regs) -{ - int ch; - __re_size_t ind; - while (1) - { - const char *backslash = strchr (repl, '\\'); - if (!backslash) - { - obstack_grow (obs, repl, strlen (repl)); - return; - } - obstack_grow (obs, repl, backslash - repl); - repl = backslash; - ch = *++repl; - switch (ch) - { - case '0': - if (!substitute_warned) - { - M4ERROR ((warning_status, 0, "\ -Warning: \\0 will disappear, use \\& instead in replacements")); - substitute_warned = 1; - } - /* Fall through. */ - - case '&': - obstack_grow (obs, victim + regs->start[0], - regs->end[0] - regs->start[0]); - repl++; - break; - - case '1': case '2': case '3': case '4': case '5': case '6': - case '7': case '8': case '9': - ind = ch -= '0'; - if (regs->num_regs - 1 <= ind) - M4ERROR ((warning_status, 0, - "Warning: sub-expression %d not present", ch)); - else if (regs->end[ch] > 0) - obstack_grow (obs, victim + regs->start[ch], - regs->end[ch] - regs->start[ch]); - repl++; - break; - - case '\0': - M4ERROR ((warning_status, 0, - "Warning: trailing \\ ignored in replacement")); - return; - - default: - obstack_1grow (obs, ch); - repl++; - break; - } - } -} - -/*------------------------------------------. -| Initialize regular expression variables. | -`------------------------------------------*/ - -void -init_pattern_buffer (struct re_pattern_buffer *buf, struct re_registers *regs) -{ - buf->translate = NULL; - buf->fastmap = NULL; - buf->buffer = NULL; - buf->allocated = 0; - if (regs) - { - regs->start = NULL; - regs->end = NULL; - } -} - -/*------------------------------------------------------------------. -| Regular expression version of index. Given two arguments, expand | -| to the index of the first match of the second argument (a regexp) | -| in the first. Expand to -1 if here is no match. Given a third | -| argument, it changes the expansion to this argument. | -`------------------------------------------------------------------*/ - -static void -m4_regexp (struct obstack *obs, int argc, token_data **argv) -{ - const char *victim; /* first argument */ - const char *regexp; /* regular expression */ - const char *repl; /* replacement string */ - - struct re_pattern_buffer buf; /* compiled regular expression */ - struct re_registers regs; /* for subexpression matches */ - const char *msg; /* error message from re_compile_pattern */ - int startpos; /* start position of match */ - int length; /* length of first argument */ - - if (bad_argc (argv[0], argc, 3, 4)) - { - /* builtin(`regexp') is blank, but regexp(`abc') is 0. */ - if (argc == 2) - shipout_int (obs, 0); - return; - } - - victim = TOKEN_DATA_TEXT (argv[1]); - regexp = TOKEN_DATA_TEXT (argv[2]); - - init_pattern_buffer (&buf, ®s); - msg = re_compile_pattern (regexp, strlen (regexp), &buf); - - if (msg != NULL) - { - M4ERROR ((warning_status, 0, - "bad regular expression: `%s': %s", regexp, msg)); - free_pattern_buffer (&buf, ®s); - return; - } - - length = strlen (victim); - /* Avoid overhead of allocating regs if we won't use it. */ - startpos = re_search (&buf, victim, length, 0, length, - argc == 3 ? NULL : ®s); - - if (startpos == -2) - M4ERROR ((warning_status, 0, - "error matching regular expression `%s'", regexp)); - else if (argc == 3) - shipout_int (obs, startpos); - else if (startpos >= 0) - { - repl = TOKEN_DATA_TEXT (argv[3]); - substitute (obs, victim, repl, ®s); - } - - free_pattern_buffer (&buf, ®s); -} - -/*--------------------------------------------------------------------------. -| Substitute all matches of a regexp occuring in a string. Each match of | -| the second argument (a regexp) in the first argument is changed to the | -| third argument, with \& substituted by the matched text, and \N | -| substituted by the text matched by the Nth parenthesized sub-expression. | -`--------------------------------------------------------------------------*/ - -static void -m4_patsubst (struct obstack *obs, int argc, token_data **argv) -{ - const char *victim; /* first argument */ - const char *regexp; /* regular expression */ - - struct re_pattern_buffer buf; /* compiled regular expression */ - struct re_registers regs; /* for subexpression matches */ - const char *msg; /* error message from re_compile_pattern */ - int matchpos; /* start position of match */ - int offset; /* current match offset */ - int length; /* length of first argument */ - - if (bad_argc (argv[0], argc, 3, 4)) - { - /* builtin(`patsubst') is blank, but patsubst(`abc') is abc. */ - if (argc == 2) - obstack_grow (obs, ARG (1), strlen (ARG (1))); - return; - } - - regexp = TOKEN_DATA_TEXT (argv[2]); - - init_pattern_buffer (&buf, ®s); - msg = re_compile_pattern (regexp, strlen (regexp), &buf); - - if (msg != NULL) - { - M4ERROR ((warning_status, 0, - "bad regular expression `%s': %s", regexp, msg)); - free (buf.buffer); - return; - } - - victim = TOKEN_DATA_TEXT (argv[1]); - length = strlen (victim); - - offset = 0; - while (offset <= length) - { - matchpos = re_search (&buf, victim, length, - offset, length - offset, ®s); - if (matchpos < 0) - { - - /* Match failed -- either error or there is no match in the - rest of the string, in which case the rest of the string is - copied verbatim. */ - - if (matchpos == -2) - M4ERROR ((warning_status, 0, - "error matching regular expression `%s'", regexp)); - else if (offset < length) - obstack_grow (obs, victim + offset, length - offset); - break; - } - - /* Copy the part of the string that was skipped by re_search (). */ - - if (matchpos > offset) - obstack_grow (obs, victim + offset, matchpos - offset); - - /* Handle the part of the string that was covered by the match. */ - - substitute (obs, victim, ARG (3), ®s); - - /* Update the offset to the end of the match. If the regexp - matched a null string, advance offset one more, to avoid - infinite loops. */ - - offset = regs.end[0]; - if (regs.start[0] == regs.end[0]) - obstack_1grow (obs, victim[offset++]); - } - obstack_1grow (obs, '\0'); - - free_pattern_buffer (&buf, ®s); -} - -/* Finally, a placeholder builtin. This builtin is not installed by - default, but when reading back frozen files, this is associated - with any builtin we don't recognize (for example, if the frozen - file was created with a changeword capable m4, but is then loaded - by a different m4 that does not support changeword). This way, we - can keep 'm4 -R' quiet in the common case that the user did not - know or care about the builtin when the frozen file was created, - while still flagging it as a potential error if an attempt is made - to actually use the builtin. */ - -/*--------------------------------------------------------------------. -| Issue a warning that this macro is a placeholder for an unsupported | -| builtin that was requested while reloading a frozen file. | -`--------------------------------------------------------------------*/ - -void -m4_placeholder (struct obstack *obs M4_GNUC_UNUSED, int argc, - token_data **argv) -{ - M4ERROR ((warning_status, 0, "\ -builtin `%s' requested by frozen file is not supported", ARG (0))); -} - -/*-------------------------------------------------------------------. -| This function handles all expansion of user defined and predefined | -| macros. It is called with an obstack OBS, where the macros | -| expansion will be placed, as an unfinished object. SYM points to | -| the macro definition, giving the expansion text. ARGC and ARGV | -| are the arguments, as usual. | -`-------------------------------------------------------------------*/ - -void -expand_user_macro (struct obstack *obs, symbol *sym, - int argc, token_data **argv) -{ - const char *text = SYMBOL_TEXT (sym); - int i; - while (1) - { - const char *dollar = strchr (text, '$'); - if (!dollar) - { - obstack_grow (obs, text, strlen (text)); - return; - } - obstack_grow (obs, text, dollar - text); - text = dollar; - switch (*++text) - { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if (no_gnu_extensions) - { - i = *text++ - '0'; - } - else - { - for (i = 0; isdigit (to_uchar (*text)); text++) - i = i*10 + (*text - '0'); - } - if (i < argc) - obstack_grow (obs, TOKEN_DATA_TEXT (argv[i]), - strlen (TOKEN_DATA_TEXT (argv[i]))); - break; - - case '#': /* number of arguments */ - shipout_int (obs, argc - 1); - text++; - break; - - case '*': /* all arguments */ - case '@': /* ... same, but quoted */ - dump_args (obs, argc, argv, ",", *text == '@'); - text++; - break; - - default: - obstack_1grow (obs, '$'); - break; - } - } -} diff --git a/contrib/tools/bison/m4/src/cpp.cpp b/contrib/tools/bison/m4/src/cpp.cpp deleted file mode 100644 index 19c4a90e13..0000000000 --- a/contrib/tools/bison/m4/src/cpp.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Just include a C++ header to tell stupid MSVC to link in C++ runtime providing wctype(). - -#include <cassert> diff --git a/contrib/tools/bison/m4/src/debug.c b/contrib/tools/bison/m4/src/debug.c deleted file mode 100644 index c13a205b89..0000000000 --- a/contrib/tools/bison/m4/src/debug.c +++ /dev/null @@ -1,442 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1991-1994, 2004, 2006-2007, 2009-2013 Free Software - Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "m4.h" - -#include <stdarg.h> -#include <sys/stat.h> - -/* File for debugging output. */ -FILE *debug = NULL; - -/* Obstack for trace messages. */ -static struct obstack trace; - -static void debug_set_file (FILE *); - -/*----------------------------------. -| Initialise the debugging module. | -`----------------------------------*/ - -void -debug_init (void) -{ - debug_set_file (stderr); - obstack_init (&trace); -} - -/*-----------------------------------------------------------------. -| Function to decode the debugging flags OPTS. Used by main while | -| processing option -d, and by the builtin debugmode (). | -`-----------------------------------------------------------------*/ - -int -debug_decode (const char *opts) -{ - int level; - - if (opts == NULL || *opts == '\0') - level = DEBUG_TRACE_DEFAULT; - else - { - for (level = 0; *opts; opts++) - { - switch (*opts) - { - case 'a': - level |= DEBUG_TRACE_ARGS; - break; - - case 'e': - level |= DEBUG_TRACE_EXPANSION; - break; - - case 'q': - level |= DEBUG_TRACE_QUOTE; - break; - - case 't': - level |= DEBUG_TRACE_ALL; - break; - - case 'l': - level |= DEBUG_TRACE_LINE; - break; - - case 'f': - level |= DEBUG_TRACE_FILE; - break; - - case 'p': - level |= DEBUG_TRACE_PATH; - break; - - case 'c': - level |= DEBUG_TRACE_CALL; - break; - - case 'i': - level |= DEBUG_TRACE_INPUT; - break; - - case 'x': - level |= DEBUG_TRACE_CALLID; - break; - - case 'V': - level |= DEBUG_TRACE_VERBOSE; - break; - - default: - return -1; - } - } - } - - /* This is to avoid screwing up the trace output due to changes in the - debug_level. */ - - obstack_free (&trace, obstack_finish (&trace)); - - return level; -} - -/*-----------------------------------------------------------------. -| Change the debug output stream to FP. If the underlying file is | -| the same as stdout, use stdout instead so that debug messages | -| appear in the correct relative position. | -`-----------------------------------------------------------------*/ - -static void -debug_set_file (FILE *fp) -{ - struct stat stdout_stat, debug_stat; - - if (debug != NULL && debug != stderr && debug != stdout - && close_stream (debug) != 0) - { - M4ERROR ((warning_status, errno, "error writing to debug stream")); - retcode = EXIT_FAILURE; - } - debug = fp; - - if (debug != NULL && debug != stdout) - { - if (fstat (STDOUT_FILENO, &stdout_stat) < 0) - return; - if (fstat (fileno (debug), &debug_stat) < 0) - return; - - /* mingw has a bug where fstat on a regular file reports st_ino - of 0. On normal system, st_ino should never be 0. */ - if (stdout_stat.st_ino == debug_stat.st_ino - && stdout_stat.st_dev == debug_stat.st_dev - && stdout_stat.st_ino != 0) - { - if (debug != stderr && close_stream (debug) != 0) - { - M4ERROR ((warning_status, errno, - "error writing to debug stream")); - retcode = EXIT_FAILURE; - } - debug = stdout; - } - } -} - -/*-----------------------------------------------------------. -| Serialize files. Used before executing a system command. | -`-----------------------------------------------------------*/ - -void -debug_flush_files (void) -{ - fflush (stdout); - fflush (stderr); - if (debug != NULL && debug != stdout && debug != stderr) - fflush (debug); - /* POSIX requires that if m4 doesn't consume all input, but stdin is - opened on a seekable file, that the file pointer be left at the - next character on exit (but places no restrictions on the file - pointer location on a non-seekable file). It also requires that - fflush() followed by fseeko() on an input file set the underlying - file pointer, and gnulib guarantees these semantics. However, - fflush() on a non-seekable file can lose buffered data, which we - might otherwise want to process after syscmd. Hence, we must - check whether stdin is seekable. We must also be tolerant of - operating with stdin closed, so we don't report any failures in - this attempt. The stdio-safer module and friends are essential, - so that if stdin was closed, this lseek is not on some other file - that we have since opened. */ - if (lseek (STDIN_FILENO, 0, SEEK_CUR) >= 0 - && fflush (stdin) == 0) - { - fseeko (stdin, 0, SEEK_CUR); - } -} - -/*--------------------------------------------------------------. -| Change the debug output to file NAME. If NAME is NULL, debug | -| output is reverted to stderr, and if empty, debug output is | -| discarded. Return true iff the output stream was changed. | -`--------------------------------------------------------------*/ - -bool -debug_set_output (const char *name) -{ - FILE *fp; - - if (name == NULL) - debug_set_file (stderr); - else if (*name == '\0') - debug_set_file (NULL); - else - { - fp = fopen (name, "a"); - if (fp == NULL) - return false; - - if (set_cloexec_flag (fileno (fp), true) != 0) - M4ERROR ((warning_status, errno, - "Warning: cannot protect debug file across forks")); - debug_set_file (fp); - } - return true; -} - -/*--------------------------------------------------------------. -| Print the header of a one-line debug message, starting by "m4 | -| debug". | -`--------------------------------------------------------------*/ - -void -debug_message_prefix (void) -{ - xfprintf (debug, "m4debug:"); - if (current_line) - { - if (debug_level & DEBUG_TRACE_FILE) - xfprintf (debug, "%s:", current_file); - if (debug_level & DEBUG_TRACE_LINE) - xfprintf (debug, "%d:", current_line); - } - putc (' ', debug); -} - -/* The rest of this file contains the functions for macro tracing output. - All tracing output for a macro call is collected on an obstack TRACE, - and printed whenever the line is complete. This prevents tracing - output from interfering with other debug messages generated by the - various builtins. */ - -/*------------------------------------------------------------------. -| Tracing output is formatted here, by a simplified | -| printf-to-obstack function trace_format (). Understands only %S, | -| %s, %d, %l (optional left quote) and %r (optional right quote). | -`------------------------------------------------------------------*/ - -static void -trace_format (const char *fmt, ...) -{ - va_list args; - char ch; - - int d; - const char *s; - int slen; - int maxlen; - - va_start (args, fmt); - - while (true) - { - while ((ch = *fmt++) != '\0' && ch != '%') - obstack_1grow (&trace, ch); - - if (ch == '\0') - break; - - maxlen = 0; - switch (*fmt++) - { - case 'S': - maxlen = max_debug_argument_length; - /* fall through */ - - case 's': - s = va_arg (args, const char *); - break; - - case 'l': - s = (debug_level & DEBUG_TRACE_QUOTE) ? lquote.string : ""; - break; - - case 'r': - s = (debug_level & DEBUG_TRACE_QUOTE) ? rquote.string : ""; - break; - - case 'd': - d = va_arg (args, int); - s = ntoa (d, 10); - break; - - default: - s = ""; - break; - } - - slen = strlen (s); - if (maxlen == 0 || maxlen > slen) - obstack_grow (&trace, s, slen); - else - { - obstack_grow (&trace, s, maxlen); - obstack_grow (&trace, "...", 3); - } - } - - va_end (args); -} - -/*------------------------------------------------------------------. -| Format the standard header attached to all tracing output lines. | -`------------------------------------------------------------------*/ - -static void -trace_header (int id) -{ - trace_format ("m4trace:"); - if (current_line) - { - if (debug_level & DEBUG_TRACE_FILE) - trace_format ("%s:", current_file); - if (debug_level & DEBUG_TRACE_LINE) - trace_format ("%d:", current_line); - } - trace_format (" -%d- ", expansion_level); - if (debug_level & DEBUG_TRACE_CALLID) - trace_format ("id %d: ", id); -} - -/*----------------------------------------------------. -| Print current tracing line, and clear the obstack. | -`----------------------------------------------------*/ - -static void -trace_flush (void) -{ - char *line; - - obstack_1grow (&trace, '\0'); - line = (char *) obstack_finish (&trace); - DEBUG_PRINT1 ("%s\n", line); - obstack_free (&trace, line); -} - -/*-------------------------------------------------------------. -| Do pre-argument-collction tracing for macro NAME. Used from | -| expand_macro (). | -`-------------------------------------------------------------*/ - -void -trace_prepre (const char *name, int id) -{ - trace_header (id); - trace_format ("%s ...", name); - trace_flush (); -} - -/*--------------------------------------------------------------. -| Format the parts of a trace line, that can be made before the | -| macro is actually expanded. Used from expand_macro (). | -`--------------------------------------------------------------*/ - -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 (); - } - - } - trace_format (")"); - } - - if (debug_level & DEBUG_TRACE_CALL) - { - trace_format (" -> ???"); - trace_flush (); - } -} - -/*-------------------------------------------------------------------. -| Format the final part of a trace line and print it all. Used from | -| expand_macro (). | -`-------------------------------------------------------------------*/ - -void -trace_post (const char *name, int id, int argc, const char *expanded) -{ - if (debug_level & DEBUG_TRACE_CALL) - { - trace_header (id); - trace_format ("%s%s", name, (argc > 1) ? "(...)" : ""); - } - - if (expanded && (debug_level & DEBUG_TRACE_EXPANSION)) - trace_format (" -> %l%S%r", expanded); - trace_flush (); -} diff --git a/contrib/tools/bison/m4/src/eval.c b/contrib/tools/bison/m4/src/eval.c deleted file mode 100644 index 8b4b05afb1..0000000000 --- a/contrib/tools/bison/m4/src/eval.c +++ /dev/null @@ -1,855 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2006-2007, 2009-2013 Free Software - Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* This file contains the functions to evaluate integer expressions for - the "eval" macro. It is a little, fairly self-contained module, with - its own scanner, and a recursive descent parser. The only entry point - is evaluate (). */ - -#include "m4.h" - -/* Evaluates token types. */ - -typedef enum eval_token - { - ERROR, BADOP, - PLUS, MINUS, - EXPONENT, - TIMES, DIVIDE, MODULO, - ASSIGN, EQ, NOTEQ, GT, GTEQ, LS, LSEQ, - LSHIFT, RSHIFT, - LNOT, LAND, LOR, - NOT, AND, OR, XOR, - LEFTP, RIGHTP, - NUMBER, EOTEXT - } -eval_token; - -/* Error types. */ - -typedef enum eval_error - { - NO_ERROR, - DIVIDE_ZERO, - MODULO_ZERO, - NEGATIVE_EXPONENT, - /* All errors prior to SYNTAX_ERROR can be ignored in a dead - branch of && and ||. All errors after are just more details - about a syntax error. */ - SYNTAX_ERROR, - MISSING_RIGHT, - UNKNOWN_INPUT, - EXCESS_INPUT, - INVALID_OPERATOR - } -eval_error; - -static eval_error logical_or_term (eval_token, int32_t *); -static eval_error logical_and_term (eval_token, int32_t *); -static eval_error or_term (eval_token, int32_t *); -static eval_error xor_term (eval_token, int32_t *); -static eval_error and_term (eval_token, int32_t *); -static eval_error equality_term (eval_token, int32_t *); -static eval_error cmp_term (eval_token, int32_t *); -static eval_error shift_term (eval_token, int32_t *); -static eval_error add_term (eval_token, int32_t *); -static eval_error mult_term (eval_token, int32_t *); -static eval_error exp_term (eval_token, int32_t *); -static eval_error unary_term (eval_token, int32_t *); -static eval_error simple_term (eval_token, int32_t *); - -/*--------------------. -| Lexical functions. | -`--------------------*/ - -/* Pointer to next character of input text. */ -static const char *eval_text; - -/* Value of eval_text, from before last call of eval_lex (). This is so we - can back up, if we have read too much. */ -static const char *last_text; - -static void -eval_init_lex (const char *text) -{ - eval_text = text; - last_text = NULL; -} - -static void -eval_undo (void) -{ - eval_text = last_text; -} - -/* VAL is numerical value, if any. */ - -static eval_token -eval_lex (int32_t *val) -{ - while (isspace (to_uchar (*eval_text))) - eval_text++; - - last_text = eval_text; - - if (*eval_text == '\0') - return EOTEXT; - - if (isdigit (to_uchar (*eval_text))) - { - int base, digit; - - if (*eval_text == '0') - { - eval_text++; - switch (*eval_text) - { - case 'x': - case 'X': - base = 16; - eval_text++; - break; - - case 'b': - case 'B': - base = 2; - eval_text++; - break; - - case 'r': - case 'R': - base = 0; - eval_text++; - while (isdigit (to_uchar (*eval_text)) && base <= 36) - base = 10 * base + *eval_text++ - '0'; - if (base == 0 || base > 36 || *eval_text != ':') - return ERROR; - eval_text++; - break; - - default: - base = 8; - } - } - else - base = 10; - - /* FIXME - this calculation can overflow. Consider xstrtol. */ - *val = 0; - for (; *eval_text; eval_text++) - { - if (isdigit (to_uchar (*eval_text))) - digit = *eval_text - '0'; - else if (islower (to_uchar (*eval_text))) - digit = *eval_text - 'a' + 10; - else if (isupper (to_uchar (*eval_text))) - digit = *eval_text - 'A' + 10; - else - break; - - if (base == 1) - { - if (digit == 1) - (*val)++; - else if (digit == 0 && !*val) - continue; - else - break; - } - else if (digit >= base) - break; - else - *val = *val * base + digit; - } - return NUMBER; - } - - switch (*eval_text++) - { - case '+': - if (*eval_text == '+' || *eval_text == '=') - return BADOP; - return PLUS; - case '-': - if (*eval_text == '-' || *eval_text == '=') - return BADOP; - return MINUS; - case '*': - if (*eval_text == '*') - { - eval_text++; - return EXPONENT; - } - else if (*eval_text == '=') - return BADOP; - return TIMES; - case '/': - if (*eval_text == '=') - return BADOP; - return DIVIDE; - case '%': - if (*eval_text == '=') - return BADOP; - return MODULO; - case '=': - if (*eval_text == '=') - { - eval_text++; - return EQ; - } - return ASSIGN; - case '!': - if (*eval_text == '=') - { - eval_text++; - return NOTEQ; - } - return LNOT; - case '>': - if (*eval_text == '=') - { - eval_text++; - return GTEQ; - } - else if (*eval_text == '>') - { - if (*++eval_text == '=') - return BADOP; - return RSHIFT; - } - return GT; - case '<': - if (*eval_text == '=') - { - eval_text++; - return LSEQ; - } - else if (*eval_text == '<') - { - if (*++eval_text == '=') - return BADOP; - return LSHIFT; - } - return LS; - case '^': - if (*eval_text == '=') - return BADOP; - return XOR; - case '~': - return NOT; - case '&': - if (*eval_text == '&') - { - eval_text++; - return LAND; - } - else if (*eval_text == '=') - return BADOP; - return AND; - case '|': - if (*eval_text == '|') - { - eval_text++; - return LOR; - } - else if (*eval_text == '=') - return BADOP; - return OR; - case '(': - return LEFTP; - case ')': - return RIGHTP; - default: - return ERROR; - } -} - -/*---------------------------------------. -| Main entry point, called from "eval". | -`---------------------------------------*/ - -bool -evaluate (const char *expr, int32_t *val) -{ - eval_token et; - eval_error err; - - eval_init_lex (expr); - et = eval_lex (val); - err = logical_or_term (et, val); - - if (err == NO_ERROR && *eval_text != '\0') - { - if (eval_lex (val) == BADOP) - err = INVALID_OPERATOR; - else - err = EXCESS_INPUT; - } - - switch (err) - { - case NO_ERROR: - break; - - case MISSING_RIGHT: - M4ERROR ((warning_status, 0, - "bad expression in eval (missing right parenthesis): %s", - expr)); - break; - - case SYNTAX_ERROR: - M4ERROR ((warning_status, 0, - "bad expression in eval: %s", expr)); - break; - - case UNKNOWN_INPUT: - M4ERROR ((warning_status, 0, - "bad expression in eval (bad input): %s", expr)); - break; - - case EXCESS_INPUT: - M4ERROR ((warning_status, 0, - "bad expression in eval (excess input): %s", expr)); - break; - - case INVALID_OPERATOR: - M4ERROR ((warning_status, 0, - "invalid operator in eval: %s", expr)); - retcode = EXIT_FAILURE; - break; - - case DIVIDE_ZERO: - M4ERROR ((warning_status, 0, - "divide by zero in eval: %s", expr)); - break; - - case MODULO_ZERO: - M4ERROR ((warning_status, 0, - "modulo by zero in eval: %s", expr)); - break; - - case NEGATIVE_EXPONENT: - M4ERROR ((warning_status, 0, - "negative exponent in eval: %s", expr)); - break; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad error code in evaluate ()")); - abort (); - } - - return err != NO_ERROR; -} - -/*---------------------------. -| Recursive descent parser. | -`---------------------------*/ - -static eval_error -logical_or_term (eval_token et, int32_t *v1) -{ - int32_t v2; - eval_error er; - - if ((er = logical_and_term (et, v1)) != NO_ERROR) - return er; - - while ((et = eval_lex (&v2)) == LOR) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - /* Implement short-circuiting of valid syntax. */ - er = logical_and_term (et, &v2); - if (er == NO_ERROR) - *v1 = *v1 || v2; - else if (*v1 != 0 && er < SYNTAX_ERROR) - *v1 = 1; - else - return er; - } - if (et == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -logical_and_term (eval_token et, int32_t *v1) -{ - int32_t v2; - eval_error er; - - if ((er = or_term (et, v1)) != NO_ERROR) - return er; - - while ((et = eval_lex (&v2)) == LAND) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - /* Implement short-circuiting of valid syntax. */ - er = or_term (et, &v2); - if (er == NO_ERROR) - *v1 = *v1 && v2; - else if (*v1 == 0 && er < SYNTAX_ERROR) - ; /* v1 is already 0 */ - else - return er; - } - if (et == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -or_term (eval_token et, int32_t *v1) -{ - int32_t v2; - eval_error er; - - if ((er = xor_term (et, v1)) != NO_ERROR) - return er; - - while ((et = eval_lex (&v2)) == OR) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = xor_term (et, &v2)) != NO_ERROR) - return er; - - *v1 |= v2; - } - if (et == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -xor_term (eval_token et, int32_t *v1) -{ - int32_t v2; - eval_error er; - - if ((er = and_term (et, v1)) != NO_ERROR) - return er; - - while ((et = eval_lex (&v2)) == XOR) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = and_term (et, &v2)) != NO_ERROR) - return er; - - *v1 ^= v2; - } - if (et == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -and_term (eval_token et, int32_t *v1) -{ - int32_t v2; - eval_error er; - - if ((er = equality_term (et, v1)) != NO_ERROR) - return er; - - while ((et = eval_lex (&v2)) == AND) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = equality_term (et, &v2)) != NO_ERROR) - return er; - - *v1 &= v2; - } - if (et == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -equality_term (eval_token et, int32_t *v1) -{ - eval_token op; - int32_t v2; - eval_error er; - - if ((er = cmp_term (et, v1)) != NO_ERROR) - return er; - - /* In the 1.4.x series, we maintain the traditional behavior that - '=' is a synonym for '=='; however, this is contrary to POSIX and - we hope to convert '=' to mean assignment in 2.0. */ - while ((op = eval_lex (&v2)) == EQ || op == NOTEQ || op == ASSIGN) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = cmp_term (et, &v2)) != NO_ERROR) - return er; - - if (op == ASSIGN) - { - M4ERROR ((warning_status, 0, "\ -Warning: recommend ==, not =, for equality operator")); - op = EQ; - } - *v1 = (op == EQ) == (*v1 == v2); - } - if (op == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -cmp_term (eval_token et, int32_t *v1) -{ - eval_token op; - int32_t v2; - eval_error er; - - if ((er = shift_term (et, v1)) != NO_ERROR) - return er; - - while ((op = eval_lex (&v2)) == GT || op == GTEQ - || op == LS || op == LSEQ) - { - - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = shift_term (et, &v2)) != NO_ERROR) - return er; - - switch (op) - { - case GT: - *v1 = *v1 > v2; - break; - - case GTEQ: - *v1 = *v1 >= v2; - break; - - case LS: - *v1 = *v1 < v2; - break; - - case LSEQ: - *v1 = *v1 <= v2; - break; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad comparison operator in cmp_term ()")); - abort (); - } - } - if (op == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -shift_term (eval_token et, int32_t *v1) -{ - eval_token op; - int32_t v2; - uint32_t u1; - eval_error er; - - if ((er = add_term (et, v1)) != NO_ERROR) - return er; - - while ((op = eval_lex (&v2)) == LSHIFT || op == RSHIFT) - { - - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = add_term (et, &v2)) != NO_ERROR) - return er; - - /* Minimize undefined C behavior (shifting by a negative number, - shifting by the width or greater, left shift overflow, or - right shift of a negative number). Implement Java 32-bit - wrap-around semantics. This code assumes that the - implementation-defined overflow when casting unsigned to - signed is a silent twos-complement wrap-around. */ - switch (op) - { - case LSHIFT: - u1 = *v1; - u1 <<= (uint32_t) (v2 & 0x1f); - *v1 = u1; - break; - - case RSHIFT: - u1 = *v1 < 0 ? ~*v1 : *v1; - u1 >>= (uint32_t) (v2 & 0x1f); - *v1 = *v1 < 0 ? ~u1 : u1; - break; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad shift operator in shift_term ()")); - abort (); - } - } - if (op == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -add_term (eval_token et, int32_t *v1) -{ - eval_token op; - int32_t v2; - eval_error er; - - if ((er = mult_term (et, v1)) != NO_ERROR) - return er; - - while ((op = eval_lex (&v2)) == PLUS || op == MINUS) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = mult_term (et, &v2)) != NO_ERROR) - return er; - - /* Minimize undefined C behavior on overflow. This code assumes - that the implementation-defined overflow when casting - unsigned to signed is a silent twos-complement - wrap-around. */ - if (op == PLUS) - *v1 = (int32_t) ((uint32_t) *v1 + (uint32_t) v2); - else - *v1 = (int32_t) ((uint32_t) *v1 - (uint32_t) v2); - } - if (op == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -mult_term (eval_token et, int32_t *v1) -{ - eval_token op; - int32_t v2; - eval_error er; - - if ((er = exp_term (et, v1)) != NO_ERROR) - return er; - - while ((op = eval_lex (&v2)) == TIMES || op == DIVIDE || op == MODULO) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = exp_term (et, &v2)) != NO_ERROR) - return er; - - /* Minimize undefined C behavior on overflow. This code assumes - that the implementation-defined overflow when casting - unsigned to signed is a silent twos-complement - wrap-around. */ - switch (op) - { - case TIMES: - *v1 = (int32_t) ((uint32_t) *v1 * (uint32_t) v2); - break; - - case DIVIDE: - if (v2 == 0) - return DIVIDE_ZERO; - else if (v2 == -1) - /* Avoid overflow, and the x86 SIGFPE on INT_MIN / -1. */ - *v1 = (int32_t) -(uint32_t) *v1; - else - *v1 /= v2; - break; - - case MODULO: - if (v2 == 0) - return MODULO_ZERO; - else if (v2 == -1) - /* Avoid the x86 SIGFPE on INT_MIN % -1. */ - *v1 = 0; - else - *v1 %= v2; - break; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad operator in mult_term ()")); - abort (); - } - } - if (op == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -exp_term (eval_token et, int32_t *v1) -{ - uint32_t result; - int32_t v2; - eval_error er; - - if ((er = unary_term (et, v1)) != NO_ERROR) - return er; - - while ((et = eval_lex (&v2)) == EXPONENT) - { - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = exp_term (et, &v2)) != NO_ERROR) - return er; - - /* Minimize undefined C behavior on overflow. This code assumes - that the implementation-defined overflow when casting - unsigned to signed is a silent twos-complement - wrap-around. */ - result = 1; - if (v2 < 0) - return NEGATIVE_EXPONENT; - if (*v1 == 0 && v2 == 0) - return DIVIDE_ZERO; - while (v2-- > 0) - result *= (uint32_t) *v1; - *v1 = result; - } - if (et == ERROR) - return UNKNOWN_INPUT; - - eval_undo (); - return NO_ERROR; -} - -static eval_error -unary_term (eval_token et, int32_t *v1) -{ - eval_error er; - - if (et == PLUS || et == MINUS || et == NOT || et == LNOT) - { - eval_token et2 = eval_lex (v1); - if (et2 == ERROR) - return UNKNOWN_INPUT; - - if ((er = unary_term (et2, v1)) != NO_ERROR) - return er; - - /* Minimize undefined C behavior on overflow. This code assumes - that the implementation-defined overflow when casting - unsigned to signed is a silent twos-complement - wrap-around. */ - if (et == MINUS) - *v1 = (int32_t) -(uint32_t) *v1; - else if (et == NOT) - *v1 = ~*v1; - else if (et == LNOT) - *v1 = *v1 == 0 ? 1 : 0; - } - else if ((er = simple_term (et, v1)) != NO_ERROR) - return er; - - return NO_ERROR; -} - -static eval_error -simple_term (eval_token et, int32_t *v1) -{ - int32_t v2; - eval_error er; - - switch (et) - { - case LEFTP: - et = eval_lex (v1); - if (et == ERROR) - return UNKNOWN_INPUT; - - if ((er = logical_or_term (et, v1)) != NO_ERROR) - return er; - - et = eval_lex (&v2); - if (et == ERROR) - return UNKNOWN_INPUT; - - if (et != RIGHTP) - return MISSING_RIGHT; - - break; - - case NUMBER: - break; - - case BADOP: - return INVALID_OPERATOR; - - default: - return SYNTAX_ERROR; - } - return NO_ERROR; -} diff --git a/contrib/tools/bison/m4/src/format.c b/contrib/tools/bison/m4/src/format.c deleted file mode 100644 index fd8830ed7c..0000000000 --- a/contrib/tools/bison/m4/src/format.c +++ /dev/null @@ -1,394 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2006-2013 Free Software Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* printf like formatting for m4. */ - -#include "m4.h" -#include "xvasprintf.h" - -/* Simple varargs substitute. We assume int and unsigned int are the - same size; likewise for long and unsigned long. */ - -/* Parse STR as an integer, reporting warnings. */ -static int -arg_int (const char *str) -{ - char *endp; - long value; - size_t len = strlen (str); - - if (!len) - { - M4ERROR ((warning_status, 0, _("empty string treated as 0"))); - return 0; - } - errno = 0; - value = strtol (str, &endp, 10); - if (endp - str - len) - M4ERROR ((warning_status, 0, _("non-numeric argument %s"), str)); - else if (isspace (to_uchar (*str))) - M4ERROR ((warning_status, 0, _("leading whitespace ignored"))); - else if (errno == ERANGE || (int) value != value) - M4ERROR ((warning_status, 0, _("numeric overflow detected"))); - return value; -} - -/* Parse STR as a long, reporting warnings. */ -static long -arg_long (const char *str) -{ - char *endp; - long value; - size_t len = strlen (str); - - if (!len) - { - M4ERROR ((warning_status, 0, _("empty string treated as 0"))); - return 0L; - } - errno = 0; - value = strtol (str, &endp, 10); - if (endp - str - len) - M4ERROR ((warning_status, 0, _("non-numeric argument %s"), str)); - else if (isspace (to_uchar (*str))) - M4ERROR ((warning_status, 0, _("leading whitespace ignored"))); - else if (errno == ERANGE) - M4ERROR ((warning_status, 0, _("numeric overflow detected"))); - return value; -} - -/* Parse STR as a double, reporting warnings. */ -static double -arg_double (const char *str) -{ - char *endp; - double value; - size_t len = strlen (str); - - if (!len) - { - M4ERROR ((warning_status, 0, _("empty string treated as 0"))); - return 0.0; - } - errno = 0; - value = strtod (str, &endp); - if (endp - str - len) - M4ERROR ((warning_status, 0, _("non-numeric argument %s"), str)); - else if (isspace (to_uchar (*str))) - M4ERROR ((warning_status, 0, _("leading whitespace ignored"))); - else if (errno == ERANGE) - M4ERROR ((warning_status, 0, _("numeric overflow detected"))); - return value; -} - -#define ARG_INT(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, arg_int (TOKEN_DATA_TEXT (argv[-1])))) - -#define ARG_LONG(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, arg_long (TOKEN_DATA_TEXT (argv[-1])))) - -#define ARG_STR(argc, argv) \ - ((argc == 0) ? "" : \ - (--argc, argv++, TOKEN_DATA_TEXT (argv[-1]))) - -#define ARG_DOUBLE(argc, argv) \ - ((argc == 0) ? 0 : \ - (--argc, argv++, arg_double (TOKEN_DATA_TEXT (argv[-1])))) - - -/*------------------------------------------------------------------. -| The main formatting function. Output is placed on the obstack | -| OBS, the first argument in ARGV is the formatting string, and the | -| rest is arguments for the string. Warn rather than invoke | -| unspecified behavior in the underlying printf when we do not | -| recognize a format. | -`------------------------------------------------------------------*/ - -void -expand_format (struct obstack *obs, int argc, token_data **argv) -{ - const char *f; /* format control string */ - const char *fmt; /* position within f */ - char fstart[] = "%'+- 0#*.*hhd"; /* current format spec */ - char *p; /* position within fstart */ - unsigned char c; /* a simple character */ - - /* Flags. */ - char flags; /* flags to use in fstart */ - enum { - THOUSANDS = 0x01, /* ' */ - PLUS = 0x02, /* + */ - MINUS = 0x04, /* - */ - SPACE = 0x08, /* */ - ZERO = 0x10, /* 0 */ - ALT = 0x20, /* # */ - DONE = 0x40 /* no more flags */ - }; - - /* Precision specifiers. */ - int width; /* minimum field width */ - int prec; /* precision */ - char lflag; /* long flag */ - - /* Specifiers we are willing to accept. ok['x'] implies %x is ok. - Various modifiers reduce the set, in order to avoid undefined - behavior in printf. */ - char ok[128]; - - /* Buffer and stuff. */ - char *str; /* malloc'd buffer of formatted text */ - enum {CHAR, INT, LONG, DOUBLE, STR} datatype; - - f = fmt = ARG_STR (argc, argv); - memset (ok, 0, sizeof ok); - while (1) - { - const char *percent = strchr (fmt, '%'); - if (!percent) - { - obstack_grow (obs, fmt, strlen (fmt)); - return; - } - obstack_grow (obs, fmt, percent - fmt); - fmt = percent + 1; - - if (*fmt == '%') - { - obstack_1grow (obs, '%'); - fmt++; - continue; - } - - p = fstart + 1; /* % */ - lflag = 0; - ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] - = ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] - = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1; - - /* Parse flags. */ - flags = 0; - do - { - switch (*fmt) - { - case '\'': /* thousands separator */ - ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] - = ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0; - flags |= THOUSANDS; - break; - - case '+': /* mandatory sign */ - ok['c'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 0; - flags |= PLUS; - break; - - case ' ': /* space instead of positive sign */ - ok['c'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 0; - flags |= SPACE; - break; - - case '0': /* zero padding */ - ok['c'] = ok['s'] = 0; - flags |= ZERO; - break; - - case '#': /* alternate output */ - ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0; - flags |= ALT; - break; - - case '-': /* left justification */ - flags |= MINUS; - break; - - default: - flags |= DONE; - break; - } - } - while (!(flags & DONE) && fmt++); - if (flags & THOUSANDS) - *p++ = '\''; - if (flags & PLUS) - *p++ = '+'; - if (flags & MINUS) - *p++ = '-'; - if (flags & SPACE) - *p++ = ' '; - if (flags & ZERO) - *p++ = '0'; - if (flags & ALT) - *p++ = '#'; - - /* Minimum field width; an explicit 0 is the same as not giving - the width. */ - width = 0; - *p++ = '*'; - if (*fmt == '*') - { - width = ARG_INT (argc, argv); - fmt++; - } - else - while (isdigit (to_uchar (*fmt))) - { - width = 10 * width + *fmt - '0'; - fmt++; - } - - /* Maximum precision; an explicit negative precision is the same - as not giving the precision. A lone '.' is a precision of 0. */ - prec = -1; - *p++ = '.'; - *p++ = '*'; - if (*fmt == '.') - { - ok['c'] = 0; - if (*(++fmt) == '*') - { - prec = ARG_INT (argc, argv); - ++fmt; - } - else - { - prec = 0; - while (isdigit (to_uchar (*fmt))) - { - prec = 10 * prec + *fmt - '0'; - fmt++; - } - } - } - - /* Length modifiers. We don't yet recognize ll, j, t, or z. */ - if (*fmt == 'l') - { - *p++ = 'l'; - lflag = 1; - fmt++; - ok['c'] = ok['s'] = 0; - } - else if (*fmt == 'h') - { - *p++ = 'h'; - fmt++; - if (*fmt == 'h') - { - *p++ = 'h'; - fmt++; - } - ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = ok['f'] = ok['F'] - = ok['g'] = ok['G'] = ok['s'] = 0; - } - - c = *fmt++; - if (sizeof ok <= c || !ok[c]) - { - M4ERROR ((warning_status, 0, - "Warning: unrecognized specifier in `%s'", f)); - if (c == '\0') - fmt--; - continue; - } - - /* Specifiers. We don't yet recognize C, S, n, or p. */ - switch (c) - { - case 'c': - datatype = CHAR; - p -= 2; /* %.*c is undefined, so undo the '.*'. */ - break; - - case 's': - datatype = STR; - break; - - case 'd': - case 'i': - case 'o': - case 'x': - case 'X': - case 'u': - datatype = lflag ? LONG : INT; - break; - - case 'a': - case 'A': - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - datatype = DOUBLE; - break; - - default: - abort (); - } - *p++ = c; - *p = '\0'; - - /* Our constructed format string in fstart is safe. */ -#if 4 < __GNUC__ + (6 <= __GNUC_MINOR__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wformat-nonliteral" -#endif - - switch (datatype) - { - case CHAR: - str = xasprintf (fstart, width, ARG_INT(argc, argv)); - break; - - case INT: - str = xasprintf (fstart, width, prec, ARG_INT(argc, argv)); - break; - - case LONG: - str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv)); - break; - - case DOUBLE: - str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv)); - break; - - case STR: - str = xasprintf (fstart, width, prec, ARG_STR(argc, argv)); - break; - - default: - abort(); - } -#if 4 < __GNUC__ + (6 <= __GNUC_MINOR__) -# pragma GCC diagnostic pop -#endif - - /* NULL was returned on failure, such as invalid format string. For - now, just silently ignore that bad specifier. */ - if (str == NULL) - continue; - - obstack_grow (obs, str, strlen (str)); - free (str); - } -} diff --git a/contrib/tools/bison/m4/src/freeze.c b/contrib/tools/bison/m4/src/freeze.c deleted file mode 100644 index edc0568b96..0000000000 --- a/contrib/tools/bison/m4/src/freeze.c +++ /dev/null @@ -1,398 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2006-2013 Free Software Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* This module handles frozen files. */ - -#include "m4.h" - -/*-------------------------------------------------------------------. -| Destructively reverse a symbol list and return the reversed list. | -`-------------------------------------------------------------------*/ - -static symbol * -reverse_symbol_list (symbol *sym) -{ - symbol *result; - symbol *next; - - result = NULL; - while (sym) - { - next = SYMBOL_NEXT (sym); - SYMBOL_NEXT (sym) = result; - result = sym; - sym = next; - } - return result; -} - -/*------------------------------------------------. -| Produce a frozen state to the given file NAME. | -`------------------------------------------------*/ - -void -produce_frozen_state (const char *name) -{ - FILE *file; - size_t h; - symbol *sym; - const builtin *bp; - - file = fopen (name, O_BINARY ? "wb" : "w"); - if (!file) - { - M4ERROR ((EXIT_FAILURE, errno, "cannot open `%s'", name)); - return; - } - - /* Write a recognizable header. */ - - xfprintf (file, "# This is a frozen state file generated by %s\n", - PACKAGE_STRING); - xfprintf (file, "V1\n"); - - /* Dump quote delimiters. */ - - if (strcmp (lquote.string, DEF_LQUOTE) || strcmp (rquote.string, DEF_RQUOTE)) - { - xfprintf (file, "Q%d,%d\n", (int) lquote.length, (int) rquote.length); - fputs (lquote.string, file); - fputs (rquote.string, file); - fputc ('\n', file); - } - - /* Dump comment delimiters. */ - - if (strcmp (bcomm.string, DEF_BCOMM) || strcmp (ecomm.string, DEF_ECOMM)) - { - xfprintf (file, "C%d,%d\n", (int) bcomm.length, (int) ecomm.length); - fputs (bcomm.string, file); - fputs (ecomm.string, file); - fputc ('\n', file); - } - - /* Dump all symbols. */ - - for (h = 0; h < hash_table_size; h++) - { - - /* Process all entries in one bucket, from the last to the first. - This order ensures that, at reload time, pushdef's will be - executed with the oldest definitions first. */ - - symtab[h] = reverse_symbol_list (symtab[h]); - for (sym = symtab[h]; sym; sym = SYMBOL_NEXT (sym)) - { - switch (SYMBOL_TYPE (sym)) - { - case TOKEN_TEXT: - xfprintf (file, "T%d,%d\n", - (int) strlen (SYMBOL_NAME (sym)), - (int) strlen (SYMBOL_TEXT (sym))); - fputs (SYMBOL_NAME (sym), file); - fputs (SYMBOL_TEXT (sym), file); - fputc ('\n', file); - break; - - case TOKEN_FUNC: - bp = find_builtin_by_addr (SYMBOL_FUNC (sym)); - if (bp == NULL) - { - M4ERROR ((warning_status, 0, "\ -INTERNAL ERROR: builtin not found in builtin table!")); - abort (); - } - xfprintf (file, "F%d,%d\n", - (int) strlen (SYMBOL_NAME (sym)), - (int) strlen (bp->name)); - fputs (SYMBOL_NAME (sym), file); - fputs (bp->name, file); - fputc ('\n', file); - break; - - case TOKEN_VOID: - /* Ignore placeholder tokens that exist due to traceon. */ - break; - - default: - M4ERROR ((warning_status, 0, "\ -INTERNAL ERROR: bad token data type in freeze_one_symbol ()")); - abort (); - break; - } - } - - /* Reverse the bucket once more, putting it back as it was. */ - - symtab[h] = reverse_symbol_list (symtab[h]); - } - - /* Let diversions be issued from output.c module, its cleaner to have this - piece of code there. */ - - freeze_diversions (file); - - /* All done. */ - - fputs ("# End of frozen state file\n", file); - if (close_stream (file) != 0) - M4ERROR ((EXIT_FAILURE, errno, "unable to create frozen state")); -} - -/*----------------------------------------------------------------------. -| Issue a message saying that some character is an EXPECTED character. | -`----------------------------------------------------------------------*/ - -static void -issue_expect_message (int expected) -{ - if (expected == '\n') - M4ERROR ((EXIT_FAILURE, 0, "expecting line feed in frozen file")); - else - M4ERROR ((EXIT_FAILURE, 0, "expecting character `%c' in frozen file", - expected)); -} - -/*-------------------------------------------------. -| Reload a frozen state from the given file NAME. | -`-------------------------------------------------*/ - -/* We are seeking speed, here. */ - -void -reload_frozen_state (const char *name) -{ - FILE *file; - int character; - int operation; - char *string[2]; - int allocated[2]; - int number[2]; - const builtin *bp; - bool advance_line = true; - -#define GET_CHARACTER \ - do \ - { \ - if (advance_line) \ - { \ - current_line++; \ - advance_line = false; \ - } \ - (character = getc (file)); \ - if (character == '\n') \ - advance_line = true; \ - } \ - while (0) - -#define GET_NUMBER(Number, AllowNeg) \ - do \ - { \ - unsigned int n = 0; \ - while (isdigit (character) && n <= INT_MAX / 10U) \ - { \ - n = 10 * n + character - '0'; \ - GET_CHARACTER; \ - } \ - if (((AllowNeg) ? INT_MIN : INT_MAX) + 0U < n \ - || isdigit (character)) \ - m4_error (EXIT_FAILURE, 0, \ - _("integer overflow in frozen file")); \ - (Number) = n; \ - } \ - while (0) - -#define VALIDATE(Expected) \ - do \ - { \ - if (character != (Expected)) \ - issue_expect_message (Expected); \ - } \ - while (0) - - /* Skip comments (`#' at beginning of line) and blank lines, setting - character to the next directive or to EOF. */ - -#define GET_DIRECTIVE \ - do \ - { \ - GET_CHARACTER; \ - if (character == '#') \ - { \ - while (character != EOF && character != '\n') \ - GET_CHARACTER; \ - VALIDATE ('\n'); \ - } \ - } \ - while (character == '\n') - -#define GET_STRING(i) \ - do \ - { \ - void *tmp; \ - char *p; \ - if (number[(i)] + 1 > allocated[(i)]) \ - { \ - free (string[(i)]); \ - allocated[(i)] = number[(i)] + 1; \ - string[(i)] = xcharalloc ((size_t) allocated[(i)]); \ - } \ - if (number[(i)] > 0 \ - && !fread (string[(i)], (size_t) number[(i)], 1, file)) \ - m4_error (EXIT_FAILURE, 0, \ - _("premature end of frozen file")); \ - string[(i)][number[(i)]] = '\0'; \ - p = string[(i)]; \ - while ((tmp = memchr(p, '\n', number[(i)] - (p - string[(i)])))) \ - { \ - current_line++; \ - p = (char *) tmp + 1; \ - } \ - } \ - while (0) - - file = m4_path_search (name, NULL); - if (file == NULL) - M4ERROR ((EXIT_FAILURE, errno, "cannot open %s", name)); - current_file = name; - - allocated[0] = 100; - string[0] = xcharalloc ((size_t) allocated[0]); - allocated[1] = 100; - string[1] = xcharalloc ((size_t) allocated[1]); - - /* Validate format version. Only `1' is acceptable for now. */ - GET_DIRECTIVE; - VALIDATE ('V'); - GET_CHARACTER; - GET_NUMBER (number[0], false); - if (number[0] > 1) - M4ERROR ((EXIT_MISMATCH, 0, - "frozen file version %d greater than max supported of 1", - number[0])); - else if (number[0] < 1) - M4ERROR ((EXIT_FAILURE, 0, - "ill-formed frozen file, version directive expected")); - VALIDATE ('\n'); - - GET_DIRECTIVE; - while (character != EOF) - { - switch (character) - { - default: - M4ERROR ((EXIT_FAILURE, 0, "ill-formed frozen file")); - - case 'C': - case 'D': - case 'F': - case 'T': - case 'Q': - operation = character; - GET_CHARACTER; - - /* Get string lengths. Accept a negative diversion number. */ - - if (operation == 'D' && character == '-') - { - GET_CHARACTER; - GET_NUMBER (number[0], true); - number[0] = -number[0]; - } - else - GET_NUMBER (number[0], false); - VALIDATE (','); - GET_CHARACTER; - GET_NUMBER (number[1], false); - VALIDATE ('\n'); - - if (operation != 'D') - GET_STRING (0); - GET_STRING (1); - GET_CHARACTER; - VALIDATE ('\n'); - - /* Act according to operation letter. */ - - switch (operation) - { - case 'C': - - /* Change comment strings. */ - - set_comment (string[0], string[1]); - break; - - case 'D': - - /* Select a diversion and add a string to it. */ - - make_diversion (number[0]); - if (number[1] > 0) - output_text (string[1], number[1]); - break; - - case 'F': - - /* Enter a macro having a builtin function as a definition. */ - - bp = find_builtin_by_name (string[1]); - define_builtin (string[0], bp, SYMBOL_PUSHDEF); - break; - - case 'T': - - /* Enter a macro having an expansion text as a definition. */ - - define_user_macro (string[0], string[1], SYMBOL_PUSHDEF); - break; - - case 'Q': - - /* Change quote strings. */ - - set_quotes (string[0], string[1]); - break; - - default: - - /* Cannot happen. */ - - break; - } - break; - - } - GET_DIRECTIVE; - } - - free (string[0]); - free (string[1]); - if (close_stream (file) != 0) - m4_error (EXIT_FAILURE, errno, _("unable to read frozen state")); - current_file = NULL; - current_line = 0; - -#undef GET_CHARACTER -#undef GET_DIRECTIVE -#undef GET_NUMBER -#undef VALIDATE -#undef GET_STRING -} diff --git a/contrib/tools/bison/m4/src/input.c b/contrib/tools/bison/m4/src/input.c deleted file mode 100644 index 836d706489..0000000000 --- a/contrib/tools/bison/m4/src/input.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2004-2013 Free Software Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* Handling of different input sources, and lexical analysis. */ - -#include "m4.h" - -#include "memchr2.h" - -/* Unread input can be either files, that should be read (eg. included - files), strings, which should be rescanned (eg. macro expansion text), - or quoted macro definitions (as returned by the builtin "defn"). - Unread input are organised in a stack, implemented with an obstack. - Each input source is described by a "struct input_block". The obstack - is "current_input". The top of the input stack is "isp". - - The macro "m4wrap" places the text to be saved on another input - stack, on the obstack "wrapup_stack", whose top is "wsp". When EOF - is seen on normal input (eg, when "current_input" is empty), input is - switched over to "wrapup_stack", and the original "current_input" is - freed. A new stack is allocated for "wrapup_stack", which will - accept any text produced by calls to "m4wrap" from within the - wrapped text. This process of shuffling "wrapup_stack" to - "current_input" can continue indefinitely, even generating infinite - loops (e.g. "define(`f',`m4wrap(`f')')f"), without memory leaks. - - Pushing new input on the input stack is done by push_file (), - push_string (), push_wrapup () (for wrapup text), and push_macro () - (for macro definitions). Because macro expansion needs direct access - to the current input obstack (for optimisation), push_string () are - split in two functions, push_string_init (), which returns a pointer - to the current input stack, and push_string_finish (), which return a - pointer to the final text. The input_block *next is used to manage - the coordination between the different push routines. - - The current file and line number are stored in two global - variables, for use by the error handling functions in m4.c. Macro - expansion wants to report the line where a macro name was detected, - rather than where it finished collecting arguments. This also - applies to text resulting from macro expansions. So each input - block maintains its own notion of the current file and line, and - swapping between input blocks updates the global variables - accordingly. */ - -#ifdef ENABLE_CHANGEWORD -#include <contrib/tools/bison/gnulib/src/regex.h> -#endif - -enum input_type -{ - INPUT_STRING, /* String resulting from macro expansion. */ - INPUT_FILE, /* File from command line or include. */ - INPUT_MACRO /* Builtin resulting from defn. */ -}; - -typedef enum input_type input_type; - -struct input_block -{ - struct input_block *prev; /* previous input_block on the input stack */ - input_type type; /* see enum values */ - const char *file; /* file where this input is from */ - int line; /* line where this input is from */ - union - { - struct - { - char *string; /* remaining string value */ - char *end; /* terminating NUL of string */ - } - u_s; /* INPUT_STRING */ - struct - { - FILE *fp; /* input file handle */ - bool_bitfield end : 1; /* true if peek has seen EOF */ - bool_bitfield close : 1; /* true if we should close file on pop */ - bool_bitfield advance : 1; /* track previous start_of_input_line */ - } - u_f; /* INPUT_FILE */ - builtin_func *func; /* pointer to macro's function */ - } - u; -}; - -typedef struct input_block input_block; - - -/* Current input file name. */ -const char *current_file; - -/* Current input line number. */ -int current_line; - -/* Obstack for storing individual tokens. */ -static struct obstack token_stack; - -/* Obstack for storing file names. */ -static struct obstack file_names; - -/* Wrapup input stack. */ -static struct obstack *wrapup_stack; - -/* Current stack, from input or wrapup. */ -static struct obstack *current_input; - -/* Bottom of token_stack, for obstack_free. */ -static void *token_bottom; - -/* Pointer to top of current_input. */ -static input_block *isp; - -/* Pointer to top of wrapup_stack. */ -static input_block *wsp; - -/* Aux. for handling split push_string (). */ -static input_block *next; - -/* Flag for next_char () to increment current_line. */ -static bool start_of_input_line; - -/* Flag for next_char () to recognize change in input block. */ -static bool input_change; - -#define CHAR_EOF 256 /* character return on EOF */ -#define CHAR_MACRO 257 /* character return for MACRO token */ - -/* Quote chars. */ -STRING rquote; -STRING lquote; - -/* Comment chars. */ -STRING bcomm; -STRING ecomm; - -#ifdef ENABLE_CHANGEWORD - -# define DEFAULT_WORD_REGEXP "[_a-zA-Z][_a-zA-Z0-9]*" - -static struct re_pattern_buffer word_regexp; -static int default_word_regexp; -static struct re_registers regs; - -#else /* ! ENABLE_CHANGEWORD */ -# define default_word_regexp 1 -#endif /* ! ENABLE_CHANGEWORD */ - -#ifdef DEBUG_INPUT -static const char *token_type_string (token_type); -#endif - - -/*-------------------------------------------------------------------. -| push_file () pushes an input file on the input stack, saving the | -| current file name and line number. If next is non-NULL, this push | -| invalidates a call to push_string_init (), whose storage is | -| consequently released. If CLOSE_WHEN_DONE, then close FP after | -| EOF is detected. | -`-------------------------------------------------------------------*/ - -void -push_file (FILE *fp, const char *title, bool close_when_done) -{ - input_block *i; - - if (next != NULL) - { - obstack_free (current_input, next); - next = NULL; - } - - if (debug_level & DEBUG_TRACE_INPUT) - DEBUG_MESSAGE1 ("input read from %s", title); - - i = (input_block *) obstack_alloc (current_input, - sizeof (struct input_block)); - i->type = INPUT_FILE; - i->file = (char *) obstack_copy0 (&file_names, title, strlen (title)); - i->line = 1; - input_change = true; - - i->u.u_f.fp = fp; - i->u.u_f.end = false; - i->u.u_f.close = close_when_done; - i->u.u_f.advance = start_of_input_line; - output_current_line = -1; - - i->prev = isp; - isp = i; -} - -/*---------------------------------------------------------------. -| push_macro () pushes a builtin macro's definition on the input | -| stack. If next is non-NULL, this push invalidates a call to | -| push_string_init (), whose storage is consequently released. | -`---------------------------------------------------------------*/ - -void -push_macro (builtin_func *func) -{ - input_block *i; - - if (next != NULL) - { - obstack_free (current_input, next); - next = NULL; - } - - i = (input_block *) obstack_alloc (current_input, - sizeof (struct input_block)); - i->type = INPUT_MACRO; - i->file = current_file; - i->line = current_line; - input_change = true; - - i->u.func = func; - i->prev = isp; - isp = i; -} - -/*------------------------------------------------------------------. -| First half of push_string (). The pointer next points to the new | -| input_block. | -`------------------------------------------------------------------*/ - -struct obstack * -push_string_init (void) -{ - if (next != NULL) - { - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: recursive push_string!")); - abort (); - } - - next = (input_block *) obstack_alloc (current_input, - sizeof (struct input_block)); - next->type = INPUT_STRING; - next->file = current_file; - next->line = current_line; - - return current_input; -} - -/*-------------------------------------------------------------------. -| Last half of push_string (). If next is now NULL, a call to | -| push_file () has invalidated the previous call to push_string_init | -| (), so we just give up. If the new object is void, we do not push | -| it. The function push_string_finish () returns a pointer to the | -| finished object. This pointer is only for temporary use, since | -| reading the next token might release the memory used for the | -| object. | -`-------------------------------------------------------------------*/ - -const char * -push_string_finish (void) -{ - const char *ret = NULL; - - if (next == NULL) - return NULL; - - if (obstack_object_size (current_input) > 0) - { - size_t len = obstack_object_size (current_input); - obstack_1grow (current_input, '\0'); - next->u.u_s.string = (char *) obstack_finish (current_input); - next->u.u_s.end = next->u.u_s.string + len; - next->prev = isp; - isp = next; - ret = isp->u.u_s.string; /* for immediate use only */ - input_change = true; - } - else - obstack_free (current_input, next); /* people might leave garbage on it. */ - next = NULL; - return ret; -} - -/*------------------------------------------------------------------. -| The function push_wrapup () pushes a string on the wrapup stack. | -| When the normal input stack gets empty, the wrapup stack will | -| become the input stack, and push_string () and push_file () will | -| operate on wrapup_stack. Push_wrapup should be done as | -| push_string (), but this will suffice, as long as arguments to | -| m4_m4wrap () are moderate in size. | -`------------------------------------------------------------------*/ - -void -push_wrapup (const char *s) -{ - size_t len = strlen (s); - input_block *i; - i = (input_block *) obstack_alloc (wrapup_stack, - sizeof (struct input_block)); - i->prev = wsp; - i->type = INPUT_STRING; - i->file = current_file; - i->line = current_line; - i->u.u_s.string = (char *) obstack_copy0 (wrapup_stack, s, len); - i->u.u_s.end = i->u.u_s.string + len; - wsp = i; -} - - -/*-------------------------------------------------------------------. -| The function pop_input () pops one level of input sources. If the | -| popped input_block is a file, current_file and current_line are | -| reset to the saved values before the memory for the input_block is | -| released. | -`-------------------------------------------------------------------*/ - -static void -pop_input (void) -{ - input_block *tmp = isp->prev; - - switch (isp->type) - { - case INPUT_STRING: - case INPUT_MACRO: - break; - - case INPUT_FILE: - if (debug_level & DEBUG_TRACE_INPUT) - { - if (tmp) - DEBUG_MESSAGE2 ("input reverted to %s, line %d", - tmp->file, tmp->line); - else - DEBUG_MESSAGE ("input exhausted"); - } - - if (ferror (isp->u.u_f.fp)) - { - M4ERROR ((warning_status, 0, "read error")); - if (isp->u.u_f.close) - fclose (isp->u.u_f.fp); - retcode = EXIT_FAILURE; - } - else if (isp->u.u_f.close && fclose (isp->u.u_f.fp) == EOF) - { - M4ERROR ((warning_status, errno, "error reading file")); - retcode = EXIT_FAILURE; - } - start_of_input_line = isp->u.u_f.advance; - output_current_line = -1; - break; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: input stack botch in pop_input ()")); - abort (); - } - obstack_free (current_input, isp); - next = NULL; /* might be set in push_string_init () */ - - isp = tmp; - input_change = true; -} - -/*-------------------------------------------------------------------. -| To switch input over to the wrapup stack, main calls pop_wrapup | -| (). Since wrapup text can install new wrapup text, pop_wrapup () | -| returns false when there is no wrapup text on the stack, and true | -| otherwise. | -`-------------------------------------------------------------------*/ - -bool -pop_wrapup (void) -{ - next = NULL; - obstack_free (current_input, NULL); - free (current_input); - - if (wsp == NULL) - { - /* End of the program. Free all memory even though we are about - to exit, since it makes leak detection easier. */ - obstack_free (&token_stack, NULL); - obstack_free (&file_names, NULL); - obstack_free (wrapup_stack, NULL); - free (wrapup_stack); -#ifdef ENABLE_CHANGEWORD - regfree (&word_regexp); -#endif /* ENABLE_CHANGEWORD */ - return false; - } - - current_input = wrapup_stack; - wrapup_stack = (struct obstack *) xmalloc (sizeof (struct obstack)); - obstack_init (wrapup_stack); - - isp = wsp; - wsp = NULL; - input_change = true; - - return true; -} - -/*-------------------------------------------------------------------. -| When a MACRO token is seen, next_token () uses init_macro_token () | -| to retrieve the value of the function pointer. | -`-------------------------------------------------------------------*/ - -static void -init_macro_token (token_data *td) -{ - if (isp->type != INPUT_MACRO) - { - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad call to init_macro_token ()")); - abort (); - } - - TOKEN_DATA_TYPE (td) = TOKEN_FUNC; - TOKEN_DATA_FUNC (td) = isp->u.func; -} - - -/*-----------------------------------------------------------------. -| Low level input is done a character at a time. The function | -| peek_input () is used to look at the next character in the input | -| stream. At any given time, it reads from the input_block on the | -| top of the current input stack. | -`-----------------------------------------------------------------*/ - -static int -peek_input (void) -{ - int ch; - input_block *block = isp; - - while (1) - { - if (block == NULL) - return CHAR_EOF; - - switch (block->type) - { - case INPUT_STRING: - ch = to_uchar (block->u.u_s.string[0]); - if (ch != '\0') - return ch; - break; - - case INPUT_FILE: - ch = getc (block->u.u_f.fp); - if (ch != EOF) - { - ungetc (ch, block->u.u_f.fp); - return ch; - } - block->u.u_f.end = true; - break; - - case INPUT_MACRO: - return CHAR_MACRO; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: input stack botch in peek_input ()")); - abort (); - } - block = block->prev; - } -} - -/*-------------------------------------------------------------------. -| The function next_char () is used to read and advance the input to | -| the next character. It also manages line numbers for error | -| messages, so they do not get wrong, due to lookahead. The token | -| consisting of a newline alone is taken as belonging to the line it | -| ends, and the current line number is not incremented until the | -| next character is read. 99.9% of all calls will read from a | -| string, so factor that out into a macro for speed. | -`-------------------------------------------------------------------*/ - -#define next_char() \ - (isp && isp->type == INPUT_STRING && isp->u.u_s.string[0] \ - && !input_change \ - ? to_uchar (*isp->u.u_s.string++) \ - : next_char_1 ()) - -static int -next_char_1 (void) -{ - int ch; - - while (1) - { - if (isp == NULL) - { - current_file = ""; - current_line = 0; - return CHAR_EOF; - } - - if (input_change) - { - current_file = isp->file; - current_line = isp->line; - input_change = false; - } - - switch (isp->type) - { - case INPUT_STRING: - ch = to_uchar (*isp->u.u_s.string++); - if (ch != '\0') - return ch; - break; - - case INPUT_FILE: - if (start_of_input_line) - { - start_of_input_line = false; - current_line = ++isp->line; - } - - /* If stdin is a terminal, calling getc after peek_input - already called it would make the user have to hit ^D - twice to quit. */ - ch = isp->u.u_f.end ? EOF : getc (isp->u.u_f.fp); - if (ch != EOF) - { - if (ch == '\n') - start_of_input_line = true; - return ch; - } - break; - - case INPUT_MACRO: - pop_input (); /* INPUT_MACRO input sources has only one token */ - return CHAR_MACRO; - - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: input stack botch in next_char ()")); - abort (); - } - - /* End of input source --- pop one level. */ - pop_input (); - } -} - -/*-------------------------------------------------------------------. -| skip_line () simply discards all immediately following characters, | -| upto the first newline. It is only used from m4_dnl (). | -`-------------------------------------------------------------------*/ - -void -skip_line (void) -{ - int ch; - const char *file = current_file; - int line = current_line; - - while ((ch = next_char ()) != CHAR_EOF && ch != '\n') - ; - if (ch == CHAR_EOF) - /* current_file changed to "" if we see CHAR_EOF, use the - previous value we stored earlier. */ - M4ERROR_AT_LINE ((warning_status, 0, file, line, - "Warning: end of file treated as newline")); - /* On the rare occasion that dnl crosses include file boundaries - (either the input file did not end in a newline, or changeword - was used), calling next_char can update current_file and - current_line, and that update will be undone as we return to - expand_macro. This informs next_char to fix things again. */ - if (file != current_file || line != current_line) - input_change = true; -} - - -/*------------------------------------------------------------------. -| This function is for matching a string against a prefix of the | -| input stream. If the string matches the input and consume is | -| true, the input is discarded; otherwise any characters read are | -| pushed back again. The function is used only when multicharacter | -| quotes or comment delimiters are used. | -`------------------------------------------------------------------*/ - -static bool -match_input (const char *s, bool consume) -{ - int n; /* number of characters matched */ - int ch; /* input character */ - const char *t; - bool result = false; - - ch = peek_input (); - if (ch != to_uchar (*s)) - return false; /* fail */ - - if (s[1] == '\0') - { - if (consume) - next_char (); - return true; /* short match */ - } - - next_char (); - for (n = 1, t = s++; peek_input () == to_uchar (*s++); ) - { - next_char (); - n++; - if (*s == '\0') /* long match */ - { - if (consume) - return true; - result = true; - break; - } - } - - /* Failed or shouldn't consume, push back input. */ - { - struct obstack *h = push_string_init (); - - /* `obstack_grow' may be macro evaluating its arg 1 several times. */ - obstack_grow (h, t, n); - } - push_string_finish (); - return result; -} - -/*--------------------------------------------------------------------. -| The macro MATCH() is used to match a string S against the input. | -| The first character is handled inline, for speed. Hopefully, this | -| will not hurt efficiency too much when single character quotes and | -| comment delimiters are used. If CONSUME, then CH is the result of | -| next_char, and a successful match will discard the matched string. | -| Otherwise, CH is the result of peek_char, and the input stream is | -| effectively unchanged. | -`--------------------------------------------------------------------*/ - -#define MATCH(ch, s, consume) \ - (to_uchar ((s)[0]) == (ch) \ - && (ch) != '\0' \ - && ((s)[1] == '\0' || (match_input ((s) + (consume), consume)))) - - -/*--------------------------------------------------------. -| Initialize input stacks, and quote/comment characters. | -`--------------------------------------------------------*/ - -void -input_init (void) -{ - current_file = ""; - current_line = 0; - - current_input = (struct obstack *) xmalloc (sizeof (struct obstack)); - obstack_init (current_input); - wrapup_stack = (struct obstack *) xmalloc (sizeof (struct obstack)); - obstack_init (wrapup_stack); - - obstack_init (&file_names); - - /* Allocate an object in the current chunk, so that obstack_free - will always work even if the first token parsed spills to a new - chunk. */ - obstack_init (&token_stack); - obstack_alloc (&token_stack, 1); - token_bottom = obstack_base (&token_stack); - - isp = NULL; - wsp = NULL; - next = NULL; - - start_of_input_line = false; - - lquote.string = xstrdup (DEF_LQUOTE); - lquote.length = strlen (lquote.string); - rquote.string = xstrdup (DEF_RQUOTE); - rquote.length = strlen (rquote.string); - bcomm.string = xstrdup (DEF_BCOMM); - bcomm.length = strlen (bcomm.string); - ecomm.string = xstrdup (DEF_ECOMM); - ecomm.length = strlen (ecomm.string); - -#ifdef ENABLE_CHANGEWORD - set_word_regexp (user_word_regexp); -#endif -} - - -/*------------------------------------------------------------------. -| Functions for setting quotes and comment delimiters. Used by | -| m4_changecom () and m4_changequote (). Pass NULL if the argument | -| was not present, to distinguish from an explicit empty string. | -`------------------------------------------------------------------*/ - -void -set_quotes (const char *lq, const char *rq) -{ - free (lquote.string); - free (rquote.string); - - /* POSIX states that with 0 arguments, the default quotes are used. - POSIX XCU ERN 112 states that behavior is implementation-defined - if there was only one argument, or if there is an empty string in - either position when there are two arguments. We allow an empty - left quote to disable quoting, but a non-empty left quote will - always create a non-empty right quote. See the texinfo for what - some other implementations do. */ - if (!lq) - { - lq = DEF_LQUOTE; - rq = DEF_RQUOTE; - } - else if (!rq || (*lq && !*rq)) - rq = DEF_RQUOTE; - - lquote.string = xstrdup (lq); - lquote.length = strlen (lquote.string); - rquote.string = xstrdup (rq); - rquote.length = strlen (rquote.string); -} - -void -set_comment (const char *bc, const char *ec) -{ - free (bcomm.string); - free (ecomm.string); - - /* POSIX requires no arguments to disable comments. It requires - empty arguments to be used as-is, but this is counter to - traditional behavior, because a non-null begin and null end makes - it impossible to end a comment. An aardvark has been filed: - http://www.opengroup.org/austin/mailarchives/ag-review/msg02168.html - This implementation assumes the aardvark will be approved. See - the texinfo for what some other implementations do. */ - if (!bc) - bc = ec = ""; - else if (!ec || (*bc && !*ec)) - ec = DEF_ECOMM; - - bcomm.string = xstrdup (bc); - bcomm.length = strlen (bcomm.string); - ecomm.string = xstrdup (ec); - ecomm.length = strlen (ecomm.string); -} - -#ifdef ENABLE_CHANGEWORD - -void -set_word_regexp (const char *regexp) -{ - const char *msg; - struct re_pattern_buffer new_word_regexp; - - if (!*regexp || STREQ (regexp, DEFAULT_WORD_REGEXP)) - { - default_word_regexp = true; - return; - } - - /* Dry run to see whether the new expression is compilable. */ - init_pattern_buffer (&new_word_regexp, NULL); - msg = re_compile_pattern (regexp, strlen (regexp), &new_word_regexp); - regfree (&new_word_regexp); - - if (msg != NULL) - { - M4ERROR ((warning_status, 0, - "bad regular expression `%s': %s", regexp, msg)); - return; - } - - /* If compilation worked, retry using the word_regexp struct. We - can't rely on struct assigns working, so redo the compilation. - The fastmap can be reused between compilations, and will be freed - by the final regfree. */ - if (!word_regexp.fastmap) - word_regexp.fastmap = xcharalloc (UCHAR_MAX + 1); - msg = re_compile_pattern (regexp, strlen (regexp), &word_regexp); - assert (!msg); - re_set_registers (&word_regexp, ®s, regs.num_regs, regs.start, regs.end); - if (re_compile_fastmap (&word_regexp)) - assert (false); - - default_word_regexp = false; -} - -#endif /* ENABLE_CHANGEWORD */ - - -/*--------------------------------------------------------------------. -| Parse and return a single token from the input stream. A token | -| can either be TOKEN_EOF, if the input_stack is empty; it can be | -| TOKEN_STRING for a quoted string; TOKEN_WORD for something that is | -| a potential macro name; and TOKEN_SIMPLE for any single character | -| that is not a part of any of the previous types. If LINE is not | -| NULL, set *LINE to the line where the token starts. | -| | -| Next_token () return the token type, and passes back a pointer to | -| the token data through TD. The token text is collected on the | -| obstack token_stack, which never contains more than one token text | -| at a time. The storage pointed to by the fields in TD is | -| therefore subject to change the next time next_token () is called. | -`--------------------------------------------------------------------*/ - -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; -} - -/*-----------------------------------------------. -| Peek at the next token from the input stream. | -`-----------------------------------------------*/ - -token_type -peek_token (void) -{ - token_type result; - int ch = peek_input (); - - if (ch == CHAR_EOF) - { - result = TOKEN_EOF; - } - else if (ch == CHAR_MACRO) - { - result = TOKEN_MACDEF; - } - else if (MATCH (ch, bcomm.string, false)) - { - result = TOKEN_STRING; - } - else if ((default_word_regexp && (isalpha (ch) || ch == '_')) -#ifdef ENABLE_CHANGEWORD - || (! default_word_regexp && word_regexp.fastmap[ch]) -#endif /* ENABLE_CHANGEWORD */ - ) - { - result = TOKEN_WORD; - } - else if (MATCH (ch, lquote.string, false)) - { - result = TOKEN_STRING; - } - else - switch (ch) - { - case '(': - result = TOKEN_OPEN; - break; - case ',': - result = TOKEN_COMMA; - break; - case ')': - result = TOKEN_CLOSE; - break; - default: - result = TOKEN_SIMPLE; - } - -#ifdef DEBUG_INPUT - xfprintf (stderr, "peek_token -> %s\n", token_type_string (result)); -#endif /* DEBUG_INPUT */ - return result; -} - - -#ifdef DEBUG_INPUT - -static const char * -token_type_string (token_type t) -{ - switch (t) - { /* TOKSW */ - case TOKEN_EOF: - return "EOF"; - case TOKEN_STRING: - return "STRING"; - case TOKEN_WORD: - return "WORD"; - case TOKEN_OPEN: - return "OPEN"; - case TOKEN_COMMA: - return "COMMA"; - case TOKEN_CLOSE: - return "CLOSE"; - case TOKEN_SIMPLE: - return "SIMPLE"; - case TOKEN_MACDEF: - return "MACDEF"; - default: - abort (); - } - } - -static void -print_token (const char *s, token_type t, token_data *td) -{ - xfprintf (stderr, "%s: ", s); - switch (t) - { /* TOKSW */ - case TOKEN_OPEN: - case TOKEN_COMMA: - case TOKEN_CLOSE: - case TOKEN_SIMPLE: - xfprintf (stderr, "char:"); - break; - - case TOKEN_WORD: - xfprintf (stderr, "word:"); - break; - - case TOKEN_STRING: - xfprintf (stderr, "string:"); - break; - - case TOKEN_MACDEF: - xfprintf (stderr, "macro: %p\n", TOKEN_DATA_FUNC (td)); - break; - - case TOKEN_EOF: - xfprintf (stderr, "eof\n"); - break; - } - xfprintf (stderr, "\t\"%s\"\n", TOKEN_DATA_TEXT (td)); -} - -static void M4_GNUC_UNUSED -lex_debug (void) -{ - token_type t; - token_data td; - - while ((t = next_token (&td, NULL)) != TOKEN_EOF) - print_token ("lex", t, &td); -} -#endif /* DEBUG_INPUT */ diff --git a/contrib/tools/bison/m4/src/m4.c b/contrib/tools/bison/m4/src/m4.c deleted file mode 100644 index 2c03154471..0000000000 --- a/contrib/tools/bison/m4/src/m4.c +++ /dev/null @@ -1,695 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2004-2013 Free Software Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "m4.h" - -#include <getopt.h> -#include <limits.h> -#include <signal.h> - -#include "c-stack.h" -#include "ignore-value.h" -#include "progname.h" -#include "version-etc.h" - -#ifdef DEBUG_STKOVF -# include "assert.h" -#endif - -#define AUTHORS "Rene' Seindal" - -static void usage (int) M4_GNUC_NORETURN; - -/* Enable sync output for /lib/cpp (-s). */ -int sync_output = 0; - -/* Debug (-d[flags]). */ -int debug_level = 0; - -/* Hash table size (should be a prime) (-Hsize). */ -size_t hash_table_size = HASHMAX; - -/* Disable GNU extensions (-G). */ -int no_gnu_extensions = 0; - -/* Prefix all builtin functions by `m4_'. */ -int prefix_all_builtins = 0; - -/* Max length of arguments in trace output (-lsize). */ -int max_debug_argument_length = 0; - -/* Suppress warnings about missing arguments. */ -int suppress_warnings = 0; - -/* If true, then warnings affect exit status. */ -static bool fatal_warnings = false; - -/* If not zero, then value of exit status for warning diagnostics. */ -int warning_status = 0; - -/* Artificial limit for expansion_level in macro.c. */ -int nesting_limit = 1024; - -#ifdef ENABLE_CHANGEWORD -/* User provided regexp for describing m4 words. */ -const char *user_word_regexp = ""; -#endif - -/* Global catchall for any errors that should affect final error status, but - where we try to continue execution in the meantime. */ -int retcode; - -struct macro_definition -{ - struct macro_definition *next; - int code; /* D, U, s, t, '\1', or DEBUGFILE_OPTION. */ - const char *arg; -}; -typedef struct macro_definition macro_definition; - -/* Error handling functions. */ - -/*-----------------------. -| Wrapper around error. | -`-----------------------*/ - -void -m4_error (int status, int errnum, const char *format, ...) -{ - va_list args; - va_start (args, format); - verror_at_line (status, errnum, current_line ? current_file : NULL, - current_line, format, args); - if (fatal_warnings && ! retcode) - retcode = EXIT_FAILURE; - va_end (args); -} - -/*-------------------------------. -| Wrapper around error_at_line. | -`-------------------------------*/ - -void -m4_error_at_line (int status, int errnum, const char *file, int line, - const char *format, ...) -{ - va_list args; - va_start (args, format); - verror_at_line (status, errnum, line ? file : NULL, line, format, args); - if (fatal_warnings && ! retcode) - retcode = EXIT_FAILURE; - va_end (args); -} - -#ifndef SIGBUS -# define SIGBUS SIGILL -#endif - -#ifndef NSIG -# ifndef MAX -# define MAX(a,b) ((a) < (b) ? (b) : (a)) -# endif -# define NSIG (MAX (SIGABRT, MAX (SIGILL, MAX (SIGFPE, \ - MAX (SIGSEGV, SIGBUS)))) + 1) -#endif - -/* Pre-translated messages for program errors. Do not translate in - the signal handler, since gettext and strsignal are not - async-signal-safe. */ -static const char * volatile program_error_message; -static const char * volatile signal_message[NSIG]; - -/* Print a nicer message about any programmer errors, then exit. This - must be aysnc-signal safe, since it is executed as a signal - handler. If SIGNO is zero, this represents a stack overflow; in - that case, we return to allow c_stack_action to handle things. */ -static void M4_GNUC_PURE -fault_handler (int signo) -{ - if (signo) - { - /* POSIX states that reading static memory is, in general, not - async-safe. However, the static variables that we read are - never modified once this handler is installed, so this - particular usage is safe. And it seems an oversight that - POSIX claims strlen is not async-safe. Ignore write - failures, since we will exit with non-zero status anyway. */ -#define WRITE(f, b, l) ignore_value (write (f, b, l)) - WRITE (STDERR_FILENO, program_name, strlen (program_name)); - WRITE (STDERR_FILENO, ": ", 2); - WRITE (STDERR_FILENO, program_error_message, - strlen (program_error_message)); - if (signal_message[signo]) - { - WRITE (STDERR_FILENO, ": ", 2); - WRITE (STDERR_FILENO, signal_message[signo], - strlen (signal_message[signo])); - } - WRITE (STDERR_FILENO, "\n", 1); -#undef WRITE - _exit (EXIT_INTERNAL_ERROR); - } -} - - -/*---------------------------------------------. -| Print a usage message and exit with STATUS. | -`---------------------------------------------*/ - -static void -usage (int status) -{ - if (status != EXIT_SUCCESS) - xfprintf (stderr, "Try `%s --help' for more information.\n", program_name); - else - { - xprintf ("Usage: %s [OPTION]... [FILE]...\n", program_name); - fputs ("\ -Process macros in FILEs. If no FILE or if FILE is `-', standard input\n\ -is read.\n\ -", stdout); - fputs ("\ -\n\ -Mandatory or optional arguments to long options are mandatory or optional\n\ -for short options too.\n\ -\n\ -Operation modes:\n\ - --help display this help and exit\n\ - --version output version information and exit\n\ -", stdout); - xprintf ("\ - -E, --fatal-warnings once: warnings become errors, twice: stop\n\ - execution at first error\n\ - -i, --interactive unbuffer output, ignore interrupts\n\ - -P, --prefix-builtins force a `m4_' prefix to all builtins\n\ - -Q, --quiet, --silent suppress some warnings for builtins\n\ - --warn-macro-sequence[=REGEXP]\n\ - warn if macro definition matches REGEXP,\n\ - default %s\n\ -", DEFAULT_MACRO_SEQUENCE); -#ifdef ENABLE_CHANGEWORD - fputs ("\ - -W, --word-regexp=REGEXP use REGEXP for macro name syntax\n\ -", stdout); -#endif - fputs ("\ -\n\ -Preprocessor features:\n\ - -D, --define=NAME[=VALUE] define NAME as having VALUE, or empty\n\ - -I, --include=DIRECTORY append DIRECTORY to include path\n\ - -s, --synclines generate `#line NUM \"FILE\"' lines\n\ - -U, --undefine=NAME undefine NAME\n\ -", stdout); - puts (""); - xprintf (_("\ -Limits control:\n\ - -g, --gnu override -G to re-enable GNU extensions\n\ - -G, --traditional suppress all GNU extensions\n\ - -H, --hashsize=PRIME set symbol lookup hash table size [509]\n\ - -L, --nesting-limit=NUMBER change nesting limit, 0 for unlimited [%d]\n\ -"), nesting_limit); - puts (""); - fputs ("\ -Frozen state files:\n\ - -F, --freeze-state=FILE produce a frozen state on FILE at end\n\ - -R, --reload-state=FILE reload a frozen state from FILE at start\n\ -", stdout); - fputs ("\ -\n\ -Debugging:\n\ - -d, --debug[=FLAGS] set debug level (no FLAGS implies `aeq')\n\ - --debugfile[=FILE] redirect debug and trace output to FILE\n\ - (default stderr, discard if empty string)\n\ - -l, --arglength=NUM restrict macro tracing size\n\ - -t, --trace=NAME trace NAME when it is defined\n\ -", stdout); - fputs ("\ -\n\ -FLAGS is any of:\n\ - a show actual arguments\n\ - c show before collect, after collect and after call\n\ - e show expansion\n\ - f say current input file name\n\ - i show changes in input files\n\ - l say current input line number\n\ - p show results of path searches\n\ - q quote values as necessary, with a or e flag\n\ - t trace for all macro calls, not only traceon'ed\n\ - x add a unique macro call id, useful with c flag\n\ - V shorthand for all of the above flags\n\ -", stdout); - fputs ("\ -\n\ -If defined, the environment variable `M4PATH' is a colon-separated list\n\ -of directories included after any specified by `-I'.\n\ -", stdout); - fputs ("\ -\n\ -Exit status is 0 for success, 1 for failure, 63 for frozen file version\n\ -mismatch, or whatever value was passed to the m4exit macro.\n\ -", stdout); - emit_bug_reporting_address (); - } - exit (status); -} - -/*--------------------------------------. -| Decode options and launch execution. | -`--------------------------------------*/ - -/* For long options that have no equivalent short option, use a - non-character as a pseudo short option, starting with CHAR_MAX + 1. */ -enum -{ - DEBUGFILE_OPTION = CHAR_MAX + 1, /* no short opt */ - DIVERSIONS_OPTION, /* not quite -N, because of message */ - WARN_MACRO_SEQUENCE_OPTION, /* no short opt */ - - HELP_OPTION, /* no short opt */ - VERSION_OPTION /* no short opt */ -}; - -static const struct option long_options[] = -{ - {"arglength", required_argument, NULL, 'l'}, - {"debug", optional_argument, NULL, 'd'}, - {"define", required_argument, NULL, 'D'}, - {"error-output", required_argument, NULL, 'o'}, /* FIXME: deprecate in 2.0 */ - {"fatal-warnings", no_argument, NULL, 'E'}, - {"freeze-state", required_argument, NULL, 'F'}, - {"gnu", no_argument, NULL, 'g'}, - {"hashsize", required_argument, NULL, 'H'}, - {"include", required_argument, NULL, 'I'}, - {"interactive", no_argument, NULL, 'i'}, - {"nesting-limit", required_argument, NULL, 'L'}, - {"prefix-builtins", no_argument, NULL, 'P'}, - {"quiet", no_argument, NULL, 'Q'}, - {"reload-state", required_argument, NULL, 'R'}, - {"silent", no_argument, NULL, 'Q'}, - {"synclines", no_argument, NULL, 's'}, - {"trace", required_argument, NULL, 't'}, - {"traditional", no_argument, NULL, 'G'}, - {"undefine", required_argument, NULL, 'U'}, - {"word-regexp", required_argument, NULL, 'W'}, - - {"debugfile", optional_argument, NULL, DEBUGFILE_OPTION}, - {"diversions", required_argument, NULL, DIVERSIONS_OPTION}, - {"warn-macro-sequence", optional_argument, NULL, WARN_MACRO_SEQUENCE_OPTION}, - - {"help", no_argument, NULL, HELP_OPTION}, - {"version", no_argument, NULL, VERSION_OPTION}, - - { NULL, 0, NULL, 0 }, -}; - -/* Process a command line file NAME, and return true only if it was - stdin. */ -static void -process_file (const char *name) -{ - if (STREQ (name, "-")) - { - /* If stdin is a terminal, we want to allow 'm4 - file -' - to read input from stdin twice, like GNU cat. Besides, - there is no point closing stdin before wrapped text, to - minimize bugs in syscmd called from wrapped text. */ - push_file (stdin, "stdin", false); - } - else - { - char *full_name; - FILE *fp = m4_path_search (name, &full_name); - if (fp == NULL) - { - error (0, errno, _("cannot open `%s'"), name); - /* Set the status to EXIT_FAILURE, even though we - continue to process files after a missing file. */ - retcode = EXIT_FAILURE; - return; - } - push_file (fp, full_name, true); - free (full_name); - } - expand_input (); -} - -/* POSIX requires only -D, -U, and -s; and says that the first two - must be recognized when interspersed with file names. Traditional - behavior also handles -s between files. Starting OPTSTRING with - '-' forces getopt_long to hand back file names as arguments to opt - '\1', rather than reordering the command line. */ -#ifdef ENABLE_CHANGEWORD -#define OPTSTRING "-B:D:EF:GH:I:L:N:PQR:S:T:U:W:d::egil:o:st:" -#else -#define OPTSTRING "-B:D:EF:GH:I:L:N:PQR:S:T:U:d::egil:o:st:" -#endif - -int -main (int argc, char *const *argv) -{ -#if !defined(_WIN32) && !defined(_WIN64) - struct sigaction act; -#endif - macro_definition *head; /* head of deferred argument list */ - macro_definition *tail; - macro_definition *defn; - int optchar; /* option character */ - - macro_definition *defines; - bool interactive = false; - bool seen_file = false; - const char *debugfile = NULL; - const char *frozen_file_to_read = NULL; - const char *frozen_file_to_write = NULL; - const char *macro_sequence = ""; - - set_program_name (argv[0]); - retcode = EXIT_SUCCESS; - atexit (close_stdin); - - include_init (); - debug_init (); - - /* Stack overflow and program error handling. Ignore failure to - install a handler, since this is merely for improved output on - crash, and we should never crash ;). We install SIGBUS and - SIGSEGV handlers prior to using the c-stack module; depending on - the platform, c-stack will then override none, SIGSEGV, or both - handlers. */ - program_error_message - = xasprintf (_("internal error detected; please report this bug to <%s>"), - PACKAGE_BUGREPORT); - signal_message[SIGSEGV] = xstrdup (strsignal (SIGSEGV)); - signal_message[SIGABRT] = xstrdup (strsignal (SIGABRT)); - signal_message[SIGILL] = xstrdup (strsignal (SIGILL)); - signal_message[SIGFPE] = xstrdup (strsignal (SIGFPE)); - if (SIGBUS != SIGILL && SIGBUS != SIGSEGV) - signal_message[SIGBUS] = xstrdup (strsignal (SIGBUS)); -#if !defined(_WIN32) && !defined(_WIN64) - // No such signals on Windows - sigemptyset(&act.sa_mask); - /* One-shot - if we fault while handling a fault, we want to revert - to default signal behavior. */ - act.sa_flags = SA_NODEFER | SA_RESETHAND; - act.sa_handler = fault_handler; - sigaction (SIGSEGV, &act, NULL); - sigaction (SIGABRT, &act, NULL); - sigaction (SIGILL, &act, NULL); - sigaction (SIGFPE, &act, NULL); - sigaction (SIGBUS, &act, NULL); -#endif - if (c_stack_action (fault_handler) == 0) - nesting_limit = 0; - -#ifdef DEBUG_STKOVF - /* Make it easier to test our fault handlers. Exporting M4_CRASH=0 - attempts a SIGSEGV, exporting it as 1 attempts an assertion - failure with a fallback to abort. */ - { - char *crash = getenv ("M4_CRASH"); - if (crash) - { - if (!strtol (crash, NULL, 10)) - ++*(int *) 8; - assert (false); - abort (); - } - } -#endif /* DEBUG_STKOVF */ - - /* First, we decode the arguments, to size up tables and stuff. */ - head = tail = NULL; - - while ((optchar = getopt_long (argc, (char **) argv, OPTSTRING, - long_options, NULL)) != -1) - switch (optchar) - { - default: - usage (EXIT_FAILURE); - - case 'B': - case 'S': - case 'T': - /* Compatibility junk: options that other implementations - support, but which we ignore as no-ops and don't list in - --help. */ - error (0, 0, _("warning: `m4 -%c' may be removed in a future release"), - optchar); - break; - - case 'N': - case DIVERSIONS_OPTION: - /* -N became an obsolete no-op in 1.4.x. */ - error (0, 0, _("warning: `m4 %s' is deprecated"), - optchar == 'N' ? "-N" : "--diversions"); - break; - - case 'D': - case 'U': - case 's': - case 't': - case '\1': - case DEBUGFILE_OPTION: - /* Arguments that cannot be handled until later are accumulated. */ - - defn = (macro_definition *) xmalloc (sizeof (macro_definition)); - defn->code = optchar; - defn->arg = optarg; - defn->next = NULL; - - if (head == NULL) - head = defn; - else - tail->next = defn; - tail = defn; - - break; - - case 'E': - if (! fatal_warnings) - fatal_warnings = true; - else - warning_status = EXIT_FAILURE; - break; - - case 'F': - frozen_file_to_write = optarg; - break; - - case 'G': - no_gnu_extensions = 1; - break; - - case 'H': - hash_table_size = strtol (optarg, NULL, 10); - if (hash_table_size == 0) - hash_table_size = HASHMAX; - break; - - case 'I': - add_include_directory (optarg); - break; - - case 'L': - nesting_limit = strtol (optarg, NULL, 10); - break; - - case 'P': - prefix_all_builtins = 1; - break; - - case 'Q': - suppress_warnings = 1; - break; - - case 'R': - frozen_file_to_read = optarg; - break; - -#ifdef ENABLE_CHANGEWORD - case 'W': - user_word_regexp = optarg; - break; -#endif - - case 'd': - debug_level = debug_decode (optarg); - if (debug_level < 0) - { - error (0, 0, _("bad debug flags: `%s'"), optarg); - debug_level = 0; - } - break; - - case 'e': - error (0, 0, _("warning: `m4 -e' is deprecated, use `-i' instead")); - /* fall through */ - case 'i': - interactive = true; - break; - - case 'g': - no_gnu_extensions = 0; - break; - - case 'l': - max_debug_argument_length = strtol (optarg, NULL, 10); - if (max_debug_argument_length <= 0) - max_debug_argument_length = 0; - break; - - case 'o': - /* -o/--error-output are deprecated synonyms of --debugfile, - but don't issue a deprecation warning until autoconf 2.61 - or later is more widely established, as such a warning - would interfere with all earlier versions of autoconf. */ - /* Don't call debug_set_output here, as it has side effects. */ - debugfile = optarg; - break; - - case WARN_MACRO_SEQUENCE_OPTION: - /* Don't call set_macro_sequence here, as it can exit. - --warn-macro-sequence sets optarg to NULL (which uses the - default regexp); --warn-macro-sequence= sets optarg to "" - (which disables these warnings). */ - macro_sequence = optarg; - break; - - case VERSION_OPTION: - version_etc (stdout, PACKAGE, PACKAGE_NAME, VERSION, AUTHORS, NULL); - exit (EXIT_SUCCESS); - break; - - case HELP_OPTION: - usage (EXIT_SUCCESS); - break; - } - - defines = head; - - /* Do the basic initializations. */ - if (debugfile && !debug_set_output (debugfile)) - M4ERROR ((warning_status, errno, "cannot set debug file `%s'", debugfile)); - - input_init (); - output_init (); - symtab_init (); - set_macro_sequence (macro_sequence); - include_env_init (); - - if (frozen_file_to_read) - reload_frozen_state (frozen_file_to_read); - else - builtin_init (); - - /* Interactive mode means unbuffered output, and interrupts ignored. */ - - if (interactive) - { - signal (SIGINT, SIG_IGN); - setbuf (stdout, (char *) NULL); - } - - /* Handle deferred command line macro definitions. Must come after - initialization of the symbol table. */ - - while (defines != NULL) - { - macro_definition *next; - symbol *sym; - - switch (defines->code) - { - case 'D': - { - /* defines->arg is read-only, so we need a copy. */ - char *macro_name = xstrdup (defines->arg); - char *macro_value = strchr (macro_name, '='); - if (macro_value) - *macro_value++ = '\0'; - define_user_macro (macro_name, macro_value, SYMBOL_INSERT); - free (macro_name); - } - break; - - case 'U': - lookup_symbol (defines->arg, SYMBOL_DELETE); - break; - - case 't': - sym = lookup_symbol (defines->arg, SYMBOL_INSERT); - SYMBOL_TRACED (sym) = true; - break; - - case 's': - sync_output = 1; - break; - - case '\1': - seen_file = true; - process_file (defines->arg); - break; - - case DEBUGFILE_OPTION: - if (!debug_set_output (defines->arg)) - M4ERROR ((warning_status, errno, "cannot set debug file `%s'", - debugfile ? debugfile : _("stderr"))); - break; - - default: - M4ERROR ((0, 0, "INTERNAL ERROR: bad code in deferred arguments")); - abort (); - } - - next = defines->next; - free (defines); - defines = next; - } - - /* Handle remaining input files. Each file is pushed on the input, - and the input read. Wrapup text is handled separately later. */ - - if (optind == argc && !seen_file) - process_file ("-"); - else - for (; optind < argc; optind++) - process_file (argv[optind]); - - /* Now handle wrapup text. */ - - while (pop_wrapup ()) - expand_input (); - - /* Change debug stream back to stderr, to force flushing the debug - stream and detect any errors it might have encountered. The - three standard streams are closed by close_stdin. */ - debug_set_output (NULL); - - if (frozen_file_to_write) - produce_frozen_state (frozen_file_to_write); - else - { - make_diversion (0); - undivert_all (); - } - output_exit (); - free_macro_sequence (); - exit (retcode); -} diff --git a/contrib/tools/bison/m4/src/m4.h b/contrib/tools/bison/m4/src/m4.h deleted file mode 100644 index eb2a96784f..0000000000 --- a/contrib/tools/bison/m4/src/m4.h +++ /dev/null @@ -1,491 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2004-2013 Free Software Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* We use <config.h> instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ - -#include <config.h> - -#include <assert.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdint.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include "binary-io.h" -#include "clean-temp.h" -#include "cloexec.h" -#include "close-stream.h" -#include "closein.h" -#include "dirname.h" -#include "error.h" -#include "exitfail.h" -#include "filenamecat.h" -#include "obstack.h" -#include "stdio--.h" -#include "stdlib--.h" -#include "unistd--.h" -#include "verror.h" -#include "xalloc.h" -#include "xprintf.h" -#include "xvasprintf.h" - -/* Canonicalize UNIX recognition macros. */ -#if defined unix || defined __unix || defined __unix__ \ - || defined _POSIX_VERSION || defined _POSIX2_VERSION \ - || defined __NetBSD__ || defined __OpenBSD__ \ - || defined __APPLE__ || defined __APPLE_CC__ -# define UNIX 1 -#endif - -/* Canonicalize Windows recognition macros. */ -#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ -# define W32_NATIVE 1 -#endif - -/* Canonicalize OS/2 recognition macro. */ -#ifdef __EMX__ -# define OS2 1 -# undef UNIX -#endif - -/* Used if any programmer error is detected (not possible, right?) */ -#define EXIT_INTERNAL_ERROR 2 - -/* Used for version mismatch, when -R detects a frozen file it can't parse. */ -#define EXIT_MISMATCH 63 - -/* No-op, for future gettext compatibility. */ -#define _(ARG) ARG - -/* Various declarations. */ - -struct string - { - char *string; /* characters of the string */ - size_t length; /* length of the string */ - }; -typedef struct string STRING; - -/* Memory allocation. */ -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - -/* Those must come first. */ -typedef struct token_data token_data; -typedef void builtin_func (struct obstack *, int, token_data **); - -/* Gnulib's stdbool doesn't work with bool bitfields. For nicer - debugging, use bool when we know it works, but use the more - portable unsigned int elsewhere. */ -#if __GNUC__ > 2 -typedef bool bool_bitfield; -#else -typedef unsigned int bool_bitfield; -#endif /* ! __GNUC__ */ - -/* Take advantage of GNU C compiler source level optimization hints, - using portable macros. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6) -# define M4_GNUC_ATTRIBUTE(args) __attribute__ (args) -#else -# define M4_GNUC_ATTRIBUTE(args) -#endif /* __GNUC__ */ - -#define M4_GNUC_UNUSED M4_GNUC_ATTRIBUTE ((__unused__)) -#define M4_GNUC_PRINTF(fmt, arg) \ - M4_GNUC_ATTRIBUTE ((__format__ (__printf__, fmt, arg))) -#define M4_GNUC_NORETURN M4_GNUC_ATTRIBUTE ((__noreturn__)) -#define M4_GNUC_PURE M4_GNUC_ATTRIBUTE ((__pure__)) - -/* File: m4.c --- global definitions. */ - -/* Option flags. */ -extern int sync_output; /* -s */ -extern int debug_level; /* -d */ -extern size_t hash_table_size; /* -H */ -extern int no_gnu_extensions; /* -G */ -extern int prefix_all_builtins; /* -P */ -extern int max_debug_argument_length; /* -l */ -extern int suppress_warnings; /* -Q */ -extern int warning_status; /* -E */ -extern int nesting_limit; /* -L */ -#ifdef ENABLE_CHANGEWORD -extern const char *user_word_regexp; /* -W */ -#endif - -/* Error handling. */ -extern int retcode; - -extern void m4_error (int, int, const char *, ...) M4_GNUC_PRINTF(3, 4); -extern void m4_error_at_line (int, int, const char *, int, - const char *, ...) M4_GNUC_PRINTF(5, 6); - -#define M4ERROR(Arglist) (m4_error Arglist) -#define M4ERROR_AT_LINE(Arglist) (m4_error_at_line Arglist) - - -/* File: debug.c --- debugging and tracing function. */ - -extern FILE *debug; - -/* The value of debug_level is a bitmask of the following. */ - -/* a: show arglist in trace output */ -#define DEBUG_TRACE_ARGS 1 -/* e: show expansion in trace output */ -#define DEBUG_TRACE_EXPANSION 2 -/* q: quote args and expansion in trace output */ -#define DEBUG_TRACE_QUOTE 4 -/* t: trace all macros -- overrides trace{on,off} */ -#define DEBUG_TRACE_ALL 8 -/* l: add line numbers to trace output */ -#define DEBUG_TRACE_LINE 16 -/* f: add file name to trace output */ -#define DEBUG_TRACE_FILE 32 -/* p: trace path search of include files */ -#define DEBUG_TRACE_PATH 64 -/* c: show macro call before args collection */ -#define DEBUG_TRACE_CALL 128 -/* i: trace changes of input files */ -#define DEBUG_TRACE_INPUT 256 -/* x: add call id to trace output */ -#define DEBUG_TRACE_CALLID 512 - -/* V: very verbose -- print everything */ -#define DEBUG_TRACE_VERBOSE 1023 -/* default flags -- equiv: aeq */ -#define DEBUG_TRACE_DEFAULT 7 - -#define DEBUG_PRINT1(Fmt, Arg1) \ - do \ - { \ - if (debug != NULL) \ - xfprintf (debug, Fmt, Arg1); \ - } \ - while (0) - -#define DEBUG_PRINT3(Fmt, Arg1, Arg2, Arg3) \ - do \ - { \ - if (debug != NULL) \ - xfprintf (debug, Fmt, Arg1, Arg2, Arg3); \ - } \ - while (0) - -#define DEBUG_MESSAGE(Fmt) \ - do \ - { \ - if (debug != NULL) \ - { \ - debug_message_prefix (); \ - xfprintf (debug, Fmt); \ - putc ('\n', debug); \ - } \ - } \ - while (0) - -#define DEBUG_MESSAGE1(Fmt, Arg1) \ - do \ - { \ - if (debug != NULL) \ - { \ - debug_message_prefix (); \ - xfprintf (debug, Fmt, Arg1); \ - putc ('\n', debug); \ - } \ - } \ - while (0) - -#define DEBUG_MESSAGE2(Fmt, Arg1, Arg2) \ - do \ - { \ - if (debug != NULL) \ - { \ - debug_message_prefix (); \ - xfprintf (debug, Fmt, Arg1, Arg2); \ - putc ('\n', debug); \ - } \ - } \ - while (0) - -extern void debug_init (void); -extern int debug_decode (const char *); -extern void debug_flush_files (void); -extern bool debug_set_output (const char *); -extern void debug_message_prefix (void); - -extern void trace_prepre (const char *, int); -extern void trace_pre (const char *, int, int, token_data **); -extern void trace_post (const char *, int, int, const char *); - -/* File: input.c --- lexical definitions. */ - -/* Various different token types. */ -enum token_type -{ - TOKEN_EOF, /* end of file */ - TOKEN_STRING, /* a quoted string or comment */ - TOKEN_WORD, /* an identifier */ - TOKEN_OPEN, /* ( */ - TOKEN_COMMA, /* , */ - TOKEN_CLOSE, /* ) */ - TOKEN_SIMPLE, /* any other single character */ - TOKEN_MACDEF /* a macro's definition (see "defn") */ -}; - -/* The data for a token, a macro argument, and a macro definition. */ -enum token_data_type -{ - TOKEN_VOID, - TOKEN_TEXT, - TOKEN_FUNC -}; - -struct token_data -{ - enum token_data_type type; - union - { - struct - { - char *text; -#ifdef ENABLE_CHANGEWORD - char *original_text; -#endif - } - u_t; - builtin_func *func; - } - u; -}; - -#define TOKEN_DATA_TYPE(Td) ((Td)->type) -#define TOKEN_DATA_TEXT(Td) ((Td)->u.u_t.text) -#ifdef ENABLE_CHANGEWORD -# define TOKEN_DATA_ORIG_TEXT(Td) ((Td)->u.u_t.original_text) -#endif -#define TOKEN_DATA_FUNC(Td) ((Td)->u.func) - -typedef enum token_type token_type; -typedef enum token_data_type token_data_type; - -extern void input_init (void); -extern token_type peek_token (void); -extern token_type next_token (token_data *, int *); -extern void skip_line (void); - -/* push back input */ -extern void push_file (FILE *, const char *, bool); -extern void push_macro (builtin_func *); -extern struct obstack *push_string_init (void); -extern const char *push_string_finish (void); -extern void push_wrapup (const char *); -extern bool pop_wrapup (void); - -/* current input file, and line */ -extern const char *current_file; -extern int current_line; - -/* left and right quote, begin and end comment */ -extern STRING bcomm; -extern STRING ecomm; -extern STRING lquote; -extern STRING rquote; - -#define DEF_LQUOTE "`" -#define DEF_RQUOTE "\'" -#define DEF_BCOMM "#" -#define DEF_ECOMM "\n" - -extern void set_quotes (const char *, const char *); -extern void set_comment (const char *, const char *); -#ifdef ENABLE_CHANGEWORD -extern void set_word_regexp (const char *); -#endif - -/* File: output.c --- output functions. */ -extern int current_diversion; -extern int output_current_line; - -extern void output_init (void); -extern void output_exit (void); -extern void output_text (const char *, int); -extern void shipout_text (struct obstack *, const char *, int, int); -extern void make_diversion (int); -extern void insert_diversion (int); -extern void insert_file (FILE *); -extern void freeze_diversions (FILE *); - -/* File symtab.c --- symbol table definitions. */ - -/* Operation modes for lookup_symbol (). */ -enum symbol_lookup -{ - SYMBOL_LOOKUP, - SYMBOL_INSERT, - SYMBOL_DELETE, - SYMBOL_PUSHDEF, - SYMBOL_POPDEF -}; - -/* Symbol table entry. */ -struct symbol -{ - struct symbol *next; - bool_bitfield traced : 1; - bool_bitfield shadowed : 1; - bool_bitfield macro_args : 1; - bool_bitfield blind_no_args : 1; - bool_bitfield deleted : 1; - int pending_expansions; - - char *name; - token_data data; -}; - -#define SYMBOL_NEXT(S) ((S)->next) -#define SYMBOL_TRACED(S) ((S)->traced) -#define SYMBOL_SHADOWED(S) ((S)->shadowed) -#define SYMBOL_MACRO_ARGS(S) ((S)->macro_args) -#define SYMBOL_BLIND_NO_ARGS(S) ((S)->blind_no_args) -#define SYMBOL_DELETED(S) ((S)->deleted) -#define SYMBOL_PENDING_EXPANSIONS(S) ((S)->pending_expansions) -#define SYMBOL_NAME(S) ((S)->name) -#define SYMBOL_TYPE(S) (TOKEN_DATA_TYPE (&(S)->data)) -#define SYMBOL_TEXT(S) (TOKEN_DATA_TEXT (&(S)->data)) -#define SYMBOL_FUNC(S) (TOKEN_DATA_FUNC (&(S)->data)) - -typedef enum symbol_lookup symbol_lookup; -typedef struct symbol symbol; -typedef void hack_symbol (symbol *, void *); - -#define HASHMAX 509 /* default, overridden by -Hsize */ - -extern symbol **symtab; - -extern void free_symbol (symbol *sym); -extern void symtab_init (void); -extern symbol *lookup_symbol (const char *, symbol_lookup); -extern void hack_all_symbols (hack_symbol *, void *); - -/* File: macro.c --- macro expansion. */ - -extern int expansion_level; - -extern void expand_input (void); -extern void call_macro (symbol *, int, token_data **, struct obstack *); - -/* File: builtin.c --- builtins. */ - -struct builtin -{ - const char *name; - bool_bitfield gnu_extension : 1; - bool_bitfield groks_macro_args : 1; - bool_bitfield blind_if_no_args : 1; - builtin_func *func; -}; - -struct predefined -{ - const char *unix_name; - const char *gnu_name; - const char *func; -}; - -typedef struct builtin builtin; -typedef struct predefined predefined; -struct re_pattern_buffer; -struct re_registers; - -/* The default sequence detects multi-digit parameters (obsolete after - 1.4.x), and any use of extended arguments with the default ${} - syntax (new in 2.0). */ -#define DEFAULT_MACRO_SEQUENCE "\\$\\({[^}]*}\\|[0-9][0-9]+\\)" - -extern void builtin_init (void); -extern void define_builtin (const char *, const builtin *, symbol_lookup); -extern void set_macro_sequence (const char *); -extern void free_macro_sequence (void); -extern void define_user_macro (const char *, const char *, symbol_lookup); -extern void undivert_all (void); -extern void expand_user_macro (struct obstack *, symbol *, int, token_data **); -extern void m4_placeholder (struct obstack *, int, token_data **); -extern void init_pattern_buffer (struct re_pattern_buffer *, - struct re_registers *); -extern const char *ntoa (int32_t, int); - -extern const builtin *find_builtin_by_addr (builtin_func *); -extern const builtin *find_builtin_by_name (const char *); - -/* File: path.c --- path search for include files. */ - -extern void include_init (void); -extern void include_env_init (void); -extern void add_include_directory (const char *); -extern FILE *m4_path_search (const char *, char **); - -/* File: eval.c --- expression evaluation. */ - -extern bool evaluate (const char *, int32_t *); - -/* File: format.c --- printf like formatting. */ - -extern void expand_format (struct obstack *, int, token_data **); - -/* File: freeze.c --- frozen state files. */ - -extern void produce_frozen_state (const char *); -extern void reload_frozen_state (const char *); - -/* Debugging the memory allocator. */ - -#ifdef WITH_DMALLOC -# define DMALLOC_FUNC_CHECK -# include <dmalloc.h> -#endif - -/* Other debug stuff. */ - -#ifdef DEBUG -# define DEBUG_INCL 1 -# define DEBUG_INPUT 1 -# define DEBUG_MACRO 1 -# define DEBUG_OUTPUT 1 -# define DEBUG_STKOVF 1 -# define DEBUG_SYM 1 -#endif - -/* Convert a possibly-signed character to an unsigned character. This is - a bit safer than casting to unsigned char, since it catches some type - errors that the cast doesn't. */ -#if HAVE_INLINE -static inline unsigned char to_uchar (char ch) { return ch; } -#else -# define to_uchar(C) ((unsigned char) (C)) -#endif - -/* Avoid negative logic when comparing two strings. */ -#define STREQ(a, b) (strcmp (a, b) == 0) diff --git a/contrib/tools/bison/m4/src/macro.c b/contrib/tools/bison/m4/src/macro.c deleted file mode 100644 index 0e7624372e..0000000000 --- a/contrib/tools/bison/m4/src/macro.c +++ /dev/null @@ -1,391 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2006-2007, 2009-2013 Free Software - Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* This file contains the functions, that performs the basic argument - parsing and macro expansion. */ - -#include "m4.h" - -static void expand_macro (symbol *); -static void expand_token (struct obstack *, token_type, token_data *, int); - -/* Current recursion level in expand_macro (). */ -int expansion_level = 0; - -/* The number of the current call of expand_macro (). */ -static int macro_call_id = 0; - -/* The shared stack of collected arguments for macro calls; as each - argument is collected, it is finished and its location stored in - argv_stack. Normally, this stack can be used simultaneously by - multiple macro calls; the exception is when an outer macro has - generated some text, then calls a nested macro, in which case the - nested macro must use a local stack to leave the unfinished text - alone. Too bad obstack.h does not provide an easy way to reopen a - finished object for further growth, but in practice this does not - hurt us too much. */ -static struct obstack argc_stack; - -/* The shared stack of pointers to collected arguments for macro - calls. This object is never finished; we exploit the fact that - obstack_blank is documented to take a negative size to reduce the - size again. */ -static struct obstack argv_stack; - -/*----------------------------------------------------------------------. -| This function read all input, and expands each token, one at a time. | -`----------------------------------------------------------------------*/ - -void -expand_input (void) -{ - token_type t; - token_data td; - int line; - - obstack_init (&argc_stack); - obstack_init (&argv_stack); - - while ((t = next_token (&td, &line)) != TOKEN_EOF) - expand_token ((struct obstack *) NULL, t, &td, line); - - obstack_free (&argc_stack, NULL); - obstack_free (&argv_stack, NULL); -} - - -/*----------------------------------------------------------------. -| Expand one token, according to its type. Potential macro names | -| (TOKEN_WORD) are looked up in the symbol table, to see if they | -| have a macro definition. If they have, they are expanded as | -| macros, otherwise the text is just copied to the output. | -`----------------------------------------------------------------*/ - -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 (); - } -} - - -/*-------------------------------------------------------------------. -| This function parses one argument to a macro call. It expects the | -| first left parenthesis, or the separating comma, to have been read | -| by the caller. It skips leading whitespace, and reads and expands | -| tokens, until it finds a comma or an right parenthesis at the same | -| level of parentheses. It returns a flag indicating whether the | -| argument read is the last for the active macro call. The argument | -| is built on the obstack OBS, indirectly through expand_token (). | -`-------------------------------------------------------------------*/ - -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); - } -} - -/*-------------------------------------------------------------. -| Collect all the arguments to a call of the macro SYM. The | -| arguments are stored on the obstack ARGUMENTS and a table of | -| pointers to the arguments on the obstack ARGPTR. | -`-------------------------------------------------------------*/ - -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); - } -} - - -/*-------------------------------------------------------------------. -| The actual call of a macro is handled by call_macro (). | -| call_macro () is passed a symbol SYM, whose type is used to call | -| either a builtin function, or the user macro expansion function | -| expand_user_macro () (lives in builtin.c). There are ARGC | -| arguments to the call, stored in the ARGV table. The expansion is | -| left on the obstack EXPANSION. Macro tracing is also handled | -| here. | -`-------------------------------------------------------------------*/ - -void -call_macro (symbol *sym, int argc, token_data **argv, - struct obstack *expansion) -{ - switch (SYMBOL_TYPE (sym)) - { - case TOKEN_FUNC: - (*SYMBOL_FUNC (sym)) (expansion, argc, argv); - break; - - case TOKEN_TEXT: - expand_user_macro (expansion, sym, argc, argv); - break; - - case TOKEN_VOID: - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: bad symbol type in call_macro ()")); - abort (); - } -} - -/*-------------------------------------------------------------------. -| The macro expansion is handled by expand_macro (). It parses the | -| arguments, using collect_arguments (), and builds a table of | -| pointers to the arguments. The arguments themselves are stored on | -| a local obstack. Expand_macro () uses call_macro () to do the | -| call of the macro. | -| | -| Expand_macro () is potentially recursive, since it calls | -| expand_argument (), which might call expand_token (), which might | -| call expand_macro (). | -`-------------------------------------------------------------------*/ - -static void -expand_macro (symbol *sym) -{ - struct obstack arguments; /* Alternate obstack if argc_stack is busy. */ - unsigned argv_base; /* Size of argv_stack on entry. */ - bool use_argc_stack = true; /* Whether argc_stack is safe. */ - token_data **argv; - int argc; - struct obstack *expansion; - const char *expanded; - bool traced; - int my_call_id; - - /* Report errors at the location where the open parenthesis (if any) - was found, but after expansion, restore global state back to the - location of the close parenthesis. This is safe since we - guarantee that macro expansion does not alter the state of - current_file/current_line (dnl, include, and sinclude are special - cased in the input engine to ensure this fact). */ - const char *loc_open_file = current_file; - int loc_open_line = current_line; - const char *loc_close_file; - int loc_close_line; - - SYMBOL_PENDING_EXPANSIONS (sym)++; - expansion_level++; - if (nesting_limit > 0 && expansion_level > nesting_limit) - M4ERROR ((EXIT_FAILURE, 0, - "recursion limit of %d exceeded, use -L<N> to change it", - nesting_limit)); - - macro_call_id++; - my_call_id = macro_call_id; - - traced = (debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym); - - argv_base = obstack_object_size (&argv_stack); - if (obstack_object_size (&argc_stack) > 0) - { - /* We cannot use argc_stack if this is a nested invocation, and an - outer invocation has an unfinished argument being - collected. */ - obstack_init (&arguments); - use_argc_stack = false; - } - - if (traced && (debug_level & DEBUG_TRACE_CALL)) - trace_prepre (SYMBOL_NAME (sym), my_call_id); - - collect_arguments (sym, &argv_stack, - use_argc_stack ? &argc_stack : &arguments); - - argc = ((obstack_object_size (&argv_stack) - argv_base) - / sizeof (token_data *)); - argv = (token_data **) ((char *) obstack_base (&argv_stack) + argv_base); - - loc_close_file = current_file; - loc_close_line = current_line; - current_file = loc_open_file; - current_line = loc_open_line; - - if (traced) - trace_pre (SYMBOL_NAME (sym), my_call_id, argc, argv); - - expansion = push_string_init (); - call_macro (sym, argc, argv, expansion); - expanded = push_string_finish (); - - if (traced) - trace_post (SYMBOL_NAME (sym), my_call_id, argc, expanded); - - current_file = loc_close_file; - current_line = loc_close_line; - - --expansion_level; - --SYMBOL_PENDING_EXPANSIONS (sym); - - if (SYMBOL_DELETED (sym)) - free_symbol (sym); - - if (use_argc_stack) - obstack_free (&argc_stack, argv[0]); - else - obstack_free (&arguments, NULL); - obstack_blank (&argv_stack, -argc * sizeof (token_data *)); -} diff --git a/contrib/tools/bison/m4/src/output.c b/contrib/tools/bison/m4/src/output.c deleted file mode 100644 index c378afebdb..0000000000 --- a/contrib/tools/bison/m4/src/output.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2004-2013 Free Software Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -#include "m4.h" - -#include <limits.h> -#include <sys/stat.h> - -#include "gl_avltree_oset.h" -#include "gl_xoset.h" - -/* Size of initial in-memory buffer size for diversions. Small diversions - would usually fit in. */ -#define INITIAL_BUFFER_SIZE 512 - -/* Maximum value for the total of all in-memory buffer sizes for - diversions. */ -#define MAXIMUM_TOTAL_SIZE (512 * 1024) - -/* Size of buffer size to use while copying files. */ -#define COPY_BUFFER_SIZE (32 * 512) - -/* Output functions. Most of the complexity is for handling cpp like - sync lines. - - This code is fairly entangled with the code in input.c, and maybe it - belongs there? */ - -typedef struct temp_dir m4_temp_dir; - -/* When part of diversion_table, each struct m4_diversion either - represents an open file (zero size, non-NULL u.file), an in-memory - buffer (non-zero size, non-NULL u.buffer), or an unused placeholder - diversion (zero size, u is NULL, non-zero used indicates that a - file has been created). When not part of diversion_table, u.next - is a pointer to the free_list chain. */ - -typedef struct m4_diversion m4_diversion; - -struct m4_diversion - { - union - { - FILE *file; /* Diversion file on disk. */ - char *buffer; /* Malloc'd diversion buffer. */ - m4_diversion *next; /* Free-list pointer */ - } u; - int divnum; /* Which diversion this represents. */ - int size; /* Usable size before reallocation. */ - int used; /* Used buffer length, or tmp file exists. */ - }; - -/* Table of diversions 1 through INT_MAX. */ -static gl_oset_t diversion_table; - -/* Diversion 0 (not part of diversion_table). */ -static m4_diversion div0; - -/* Linked list of reclaimed diversion storage. */ -static m4_diversion *free_list; - -/* Obstack from which diversion storage is allocated. */ -static struct obstack diversion_storage; - -/* Total size of all in-memory buffer sizes. */ -static int total_buffer_size; - -/* The number of the currently active diversion. This variable is - maintained for the `divnum' builtin function. */ -int current_diversion; - -/* Current output diversion, NULL if output is being currently - discarded. output_diversion->u is guaranteed non-NULL except when - the diversion has never been used; use size to determine if it is a - malloc'd buffer or a FILE. output_diversion->used is 0 if u.file - is stdout, and non-zero if this is a malloc'd buffer or a temporary - diversion file. */ -static m4_diversion *output_diversion; - -/* Cache of output_diversion->u.file, only valid when - output_diversion->size is 0. */ -static FILE *output_file; - -/* Cache of output_diversion->u.buffer + output_diversion->used, only - valid when output_diversion->size is non-zero. */ -static char *output_cursor; - -/* Cache of output_diversion->size - output_diversion->used, only - valid when output_diversion->size is non-zero. */ -static int output_unused; - -/* Number of input line we are generating output for. */ -int output_current_line; - -/* Temporary directory holding all spilled diversion files. */ -static m4_temp_dir *output_temp_dir; - -/* Cache of most recently used spilled diversion files. */ -static FILE *tmp_file1; -static FILE *tmp_file2; - -/* Diversions that own tmp_file, or 0. */ -static int tmp_file1_owner; -static int tmp_file2_owner; - -/* True if tmp_file2 is more recently used. */ -static bool tmp_file2_recent; - - -/* Internal routines. */ - -/* Callback for comparing list elements ELT1 and ELT2 for order in - diversion_table. */ -static int -cmp_diversion_CB (const void *elt1, const void *elt2) -{ - const m4_diversion *d1 = (const m4_diversion *) elt1; - const m4_diversion *d2 = (const m4_diversion *) elt2; - /* No need to worry about overflow, since we don't create diversions - with negative divnum. */ - return d1->divnum - d2->divnum; -} - -/* Callback for comparing list element ELT against THRESHOLD. */ -static bool -threshold_diversion_CB (const void *elt, const void *threshold) -{ - const m4_diversion *diversion = (const m4_diversion *) elt; - /* No need to worry about overflow, since we don't create diversions - with negative divnum. */ - return diversion->divnum >= *(const int *) threshold; -} - -/* Clean up any temporary directory. Designed for use as an atexit - handler, where it is not safe to call exit() recursively; so this - calls _exit if a problem is encountered. */ -static void -cleanup_tmpfile (void) -{ - /* Close any open diversions. */ - bool fail = false; - - if (diversion_table) - { - const void *elt; - gl_oset_iterator_t iter = gl_oset_iterator (diversion_table); - while (gl_oset_iterator_next (&iter, &elt)) - { - m4_diversion *diversion = (m4_diversion *) elt; - if (!diversion->size && diversion->u.file - && close_stream_temp (diversion->u.file) != 0) - { - M4ERROR ((0, errno, - "cannot clean temporary file for diversion")); - fail = true; - } - } - gl_oset_iterator_free (&iter); - } - - /* Clean up the temporary directory. */ - if (cleanup_temp_dir (output_temp_dir) != 0) - fail = true; - if (fail) - _exit (exit_failure); -} - -/* Convert DIVNUM into a temporary file name for use in m4_tmp*. */ -static const char * -m4_tmpname (int divnum) -{ - static char *buffer; - static char *tail; - if (buffer == NULL) - { - tail = xasprintf ("%s/m4-%d", output_temp_dir->dir_name, INT_MAX); - buffer = (char *) obstack_copy0 (&diversion_storage, tail, - strlen (tail)); - free (tail); - tail = strrchr (buffer, '-') + 1; - } - assert (0 < divnum); - sprintf (tail, "%d", divnum); - return buffer; -} - -/* Create a temporary file for diversion DIVNUM open for reading and - writing in a secure temp directory. The file will be automatically - closed and deleted on a fatal signal. The file can be closed and - reopened with m4_tmpclose and m4_tmpopen, or moved with - m4_tmprename; when finally done with the file, close it with - m4_tmpremove. Exits on failure, so the return value is always an - open file. */ -static FILE * -m4_tmpfile (int divnum) -{ - const char *name; - FILE *file; - - if (output_temp_dir == NULL) - { - output_temp_dir = create_temp_dir ("m4-", NULL, true); - if (output_temp_dir == NULL) - M4ERROR ((EXIT_FAILURE, errno, - "cannot create temporary file for diversion")); - atexit (cleanup_tmpfile); - } - name = m4_tmpname (divnum); - register_temp_file (output_temp_dir, name); - file = fopen_temp (name, O_BINARY ? "wb+" : "w+"); - if (file == NULL) - { - unregister_temp_file (output_temp_dir, name); - M4ERROR ((EXIT_FAILURE, errno, - "cannot create temporary file for diversion")); - } - else if (set_cloexec_flag (fileno (file), true) != 0) - M4ERROR ((warning_status, errno, - "Warning: cannot protect diversion across forks")); - return file; -} - -/* Reopen a temporary file for diversion DIVNUM for reading and - writing in a secure temp directory. If REREAD, the file is - positioned at offset 0, otherwise the file is positioned at the - end. Exits on failure, so the return value is always an open - file. */ -static FILE * -m4_tmpopen (int divnum, bool reread) -{ - const char *name; - FILE *file; - - if (tmp_file1_owner == divnum) - { - if (reread && fseeko (tmp_file1, 0, SEEK_SET) != 0) - m4_error (EXIT_FAILURE, errno, - _("cannot seek within diversion")); - tmp_file2_recent = false; - return tmp_file1; - } - else if (tmp_file2_owner == divnum) - { - if (reread && fseeko (tmp_file2, 0, SEEK_SET) != 0) - m4_error (EXIT_FAILURE, errno, - _("cannot seek within diversion")); - tmp_file2_recent = true; - return tmp_file2; - } - name = m4_tmpname (divnum); - /* We need update mode, to avoid truncation. */ - file = fopen_temp (name, O_BINARY ? "rb+" : "r+"); - if (file == NULL) - M4ERROR ((EXIT_FAILURE, errno, - "cannot create temporary file for diversion")); - else if (set_cloexec_flag (fileno (file), true) != 0) - m4_error (0, errno, _("cannot protect diversion across forks")); - /* Update mode starts at the beginning of the stream, but sometimes - we want the end. */ - else if (!reread && fseeko (file, 0, SEEK_END) != 0) - m4_error (EXIT_FAILURE, errno, - _("cannot seek within diversion")); - return file; -} - -/* Close, but don't delete, a temporary FILE for diversion DIVNUM. To - reduce the I/O overhead of repeatedly opening and closing the same - file, this implementation caches the most recent spilled diversion. - On the other hand, keeping every spilled diversion open would run - into EMFILE limits. */ -static int -m4_tmpclose (FILE *file, int divnum) -{ - int result = 0; - if (divnum != tmp_file1_owner && divnum != tmp_file2_owner) - { - if (tmp_file2_recent) - { - if (tmp_file1_owner) - result = close_stream_temp (tmp_file1); - tmp_file1 = file; - tmp_file1_owner = divnum; - } - else - { - if (tmp_file2_owner) - result = close_stream_temp (tmp_file2); - tmp_file2 = file; - tmp_file2_owner = divnum; - } - } - return result; -} - -/* Delete a closed temporary FILE for diversion DIVNUM. */ -static int -m4_tmpremove (int divnum) -{ - if (divnum == tmp_file1_owner) - { - int result = close_stream_temp (tmp_file1); - if (result) - return result; - tmp_file1_owner = 0; - } - else if (divnum == tmp_file2_owner) - { - int result = close_stream_temp (tmp_file2); - if (result) - return result; - tmp_file2_owner = 0; - } - return cleanup_temp_file (output_temp_dir, m4_tmpname (divnum)); -} - -/* Transfer the temporary file for diversion OLDNUM to the previously - unused diversion NEWNUM. Return an open stream visiting the new - temporary file, positioned at the end, or exit on failure. */ -static FILE* -m4_tmprename (int oldnum, int newnum) -{ - /* m4_tmpname reuses its return buffer. */ - char *oldname = xstrdup (m4_tmpname (oldnum)); - const char *newname = m4_tmpname (newnum); - register_temp_file (output_temp_dir, newname); - if (oldnum == tmp_file1_owner) - { - /* Be careful of mingw, which can't rename an open file. */ - if (RENAME_OPEN_FILE_WORKS) - tmp_file1_owner = newnum; - else - { - if (close_stream_temp (tmp_file1)) - m4_error (EXIT_FAILURE, errno, - _("cannot close temporary file for diversion")); - tmp_file1_owner = 0; - } - } - else if (oldnum == tmp_file2_owner) - { - /* Be careful of mingw, which can't rename an open file. */ - if (RENAME_OPEN_FILE_WORKS) - tmp_file2_owner = newnum; - else - { - if (close_stream_temp (tmp_file2)) - m4_error (EXIT_FAILURE, errno, - _("cannot close temporary file for diversion")); - tmp_file2_owner = 0; - } - } - /* Either it is safe to rename an open file, or no one should have - oldname open at this point. */ - if (rename (oldname, newname)) - m4_error (EXIT_FAILURE, errno, - _("cannot create temporary file for diversion")); - unregister_temp_file (output_temp_dir, oldname); - free (oldname); - return m4_tmpopen (newnum, false); -} - - -/*------------------------. -| Output initialization. | -`------------------------*/ - -void -output_init (void) -{ - diversion_table = gl_oset_create_empty (GL_AVLTREE_OSET, cmp_diversion_CB, - NULL); - div0.u.file = stdout; - output_diversion = &div0; - output_file = stdout; - obstack_init (&diversion_storage); -} - -void -output_exit (void) -{ - /* Order is important, since we may have registered cleanup_tmpfile - as an atexit handler, and it must not traverse stale memory. */ - gl_oset_t table = diversion_table; - if (tmp_file1_owner) - m4_tmpremove (tmp_file1_owner); - if (tmp_file2_owner) - m4_tmpremove (tmp_file2_owner); - diversion_table = NULL; - gl_oset_free (table); - obstack_free (&diversion_storage, NULL); -} - -/*----------------------------------------------------------------. -| Reorganize in-memory diversion buffers so the current diversion | -| can accomodate LENGTH more characters without further | -| reorganization. The current diversion buffer is made bigger if | -| possible. But to make room for a bigger buffer, one of the | -| in-memory diversion buffers might have to be flushed to a newly | -| created temporary file. This flushed buffer might well be the | -| current one. | -`----------------------------------------------------------------*/ - -static void -make_room_for (int length) -{ - int wanted_size; - m4_diversion *selected_diversion = NULL; - - /* Compute needed size for in-memory buffer. Diversions in-memory - buffers start at 0 bytes, then 512, then keep doubling until it is - decided to flush them to disk. */ - - output_diversion->used = output_diversion->size - output_unused; - - for (wanted_size = output_diversion->size; - wanted_size < output_diversion->used + length; - wanted_size = wanted_size == 0 ? INITIAL_BUFFER_SIZE : wanted_size * 2) - ; - - /* Check if we are exceeding the maximum amount of buffer memory. */ - - if (total_buffer_size - output_diversion->size + wanted_size - > MAXIMUM_TOTAL_SIZE) - { - int selected_used; - char *selected_buffer; - m4_diversion *diversion; - int count; - gl_oset_iterator_t iter; - const void *elt; - - /* Find out the buffer having most data, in view of flushing it to - disk. Fake the current buffer as having already received the - projected data, while making the selection. So, if it is - selected indeed, we will flush it smaller, before it grows. */ - - selected_diversion = output_diversion; - selected_used = output_diversion->used + length; - - iter = gl_oset_iterator (diversion_table); - while (gl_oset_iterator_next (&iter, &elt)) - { - diversion = (m4_diversion *) elt; - if (diversion->used > selected_used) - { - selected_diversion = diversion; - selected_used = diversion->used; - } - } - gl_oset_iterator_free (&iter); - - /* Create a temporary file, write the in-memory buffer of the - diversion to this file, then release the buffer. Zero the - diversion before doing anything that can exit () (including - m4_tmpfile), so that the atexit handler doesn't try to close - a garbage pointer as a file. */ - - selected_buffer = selected_diversion->u.buffer; - total_buffer_size -= selected_diversion->size; - selected_diversion->size = 0; - selected_diversion->u.file = NULL; - selected_diversion->u.file = m4_tmpfile (selected_diversion->divnum); - - if (selected_diversion->used > 0) - { - count = fwrite (selected_buffer, (size_t) selected_diversion->used, - 1, selected_diversion->u.file); - if (count != 1) - M4ERROR ((EXIT_FAILURE, errno, - "ERROR: cannot flush diversion to temporary file")); - } - - /* Reclaim the buffer space for other diversions. */ - - free (selected_buffer); - selected_diversion->used = 1; - } - - /* Reload output_file, just in case the flushed diversion was current. */ - - if (output_diversion == selected_diversion) - { - /* The flushed diversion was current indeed. */ - - output_file = output_diversion->u.file; - output_cursor = NULL; - output_unused = 0; - } - else - { - /* Close any selected file since it is not the current diversion. */ - if (selected_diversion) - { - FILE *file = selected_diversion->u.file; - selected_diversion->u.file = NULL; - if (m4_tmpclose (file, selected_diversion->divnum) != 0) - m4_error (0, errno, - _("cannot close temporary file for diversion")); - } - - /* The current buffer may be safely reallocated. */ - { - char *buffer = output_diversion->u.buffer; - output_diversion->u.buffer = xcharalloc ((size_t) wanted_size); - memcpy (output_diversion->u.buffer, buffer, output_diversion->used); - free (buffer); - } - - total_buffer_size += wanted_size - output_diversion->size; - output_diversion->size = wanted_size; - - output_cursor = output_diversion->u.buffer + output_diversion->used; - output_unused = wanted_size - output_diversion->used; - } -} - -/*--------------------------------------------------------------. -| Output one character CHAR, when it is known that it goes to a | -| diversion file or an in-memory diversion buffer. | -`--------------------------------------------------------------*/ - -#define OUTPUT_CHARACTER(Char) \ - if (output_file) \ - putc ((Char), output_file); \ - else if (output_unused == 0) \ - output_character_helper ((Char)); \ - else \ - (output_unused--, *output_cursor++ = (Char)) - -static void -output_character_helper (int character) -{ - make_room_for (1); - - if (output_file) - putc (character, output_file); - else - { - *output_cursor++ = character; - output_unused--; - } -} - -/*-------------------------------------------------------------------. -| Output one TEXT having LENGTH characters, when it is known that it | -| goes to a diversion file or an in-memory diversion buffer. | -`-------------------------------------------------------------------*/ - -void -output_text (const char *text, int length) -{ - int count; - - if (!output_diversion || !length) - return; - - if (!output_file && length > output_unused) - make_room_for (length); - - if (output_file) - { - count = fwrite (text, length, 1, output_file); - if (count != 1) - M4ERROR ((EXIT_FAILURE, errno, "ERROR: copying inserted file")); - } - else - { - memcpy (output_cursor, text, (size_t) length); - output_cursor += length; - output_unused -= length; - } -} - -/*--------------------------------------------------------------------. -| Add some text into an obstack OBS, taken from TEXT, having LENGTH | -| characters. If OBS is NULL, output the text to an external file | -| or an in-memory diversion buffer instead. If OBS is NULL, and | -| there is no output file, the text is discarded. LINE is the line | -| where the token starts (not necessarily current_line, in the case | -| of multiline tokens). | -| | -| If we are generating sync lines, the output has to be examined, | -| because we need to know how much output each input line generates. | -| In general, sync lines are output whenever a single input lines | -| generates several output lines, or when several input lines do not | -| generate any output. | -`--------------------------------------------------------------------*/ - -void -shipout_text (struct obstack *obs, const char *text, int length, int line) -{ - static bool start_of_output_line = true; - const char *cursor; - - /* If output goes to an obstack, merely add TEXT to it. */ - - if (obs != NULL) - { - obstack_grow (obs, text, length); - return; - } - - /* Do nothing if TEXT should be discarded. */ - - if (output_diversion == NULL) - return; - - /* Output TEXT to a file, or in-memory diversion buffer. */ - - if (!sync_output) - switch (length) - { - - /* In-line short texts. */ - - case 8: OUTPUT_CHARACTER (*text); text++; - case 7: OUTPUT_CHARACTER (*text); text++; - case 6: OUTPUT_CHARACTER (*text); text++; - case 5: OUTPUT_CHARACTER (*text); text++; - case 4: OUTPUT_CHARACTER (*text); text++; - case 3: OUTPUT_CHARACTER (*text); text++; - case 2: OUTPUT_CHARACTER (*text); text++; - case 1: OUTPUT_CHARACTER (*text); - case 0: - return; - - /* Optimize longer texts. */ - - default: - output_text (text, length); - } - else - { - /* Check for syncline only at the start of a token. Multiline - tokens, and tokens that are out of sync but in the middle of - the line, must wait until the next raw newline triggers a - syncline. */ - if (start_of_output_line) - { - start_of_output_line = false; - output_current_line++; -#ifdef DEBUG_OUTPUT - xfprintf (stderr, "DEBUG: line %d, cur %d, cur out %d\n", - line, current_line, output_current_line); -#endif - - /* Output a `#line NUM' synchronization directive if needed. - If output_current_line was previously given a negative - value (invalidated), output `#line NUM "FILE"' instead. */ - - if (output_current_line != line) - { - OUTPUT_CHARACTER ('#'); - OUTPUT_CHARACTER ('l'); - OUTPUT_CHARACTER ('i'); - OUTPUT_CHARACTER ('n'); - OUTPUT_CHARACTER ('e'); - OUTPUT_CHARACTER (' '); - for (cursor = ntoa (line, 10); *cursor; cursor++) - OUTPUT_CHARACTER (*cursor); - if (output_current_line < 1 && current_file[0] != '\0') - { - OUTPUT_CHARACTER (' '); - OUTPUT_CHARACTER ('"'); - for (cursor = current_file; *cursor; cursor++) - OUTPUT_CHARACTER (*cursor); - OUTPUT_CHARACTER ('"'); - } - OUTPUT_CHARACTER ('\n'); - output_current_line = line; - } - } - - /* Output the token, and track embedded newlines. */ - for (; length-- > 0; text++) - { - if (start_of_output_line) - { - start_of_output_line = false; - output_current_line++; -#ifdef DEBUG_OUTPUT - xfprintf (stderr, "DEBUG: line %d, cur %d, cur out %d\n", - line, current_line, output_current_line); -#endif - } - OUTPUT_CHARACTER (*text); - if (*text == '\n') - start_of_output_line = true; - } - } -} - -/* Functions for use by diversions. */ - -/*------------------------------------------------------------------. -| Make a file for diversion DIVNUM, and install it in the diversion | -| table. Grow the size of the diversion table as needed. | -`------------------------------------------------------------------*/ - -/* The number of possible diversions is limited only by memory and - available file descriptors (each overflowing diversion uses one). */ - -void -make_diversion (int divnum) -{ - m4_diversion *diversion = NULL; - - if (current_diversion == divnum) - return; - - if (output_diversion) - { - if (!output_diversion->size && !output_diversion->u.file) - { - assert (!output_diversion->used); - if (!gl_oset_remove (diversion_table, output_diversion)) - assert (false); - output_diversion->u.next = free_list; - free_list = output_diversion; - } - else if (output_diversion->size) - output_diversion->used = output_diversion->size - output_unused; - else if (output_diversion->used) - { - FILE *file = output_diversion->u.file; - output_diversion->u.file = NULL; - if (m4_tmpclose (file, output_diversion->divnum) != 0) - m4_error (0, errno, - _("cannot close temporary file for diversion")); - } - output_diversion = NULL; - output_file = NULL; - output_cursor = NULL; - output_unused = 0; - } - - current_diversion = divnum; - - if (divnum < 0) - return; - - if (divnum == 0) - diversion = &div0; - else - { - const void *elt; - if (gl_oset_search_atleast (diversion_table, threshold_diversion_CB, - &divnum, &elt)) - { - m4_diversion *temp = (m4_diversion *) elt; - if (temp->divnum == divnum) - diversion = temp; - } - } - if (diversion == NULL) - { - /* First time visiting this diversion. */ - if (free_list) - { - diversion = free_list; - free_list = diversion->u.next; - } - else - { - diversion = (m4_diversion *) obstack_alloc (&diversion_storage, - sizeof *diversion); - diversion->size = 0; - diversion->used = 0; - } - diversion->u.file = NULL; - diversion->divnum = divnum; - gl_oset_add (diversion_table, diversion); - } - - output_diversion = diversion; - if (output_diversion->size) - { - output_cursor = output_diversion->u.buffer + output_diversion->used; - output_unused = output_diversion->size - output_diversion->used; - } - else - { - if (!output_diversion->u.file && output_diversion->used) - output_diversion->u.file = m4_tmpopen (output_diversion->divnum, - false); - output_file = output_diversion->u.file; - } - output_current_line = -1; -} - -/*-------------------------------------------------------------------. -| Insert a FILE into the current output file, in the same manner | -| diversions are handled. This allows files to be included, without | -| having them rescanned by m4. | -`-------------------------------------------------------------------*/ - -void -insert_file (FILE *file) -{ - static char buffer[COPY_BUFFER_SIZE]; - size_t length; - - /* Optimize out inserting into a sink. */ - if (!output_diversion) - return; - - /* Insert output by big chunks. */ - while (1) - { - length = fread (buffer, 1, sizeof buffer, file); - if (ferror (file)) - M4ERROR ((EXIT_FAILURE, errno, "error reading inserted file")); - if (length == 0) - break; - output_text (buffer, length); - } -} - -/*-------------------------------------------------------------------. -| Insert DIVERSION (but not div0) into the current output file. The | -| diversion is NOT placed on the expansion obstack, because it must | -| not be rescanned. When the file is closed, it is deleted by the | -| system. | -`-------------------------------------------------------------------*/ - -static void -insert_diversion_helper (m4_diversion *diversion) -{ - /* Effectively undivert only if an output stream is active. */ - if (output_diversion) - { - if (diversion->size) - { - if (!output_diversion->u.file) - { - /* Transferring diversion metadata is faster than - copying contents. */ - assert (!output_diversion->used && output_diversion != &div0 - && !output_file); - output_diversion->u.buffer = diversion->u.buffer; - output_diversion->size = diversion->size; - output_cursor = diversion->u.buffer + diversion->used; - output_unused = diversion->size - diversion->used; - diversion->u.buffer = NULL; - } - else - { - /* Avoid double-charging the total in-memory size when - transferring from one in-memory diversion to - another. */ - total_buffer_size -= diversion->size; - output_text (diversion->u.buffer, diversion->used); - } - } - else if (!output_diversion->u.file) - { - /* Transferring diversion metadata is faster than copying - contents. */ - assert (!output_diversion->used && output_diversion != &div0 - && !output_file); - output_diversion->u.file = m4_tmprename (diversion->divnum, - output_diversion->divnum); - output_diversion->used = 1; - output_file = output_diversion->u.file; - diversion->u.file = NULL; - diversion->size = 1; - } - else - { - if (!diversion->u.file) - diversion->u.file = m4_tmpopen (diversion->divnum, true); - insert_file (diversion->u.file); - } - - output_current_line = -1; - } - - /* Return all space used by the diversion. */ - if (diversion->size) - { - if (!output_diversion) - total_buffer_size -= diversion->size; - free (diversion->u.buffer); - diversion->size = 0; - } - else - { - if (diversion->u.file) - { - FILE *file = diversion->u.file; - diversion->u.file = NULL; - if (m4_tmpclose (file, diversion->divnum) != 0) - m4_error (0, errno, - _("cannot clean temporary file for diversion")); - } - if (m4_tmpremove (diversion->divnum) != 0) - M4ERROR ((0, errno, "cannot clean temporary file for diversion")); - } - diversion->used = 0; - gl_oset_remove (diversion_table, diversion); - diversion->u.next = free_list; - free_list = diversion; -} - -/*------------------------------------------------------------------. -| Insert diversion number DIVNUM into the current output file. The | -| diversion is NOT placed on the expansion obstack, because it must | -| not be rescanned. When the file is closed, it is deleted by the | -| system. | -`------------------------------------------------------------------*/ - -void -insert_diversion (int divnum) -{ - const void *elt; - - /* Do not care about nonexistent diversions, and undiverting stdout - or self is a no-op. */ - if (divnum <= 0 || current_diversion == divnum) - return; - if (gl_oset_search_atleast (diversion_table, threshold_diversion_CB, - &divnum, &elt)) - { - m4_diversion *diversion = (m4_diversion *) elt; - if (diversion->divnum == divnum) - insert_diversion_helper (diversion); - } -} - -/*----------------------------------------------------------------. -| Get back all diversions. This is done just before exiting from | -| main, and from m4_undivert (), if called without arguments. | -`----------------------------------------------------------------*/ - -void -undivert_all (void) -{ - const void *elt; - gl_oset_iterator_t iter = gl_oset_iterator (diversion_table); - while (gl_oset_iterator_next (&iter, &elt)) - { - m4_diversion *diversion = (m4_diversion *) elt; - if (diversion->divnum != current_diversion) - insert_diversion_helper (diversion); - } - gl_oset_iterator_free (&iter); -} - -/*-------------------------------------------------------------. -| Produce all diversion information in frozen format on FILE. | -`-------------------------------------------------------------*/ - -void -freeze_diversions (FILE *file) -{ - int saved_number; - int last_inserted; - gl_oset_iterator_t iter; - const void *elt; - - saved_number = current_diversion; - last_inserted = 0; - make_diversion (0); - output_file = file; /* kludge in the frozen file */ - - iter = gl_oset_iterator (diversion_table); - while (gl_oset_iterator_next (&iter, &elt)) - { - m4_diversion *diversion = (m4_diversion *) elt; - if (diversion->size || diversion->used) - { - if (diversion->size) - xfprintf (file, "D%d,%d\n", diversion->divnum, diversion->used); - else - { - struct stat file_stat; - diversion->u.file = m4_tmpopen (diversion->divnum, true); - if (fstat (fileno (diversion->u.file), &file_stat) < 0) - M4ERROR ((EXIT_FAILURE, errno, "cannot stat diversion")); - if (file_stat.st_size < 0 - || (file_stat.st_size + 0UL - != (unsigned long int) file_stat.st_size)) - M4ERROR ((EXIT_FAILURE, 0, "diversion too large")); - xfprintf (file, "D%d,%lu\n", diversion->divnum, - (unsigned long int) file_stat.st_size); - } - - insert_diversion_helper (diversion); - putc ('\n', file); - - last_inserted = diversion->divnum; - } - } - gl_oset_iterator_free (&iter); - - /* Save the active diversion number, if not already. */ - - if (saved_number != last_inserted) - xfprintf (file, "D%d,0\n\n", saved_number); -} diff --git a/contrib/tools/bison/m4/src/path.c b/contrib/tools/bison/m4/src/path.c deleted file mode 100644 index 278200b782..0000000000 --- a/contrib/tools/bison/m4/src/path.c +++ /dev/null @@ -1,205 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1993, 2004, 2006-2013 Free Software Foundation, - Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* Handling of path search of included files via the builtins "include" - and "sinclude". */ - -#include "m4.h" - -struct includes -{ - struct includes *next; /* next directory to search */ - const char *dir; /* directory */ - int len; -}; - -typedef struct includes includes; - -static includes *dir_list; /* the list of path directories */ -static includes *dir_list_end; /* the end of same */ -static int dir_max_length; /* length of longest directory name */ - - -void -include_init (void) -{ - dir_list = NULL; - dir_list_end = NULL; - dir_max_length = 0; -} - -void -include_env_init (void) -{ - char *path; - char *path_end; - char *env_path; - - if (no_gnu_extensions) - return; - - env_path = getenv ("M4PATH"); - if (env_path == NULL) - return; - - env_path = xstrdup (env_path); - path = env_path; - - do - { - path_end = strchr (path, ':'); - if (path_end) - *path_end = '\0'; - add_include_directory (path); - path = path_end + 1; - } - while (path_end); - free (env_path); -} - -void -add_include_directory (const char *dir) -{ - includes *incl; - - if (no_gnu_extensions) - return; - - if (*dir == '\0') - dir = "."; - - incl = (includes *) xmalloc (sizeof (struct includes)); - incl->next = NULL; - incl->len = strlen (dir); - incl->dir = xstrdup (dir); - - if (incl->len > dir_max_length) /* remember len of longest directory */ - dir_max_length = incl->len; - - if (dir_list_end == NULL) - dir_list = incl; - else - dir_list_end->next = incl; - dir_list_end = incl; - -#ifdef DEBUG_INCL - xfprintf (stderr, "add_include_directory (%s);\n", dir); -#endif -} - -/* Attempt to open FILE; if it opens, verify that it is not a - directory, and ensure it does not leak across execs. */ -static FILE * -m4_fopen (const char *file) -{ - FILE *fp = fopen (file, "r"); - if (fp) - { - struct stat st; - int fd = fileno (fp); - if (fstat (fd, &st) == 0 && S_ISDIR (st.st_mode)) - { - fclose (fp); - errno = EISDIR; - return NULL; - } - if (set_cloexec_flag (fd, true) != 0) - M4ERROR ((warning_status, errno, - "Warning: cannot protect input file across forks")); - } - return fp; -} - -/* Search for FILE, first in `.', then according to -I options. If - successful, return the open file, and if RESULT is not NULL, set - *RESULT to a malloc'd string that represents the file found with - respect to the current working directory. */ - -FILE * -m4_path_search (const char *file, char **result) -{ - FILE *fp; - includes *incl; - char *name; /* buffer for constructed name */ - int e; - - if (result) - *result = NULL; - - /* Reject empty file. */ - if (!*file) - { - errno = ENOENT; - return NULL; - } - - /* Look in current working directory first. */ - fp = m4_fopen (file); - if (fp != NULL) - { - if (result) - *result = xstrdup (file); - return fp; - } - - /* If file not found, and filename absolute, fail. */ - if (IS_ABSOLUTE_FILE_NAME (file) || no_gnu_extensions) - return NULL; - e = errno; - - for (incl = dir_list; incl != NULL; incl = incl->next) - { - name = file_name_concat (incl->dir, file, NULL); - -#ifdef DEBUG_INCL - xfprintf (stderr, "m4_path_search (%s) -- trying %s\n", file, name); -#endif - - fp = m4_fopen (name); - if (fp != NULL) - { - if (debug_level & DEBUG_TRACE_PATH) - DEBUG_MESSAGE2 ("path search for `%s' found `%s'", file, name); - if (result) - *result = name; - else - free (name); - return fp; - } - free (name); - } - errno = e; - return fp; -} - -#ifdef DEBUG_INCL - -static void M4_GNUC_UNUSED -include_dump (void) -{ - includes *incl; - - xfprintf (stderr, "include_dump:\n"); - for (incl = dir_list; incl != NULL; incl = incl->next) - xfprintf (stderr, "\t%s\n", incl->dir); -} - -#endif /* DEBUG_INCL */ diff --git a/contrib/tools/bison/m4/src/symtab.c b/contrib/tools/bison/m4/src/symtab.c deleted file mode 100644 index 7448c272cc..0000000000 --- a/contrib/tools/bison/m4/src/symtab.c +++ /dev/null @@ -1,401 +0,0 @@ -/* GNU m4 -- A simple macro processor - - Copyright (C) 1989-1994, 2003, 2006-2013 Free Software Foundation, - Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -/* This file handles all the low level work around the symbol table. The - symbol table is a simple chained hash table. Each symbol is described - by a struct symbol, which is placed in the hash table based upon the - symbol name. Symbols that hash to the same entry in the table are - kept on a list, sorted by name. As a special case, to facilitate the - "pushdef" and "popdef" builtins, a symbol can be several times in the - symbol table, one for each definition. Since the name is the same, - all the entries for the symbol will be on the same list, and will - also, because the list is sorted, be adjacent. All the entries for a - name are simply ordered on the list by age. The current definition - will then always be the first found. */ - -#include "m4.h" -#include <limits.h> - -#ifdef DEBUG_SYM -/* When evaluating hash table performance, this profiling code shows - how many collisions were encountered. */ - -struct profile -{ - int entry; /* Number of times lookup_symbol called with this mode. */ - int comparisons; /* Number of times strcmp was called. */ - int misses; /* Number of times strcmp did not return 0. */ - long long bytes; /* Number of bytes compared. */ -}; - -static struct profile profiles[5]; -static symbol_lookup current_mode; - -/* On exit, show a profile of symbol table performance. */ -static void -show_profile (void) -{ - int i; - for (i = 0; i < 5; i++) - { - xfprintf(stderr, "m4: lookup mode %d called %d times, %d compares, " - "%d misses, %lld bytes\n", - i, profiles[i].entry, profiles[i].comparisons, - profiles[i].misses, profiles[i].bytes); - } -} - -/* Like strcmp (S1, S2), but also track profiling statistics. */ -static int -profile_strcmp (const char *s1, const char *s2) -{ - int i = 1; - int result; - while (*s1 && *s1 == *s2) - { - s1++; - s2++; - i++; - } - result = (unsigned char) *s1 - (unsigned char) *s2; - profiles[current_mode].comparisons++; - if (result != 0) - profiles[current_mode].misses++; - profiles[current_mode].bytes += i; - return result; -} - -# define strcmp profile_strcmp -#endif /* DEBUG_SYM */ - - -/*------------------------------------------------------------------. -| Initialise the symbol table, by allocating the necessary storage, | -| and zeroing all the entries. | -`------------------------------------------------------------------*/ - -/* Pointer to symbol table. */ -symbol **symtab; - -void -symtab_init (void) -{ - size_t i; - symbol **s; - - s = symtab = (symbol **) xnmalloc (hash_table_size, sizeof (symbol *)); - - for (i = 0; i < hash_table_size; i++) - s[i] = NULL; - -#ifdef DEBUG_SYM - { - int e = atexit(show_profile); - if (e != 0) - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: unable to show symtab profile")); - } -#endif /* DEBUG_SYM */ -} - -/*--------------------------------------------------. -| Return a hashvalue for a string, from GNU-emacs. | -`--------------------------------------------------*/ - -static size_t M4_GNUC_PURE -hash (const char *s) -{ - size_t val = 0; - - const char *ptr = s; - char ch; - - while ((ch = *ptr++) != '\0') - val = (val << 7) + (val >> (sizeof (val) * CHAR_BIT - 7)) + ch; - return val; -} - -/*--------------------------------------------. -| Free all storage associated with a symbol. | -`--------------------------------------------*/ - -void -free_symbol (symbol *sym) -{ - if (SYMBOL_PENDING_EXPANSIONS (sym) > 0) - SYMBOL_DELETED (sym) = true; - else - { - free (SYMBOL_NAME (sym)); - if (SYMBOL_TYPE (sym) == TOKEN_TEXT) - free (SYMBOL_TEXT (sym)); - free (sym); - } -} - -/*-------------------------------------------------------------------. -| Search in, and manipulation of the symbol table, are all done by | -| lookup_symbol (). It basically hashes NAME to a list in the | -| symbol table, and searches this list for the first occurrence of a | -| symbol with the name. | -| | -| The MODE parameter determines what lookup_symbol () will do. It | -| can either just do a lookup, do a lookup and insert if not | -| present, do an insertion even if the name is already in the list, | -| delete the first occurrence of the name on the list, or delete all | -| occurrences of the name on the list. | -`-------------------------------------------------------------------*/ - -symbol * -lookup_symbol (const char *name, symbol_lookup mode) -{ - size_t h; - int cmp = 1; - symbol *sym, *prev; - symbol **spp; - -#if DEBUG_SYM - current_mode = mode; - profiles[mode].entry++; -#endif /* DEBUG_SYM */ - - h = hash (name); - sym = symtab[h % hash_table_size]; - - for (prev = NULL; sym != NULL; prev = sym, sym = sym->next) - { - cmp = strcmp (SYMBOL_NAME (sym), name); - if (cmp >= 0) - break; - } - - /* If just searching, return status of search. */ - - if (mode == SYMBOL_LOOKUP) - return cmp == 0 ? sym : NULL; - - /* Symbol not found. */ - - spp = (prev != NULL) ? &prev->next : &symtab[h % hash_table_size]; - - switch (mode) - { - - case SYMBOL_INSERT: - - /* If the name was found in the table, check whether it is still in - use by a pending expansion. If so, replace the table element with - a new one; if not, just return the symbol. If not found, just - insert the name, and return the new symbol. */ - - if (cmp == 0 && sym != NULL) - { - if (SYMBOL_PENDING_EXPANSIONS (sym) > 0) - { - symbol *old = sym; - SYMBOL_DELETED (old) = true; - - sym = (symbol *) xmalloc (sizeof (symbol)); - SYMBOL_TYPE (sym) = TOKEN_VOID; - SYMBOL_TRACED (sym) = SYMBOL_TRACED (old); - SYMBOL_NAME (sym) = xstrdup (name); - SYMBOL_SHADOWED (sym) = false; - SYMBOL_MACRO_ARGS (sym) = false; - SYMBOL_BLIND_NO_ARGS (sym) = false; - SYMBOL_DELETED (sym) = false; - SYMBOL_PENDING_EXPANSIONS (sym) = 0; - - SYMBOL_NEXT (sym) = SYMBOL_NEXT (old); - SYMBOL_NEXT (old) = NULL; - (*spp) = sym; - } - return sym; - } - /* Fall through. */ - - case SYMBOL_PUSHDEF: - - /* Insert a name in the symbol table. If there is already a symbol - with the name, insert this in front of it, and mark the old - symbol as "shadowed". */ - - sym = (symbol *) xmalloc (sizeof (symbol)); - SYMBOL_TYPE (sym) = TOKEN_VOID; - SYMBOL_TRACED (sym) = false; - SYMBOL_NAME (sym) = xstrdup (name); - SYMBOL_SHADOWED (sym) = false; - SYMBOL_MACRO_ARGS (sym) = false; - SYMBOL_BLIND_NO_ARGS (sym) = false; - SYMBOL_DELETED (sym) = false; - SYMBOL_PENDING_EXPANSIONS (sym) = 0; - - SYMBOL_NEXT (sym) = *spp; - (*spp) = sym; - - if (mode == SYMBOL_PUSHDEF && cmp == 0) - { - SYMBOL_SHADOWED (SYMBOL_NEXT (sym)) = true; - SYMBOL_TRACED (sym) = SYMBOL_TRACED (SYMBOL_NEXT (sym)); - } - return sym; - - case SYMBOL_DELETE: - case SYMBOL_POPDEF: - - /* Delete occurrences of symbols with NAME. SYMBOL_DELETE kills - all definitions, SYMBOL_POPDEF kills only the first. - However, if the last instance of a symbol is marked for - tracing, reinsert a placeholder in the table. And if the - definition is still in use, let the caller free the memory - after it is done with the symbol. */ - - if (cmp != 0 || sym == NULL) - return NULL; - { - bool traced = false; - if (SYMBOL_NEXT (sym) != NULL - && SYMBOL_SHADOWED (SYMBOL_NEXT (sym)) - && mode == SYMBOL_POPDEF) - { - SYMBOL_SHADOWED (SYMBOL_NEXT (sym)) = false; - SYMBOL_TRACED (SYMBOL_NEXT (sym)) = SYMBOL_TRACED (sym); - } - else - traced = SYMBOL_TRACED (sym); - do - { - *spp = SYMBOL_NEXT (sym); - free_symbol (sym); - sym = *spp; - } - while (*spp != NULL && SYMBOL_SHADOWED (*spp) - && mode == SYMBOL_DELETE); - if (traced) - { - sym = (symbol *) xmalloc (sizeof (symbol)); - SYMBOL_TYPE (sym) = TOKEN_VOID; - SYMBOL_TRACED (sym) = true; - SYMBOL_NAME (sym) = xstrdup (name); - SYMBOL_SHADOWED (sym) = false; - SYMBOL_MACRO_ARGS (sym) = false; - SYMBOL_BLIND_NO_ARGS (sym) = false; - SYMBOL_DELETED (sym) = false; - SYMBOL_PENDING_EXPANSIONS (sym) = 0; - - SYMBOL_NEXT (sym) = *spp; - (*spp) = sym; - } - } - return NULL; - - case SYMBOL_LOOKUP: - default: - M4ERROR ((warning_status, 0, - "INTERNAL ERROR: invalid mode to symbol_lookup ()")); - abort (); - } -} - -/*-----------------------------------------------------------------. -| The following function is used for the cases where we want to do | -| something to each and every symbol in the table. The function | -| hack_all_symbols () traverses the symbol table, and calls a | -| specified function FUNC for each symbol in the table. FUNC is | -| called with a pointer to the symbol, and the DATA argument. | -| | -| FUNC may safely call lookup_symbol with mode SYMBOL_POPDEF or | -| SYMBOL_LOOKUP, but any other mode can break the iteration. | -`-----------------------------------------------------------------*/ - -void -hack_all_symbols (hack_symbol *func, void *data) -{ - size_t h; - symbol *sym; - symbol *next; - - for (h = 0; h < hash_table_size; h++) - { - /* We allow func to call SYMBOL_POPDEF, which can invalidate - sym, so we must grab the next element to traverse before - calling func. */ - for (sym = symtab[h]; sym != NULL; sym = next) - { - next = SYMBOL_NEXT (sym); - func (sym, data); - } - } -} - -#ifdef DEBUG_SYM - -static void symtab_print_list (int i); - -static void M4_GNUC_UNUSED -symtab_debug (void) -{ - token_data td; - const char *text; - symbol *s; - int delete; - static int i; - - while (next_token (&td, NULL) == TOKEN_WORD) - { - text = TOKEN_DATA_TEXT (&td); - if (*text == '_') - { - delete = 1; - text++; - } - else - delete = 0; - - s = lookup_symbol (text, SYMBOL_LOOKUP); - - if (s == NULL) - xprintf ("Name `%s' is unknown\n", text); - - lookup_symbol (text, delete ? SYMBOL_DELETE : SYMBOL_INSERT); - } - symtab_print_list (i++); -} - -static void -symtab_print_list (int i) -{ - symbol *sym; - size_t h; - - xprintf ("Symbol dump #%d:\n", i); - for (h = 0; h < hash_table_size; h++) - for (sym = symtab[h]; sym != NULL; sym = sym->next) - xprintf ("\tname %s, bucket %lu, addr %p, next %p, " - "flags%s%s%s, pending %d\n", - SYMBOL_NAME (sym), - (unsigned long int) h, sym, SYMBOL_NEXT (sym), - SYMBOL_TRACED (sym) ? " traced" : "", - SYMBOL_SHADOWED (sym) ? " shadowed" : "", - SYMBOL_DELETED (sym) ? " deleted" : "", - SYMBOL_PENDING_EXPANSIONS (sym)); -} - -#endif /* DEBUG_SYM */ diff --git a/contrib/tools/bison/m4/ya.make b/contrib/tools/bison/m4/ya.make deleted file mode 100644 index f474cbfb71..0000000000 --- a/contrib/tools/bison/m4/ya.make +++ /dev/null @@ -1,36 +0,0 @@ -PROGRAM() - -LICENSE(GPL-3.0-or-later) - -LICENSE_TEXTS(.yandex_meta/licenses.list.txt) - -NO_RUNTIME() - -NO_COMPILER_WARNINGS() - -IF (MUSL) - CFLAGS( - -DO_BINARY=0 - ) -ENDIF() - -SRCS( - src/builtin.c - src/debug.c - src/eval.c - src/format.c - src/freeze.c - src/input.c - src/m4.c - src/macro.c - src/output.c - src/path.c - src/symtab.c - src/cpp.cpp -) - -PEERDIR( - contrib/tools/bison/gnulib -) - -END() |