summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/freeze.c1000
-rw-r--r--src/m4.h43
-rw-r--r--src/main.c762
-rw-r--r--src/stackovf.c454
4 files changed, 0 insertions, 2259 deletions
diff --git a/src/freeze.c b/src/freeze.c
deleted file mode 100644
index 426e34b5..00000000
--- a/src/freeze.c
+++ /dev/null
@@ -1,1000 +0,0 @@
-/* GNU m4 -- A simple macro processor
- Copyright (C) 1989-1994, 2004-2010, 2013-2014, 2017 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 <config.h>
-
-#include "m4.h"
-
-#include "binary-io.h"
-#include "close-stream.h"
-#include "quotearg.h"
-#include "verify.h"
-#include "xmemdup0.h"
-
-static void produce_mem_dump (FILE *, const char *, size_t);
-static void produce_resyntax_dump (m4 *, FILE *);
-static void produce_syntax_dump (FILE *, m4_syntax_table *, char);
-static void produce_module_dump (m4 *, FILE *, m4_module *);
-static void produce_symbol_dump (m4 *, FILE *, m4_symbol_table *);
-static void *dump_symbol_CB (m4_symbol_table *, const char *,
- size_t, m4_symbol *, void *);
-static void issue_expect_message (m4 *, int);
-static int decode_char (m4 *, FILE *, bool *);
-
-
-/* Dump an ASCII-encoded representation of LEN bytes at MEM to FILE.
- MEM may contain embedded NUL characters. */
-static void
-produce_mem_dump (FILE *file, const char *mem, size_t len)
-{
- char *quoted = quotearg_style_mem (escape_quoting_style, mem, len);
- /* Any errors will be detected by ferror later. */
- fwrite (quoted, strlen (quoted), 1, file);
-}
-
-
-/* Produce the 'R14\nPOSIX_EXTENDED\n' frozen file dump of the current
- default regular expression syntax. Note that it would be a little
- faster to use the encoded syntax in this format as used by re_compile(),
- but the representation of RE_SYNTAX_POSIX_EXTENDED may change in
- future (or alternative) implementations of re_compile, so we use an
- unencoded representation here. */
-
-static void
-produce_resyntax_dump (m4 *context, FILE *file)
-{
- int code = m4_get_regexp_syntax_opt (context);
-
- /* Don't dump default syntax code (`0' for GNU_EMACS). */
- if (code)
- {
- const char *resyntax = m4_regexp_syntax_decode (code);
-
- if (!resyntax)
- m4_error (context, EXIT_FAILURE, 0, NULL,
- _("invalid regexp syntax code `%d'"), code);
-
- /* No need to use produce_mem_dump, since we know all resyntax
- names are already ASCII-encoded. */
- xfprintf (file, "R%zu\n%s\n", strlen (resyntax), resyntax);
- }
-}
-
-static void
-produce_syntax_dump (FILE *file, m4_syntax_table *syntax, char ch)
-{
- char buf[UCHAR_MAX + 1];
- int code = m4_syntax_code (ch);
- int count = 0;
- int i;
-
- for (i = 0; i < UCHAR_MAX + 1; ++i)
- if (m4_has_syntax (syntax, i, code) && code != syntax->orig[i])
- buf[count++] = i;
-
- /* If code falls in M4_SYNTAX_MASKS, then we must treat it
- specially, since it will not be found in syntax->orig. */
- if (count == 1
- && ((code == M4_SYNTAX_RQUOTE && *buf == *DEF_RQUOTE)
- || (code == M4_SYNTAX_ECOMM && *buf == *DEF_ECOMM)))
- return;
-
- if (count || (code & M4_SYNTAX_MASKS))
- {
- xfprintf (file, "S%c%d\n", ch, count);
- produce_mem_dump (file, buf, count);
- fputc ('\n', file);
- }
-}
-
-/* Store the debug mode in textual format. */
-static void
-produce_debugmode_state (FILE *file, int flags)
-{
- /* This code tracks the number of bits in M4_DEBUG_TRACE_VERBOSE. */
- char str[15];
- int offset = 0;
- verify ((1 << (sizeof str - 1)) - 1 == M4_DEBUG_TRACE_VERBOSE);
- if (flags & M4_DEBUG_TRACE_ARGS)
- str[offset++] = 'a';
- if (flags & M4_DEBUG_TRACE_EXPANSION)
- str[offset++] = 'e';
- if (flags & M4_DEBUG_TRACE_QUOTE)
- str[offset++] = 'q';
- if (flags & M4_DEBUG_TRACE_ALL)
- str[offset++] = 't';
- if (flags & M4_DEBUG_TRACE_LINE)
- str[offset++] = 'l';
- if (flags & M4_DEBUG_TRACE_FILE)
- str[offset++] = 'f';
- if (flags & M4_DEBUG_TRACE_PATH)
- str[offset++] = 'p';
- if (flags & M4_DEBUG_TRACE_CALL)
- str[offset++] = 'c';
- if (flags & M4_DEBUG_TRACE_INPUT)
- str[offset++] = 'i';
- if (flags & M4_DEBUG_TRACE_CALLID)
- str[offset++] = 'x';
- if (flags & M4_DEBUG_TRACE_MODULE)
- str[offset++] = 'm';
- if (flags & M4_DEBUG_TRACE_STACK)
- str[offset++] = 's';
- if (flags & M4_DEBUG_TRACE_DEREF)
- str[offset++] = 'd';
- if (flags & M4_DEBUG_TRACE_OUTPUT_DUMPDEF)
- str[offset++] = 'o';
- str[offset] = '\0';
- if (offset)
- xfprintf (file, "d%d\n%s\n", offset, str);
-}
-
-/* The modules must be dumped in the order in which they will be
- reloaded from the frozen file. We store handles in a push
- down stack, so we need to dump them in the reverse order to that. */
-static void
-produce_module_dump (m4 *context, FILE *file, m4_module *module)
-{
- const char *name = m4_get_module_name (module);
- size_t len = strlen (name);
-
- module = m4_module_next (context, module);
- if (module)
- produce_module_dump (context, file, module);
-
- xfprintf (file, "M%zu\n", len);
- produce_mem_dump (file, name, len);
- fputc ('\n', file);
-}
-
-/* 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. */
-static void
-produce_symbol_dump (m4 *context, FILE *file, m4_symbol_table *symtab)
-{
- if (m4_symtab_apply (symtab, true, dump_symbol_CB, file))
- assert (false);
-}
-
-/* Given a stack of symbol values starting with VALUE, destructively
- reverse the stack and return the pointer to what was previously the
- last value in the stack. VALUE may be NULL. The symbol table that
- owns the value stack should not be modified or consulted until this
- is called again to undo the effect. */
-static m4_symbol_value *
-reverse_symbol_value_stack (m4_symbol_value *value)
-{
- m4_symbol_value *result = NULL;
- m4_symbol_value *next;
- while (value)
- {
- next = VALUE_NEXT (value);
- VALUE_NEXT (value) = result;
- result = value;
- value = next;
- }
- return result;
-}
-
-/* Dump the stack of values for SYMBOL, with name SYMBOL_NAME and
- length LEN, located in SYMTAB. USERDATA is interpreted as the
- FILE* to dump to. */
-static void *
-dump_symbol_CB (m4_symbol_table *symtab, const char *symbol_name, size_t len,
- m4_symbol *symbol, void *userdata)
-{
- FILE *file = (FILE *) userdata;
- m4_symbol_value *value;
- m4_symbol_value *last;
-
- last = value = reverse_symbol_value_stack (m4_get_symbol_value (symbol));
- while (value)
- {
- m4_module *module = VALUE_MODULE (value);
- const char *module_name = module ? m4_get_module_name (module) : NULL;
- size_t module_len = module_name ? strlen (module_name) : 0;
-
- if (m4_is_symbol_value_text (value))
- {
- const char *text = m4_get_symbol_value_text (value);
- size_t text_len = m4_get_symbol_value_len (value);
- xfprintf (file, "T%zu,%zu", len, text_len);
- if (module)
- xfprintf (file, ",%zu", module_len);
- fputc ('\n', file);
-
- produce_mem_dump (file, symbol_name, len);
- fputc ('\n', file);
- produce_mem_dump (file, text, text_len);
- fputc ('\n', file);
- if (module)
- {
- produce_mem_dump (file, module_name, module_len);
- fputc ('\n', file);
- }
- }
- else if (m4_is_symbol_value_func (value))
- {
- const m4_builtin *bp = m4_get_symbol_value_builtin (value);
- size_t bp_len;
- if (bp == NULL)
- assert (!"INTERNAL ERROR: builtin not found in builtin table!");
- bp_len = strlen (bp->name);
-
- xfprintf (file, "F%zu,%zu", len, bp_len);
- if (module)
- xfprintf (file, ",%zu", module_len);
- fputc ('\n', file);
-
- produce_mem_dump (file, symbol_name, len);
- fputc ('\n', file);
- produce_mem_dump (file, bp->name, bp_len);
- fputc ('\n', file);
- if (module)
- {
- produce_mem_dump (file, module_name, module_len);
- fputc ('\n', file);
- }
- }
- else if (m4_is_symbol_value_placeholder (value))
- ; /* Nothing to do for a builtin we couldn't reload earlier. */
- else
- assert (!"dump_symbol_CB");
- value = VALUE_NEXT (value);
- }
- reverse_symbol_value_stack (last);
- if (m4_get_symbol_traced (symbol))
- xfprintf (file, "t%zu\n%s\n", len, symbol_name);
- return NULL;
-}
-
-/* Produce a frozen state to the given file NAME. */
-void
-produce_frozen_state (m4 *context, const char *name)
-{
- FILE *file = fopen (name, O_BINARY ? "wb" : "w");
- const char *str;
- const m4_string_pair *pair;
-
- if (!file)
- {
- m4_error (context, 0, errno, NULL, _("cannot open %s"),
- quotearg_style (locale_quoting_style, name));
- return;
- }
-
- /* Write a recognizable header. */
-
- xfprintf (file, "# This is a frozen state file generated by GNU %s %s\n",
- PACKAGE, VERSION);
- fputs ("V2\n", file);
-
- /* Dump quote delimiters. */
- pair = m4_get_syntax_quotes (M4SYNTAX);
- if (STRNEQ (pair->str1, DEF_LQUOTE) || STRNEQ (pair->str2, DEF_RQUOTE))
- {
- xfprintf (file, "Q%zu,%zu\n", pair->len1, pair->len2);
- produce_mem_dump (file, pair->str1, pair->len1);
- fputc ('\n', file);
- produce_mem_dump (file, pair->str2, pair->len2);
- fputc ('\n', file);
- }
-
- /* Dump comment delimiters. */
- pair = m4_get_syntax_comments (M4SYNTAX);
- if (STRNEQ (pair->str1, DEF_BCOMM) || STRNEQ (pair->str2, DEF_ECOMM))
- {
- xfprintf (file, "C%zu,%zu\n", pair->len1, pair->len2);
- produce_mem_dump (file, pair->str1, pair->len1);
- fputc ('\n', file);
- produce_mem_dump (file, pair->str2, pair->len2);
- fputc ('\n', file);
- }
-
- /* Dump regular expression syntax. */
- produce_resyntax_dump (context, file);
-
- /* Dump syntax table. */
- str = "I@WLBOD${}SA(),RE";
- while (*str)
- produce_syntax_dump (file, M4SYNTAX, *str++);
-
- /* Dump debugmode state. */
- produce_debugmode_state (file, m4_get_debug_level_opt (context));
-
- /* Dump all loaded modules. */
- produce_module_dump (context, file, m4_module_next (context, NULL));
-
- /* Dump all symbols. */
- produce_symbol_dump (context, file, M4SYMTAB);
-
- /* Let diversions be issued from output.c module, its cleaner to have this
- piece of code there. */
- m4_freeze_diversions (context, file);
-
- /* All done. */
-
- fputs ("# End of frozen state file\n", file);
- if (close_stream (file) != 0)
- m4_error (context, EXIT_FAILURE, errno, NULL,
- _("unable to create frozen state"));
-}
-
-/* Issue a message saying that some character is an EXPECTED character. */
-static void
-issue_expect_message (m4 *context, int expected)
-{
- if (expected == '\n')
- m4_error (context, EXIT_FAILURE, 0, NULL,
- _("expecting line feed in frozen file"));
- else
- m4_error (context, EXIT_FAILURE, 0, NULL,
- _("expecting character `%c' in frozen file"), expected);
-}
-
-
-/* Reload frozen state. */
-
-/* Read the next character from the IN stream. Various escape
- sequences are converted, and returned. EOF is returned if the end
- of file is reached whilst reading the character, or on an
- unrecognized escape sequence. */
-
-static int
-decode_char (m4 *context, FILE *in, bool *advance_line)
-{
- int ch = getc (in);
- int next;
- int value = 0;
-
- if (*advance_line)
- {
- m4_set_current_line (context, m4_get_current_line (context) + 1);
- *advance_line = false;
- }
-
- while (ch == '\\')
- {
- ch = getc (in);
- switch (ch)
- {
- case 'a': return '\a';
- case 'b': return '\b';
- case 'f': return '\f';
- case 'n': return '\n';
- case 'r': return '\r';
- case 't': return '\t';
- case 'v': return '\v';
- case '\\': return '\\';
-
- case '\n':
- ch = getc (in);
- m4_set_current_line (context, m4_get_current_line (context) + 1);
- continue;
-
- case 'x': case 'X':
- next = getc (in);
- if (next >= '0' && next <= '9')
- ch = (next - '0') * 16;
- else if (next >= 'a' && next <= 'f')
- ch = (next - 'a' + 10) * 16;
- else if (next >= 'A' && next <= 'F')
- ch = (next - 'A' + 10) * 16;
- else
- return EOF;
- next = getc (in);
- if (next >= '0' && next <= '9')
- ch += next - '0';
- else if (next >= 'a' && next <= 'f')
- ch += next - 'a' + 10;
- else if (next >= 'A' && next <= 'F')
- ch += next - 'A' + 10;
- else
- return EOF;
- return ch;
- case '0': case '1': case '2': case '3':
- value = ch - '0';
- ch = getc (in);
- /* fall through */
- case '4': case '5': case '6': case '7':
- if (ch >= '0' && ch <= '7')
- {
- value = value * 8 + ch - '0';
- ch = getc (in);
- }
- else
- {
- ungetc (ch, in);
- return value;
- }
- if (ch >= '0' && ch <= '7')
- value = value * 8 + ch - '0';
- else
- ungetc (ch, in);
- return value;
-
- default:
- return EOF;
- }
- }
-
- if (ch == '\n')
- *advance_line = true;
- return ch;
-}
-
-
-/* Reload state from the given file NAME. We are seeking speed,
- here. */
-
-void
-reload_frozen_state (m4 *context, const char *name)
-{
- FILE *file = NULL;
- char *filepath;
- int version;
- int character;
- int operation;
- char syntax;
- char *string[3];
- size_t allocated[3];
- int number[3] = {0};
- bool advance_line = true;
-
-#define GET_CHARACTER \
- do \
- { \
- if (advance_line) \
- { \
- m4_set_current_line (context, \
- m4_get_current_line (context) + 1); \
- 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 / 10) \
- { \
- n = 10 * n + character - '0'; \
- GET_CHARACTER; \
- } \
- if (((AllowNeg) ? INT_MIN: INT_MAX) < n \
- || isdigit (character)) \
- m4_error (context, EXIT_FAILURE, 0, NULL, \
- _("integer overflow in frozen file")); \
- (Number) = n; \
- } \
- while (0)
-
-#define GET_STRING(File, Buf, BufSize, StrLen, UseChar) \
- do \
- { \
- size_t len = (StrLen); \
- char *p; \
- int ch; \
- if (UseChar) \
- { \
- ungetc (character, File); \
- if (advance_line) \
- { \
- assert (character == '\n'); \
- advance_line = false; \
- } \
- } \
- CHECK_ALLOCATION ((Buf), (BufSize), len); \
- p = (Buf); \
- while (len-- > 0) \
- { \
- ch = (version > 1 \
- ? decode_char (context, File, &advance_line) \
- : getc (File)); \
- if (ch == EOF) \
- m4_error (context, EXIT_FAILURE, 0, NULL, \
- _("premature end of frozen file")); \
- *p++ = ch; \
- } \
- *p = '\0'; \
- GET_CHARACTER; \
- while (version > 1 && character == '\\') \
- { \
- GET_CHARACTER; \
- VALIDATE ('\n'); \
- GET_CHARACTER; \
- } \
- } \
- while (0)
-
-#define VALIDATE(Expected) \
- do \
- { \
- if (character != (Expected)) \
- issue_expect_message (context, (Expected)); \
- } \
- while (0)
-
-#define CHECK_ALLOCATION(Where, Allocated, Needed) \
- do \
- { \
- if ((Needed) + 1 > (Allocated)) \
- { \
- free (Where); \
- (Allocated) = (Needed) + 1; \
- (Where) = xcharalloc (Allocated); \
- } \
- } \
- 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')
-
- filepath = m4_path_search (context, name, NULL);
- file = m4_fopen (context, filepath, "r");
- if (file == NULL)
- m4_error (context, EXIT_FAILURE, errno, NULL, _("cannot open %s"),
- quotearg_style (locale_quoting_style, name));
- m4_set_current_file (context, name);
-
- allocated[0] = 100;
- string[0] = xcharalloc (allocated[0]);
- allocated[1] = 100;
- string[1] = xcharalloc (allocated[1]);
- allocated[2] = 100;
- string[2] = xcharalloc (allocated[2]);
-
- /* Validate format version. Accept both `1' (m4 1.3 and 1.4.x) and
- `2' (m4 2.0). */
- GET_DIRECTIVE;
- VALIDATE ('V');
- GET_CHARACTER;
- GET_NUMBER (version, false);
- switch (version)
- {
- case 2:
- break;
- case 1:
- m4__module_open (context, "m4", NULL);
- if (m4_get_posixly_correct_opt (context))
- m4__module_open (context, "traditional", NULL);
- else
- m4__module_open (context, "gnu", NULL);
- /* Disable { and } categories, since ${11} was not supported in
- 1.4.x. */
- m4_set_syntax (M4SYNTAX, 'O', '+', "{}", 2);
- break;
- default:
- if (version > 2)
- m4_error (context, EXIT_MISMATCH, 0, NULL,
- _("frozen file version %d greater than max supported of 2"),
- version);
- else
- m4_error (context, EXIT_FAILURE, 0, NULL,
- _("ill-formed frozen file, version directive expected"));
- }
- VALIDATE ('\n');
-
- GET_DIRECTIVE;
- while (character != EOF)
- {
- switch (character)
- {
- default:
- m4_error (context, EXIT_FAILURE, 0, NULL,
- _("ill-formed frozen file, unknown directive %c"),
- character);
-
- case 'd':
- /* Set debugmode flags. */
- if (version < 2)
- {
- /* 'd' operator is not supported in format version 1. */
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, version 2 directive `%c' encountered"), 'd');
- }
-
- GET_CHARACTER;
- GET_NUMBER (number[0], false);
- VALIDATE ('\n');
- GET_STRING (file, string[0], allocated[0], number[0], false);
- VALIDATE ('\n');
-
- if (m4_debug_decode (context, string[0], number[0]) < 0)
- m4_error (context, EXIT_FAILURE, 0, NULL,
- _("unknown debug mode %s"),
- quotearg_style_mem (locale_quoting_style, string[0],
- number[0]));
- break;
-
- case 'F':
- GET_CHARACTER;
-
- /* Get string lengths. */
-
- GET_NUMBER (number[0], false);
- VALIDATE (',');
- GET_CHARACTER;
- GET_NUMBER (number[1], false);
-
- if (character == ',')
- {
- if (version > 1)
- {
- /* 'F' operator accepts an optional third argument for
- format versions 2 or later. */
- GET_CHARACTER;
- GET_NUMBER (number[2], false);
- }
- else
- /* 3 argument 'F' operations are invalid for format
- version 1. */
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, version 2 directive `%c' encountered"), 'F');
- }
- else
- {
- number[2] = 0;
- }
-
- VALIDATE ('\n');
-
-
- /* Get string contents. */
-
- GET_STRING (file, string[0], allocated[0], number[0], false);
- if (version > 1)
- {
- VALIDATE ('\n');
- GET_CHARACTER;
- }
- GET_STRING (file, string[1], allocated[1], number[1], true);
- if (version > 1 && number[2])
- {
- VALIDATE ('\n');
- GET_CHARACTER;
- }
- GET_STRING (file, string[2], allocated[2], number[2], true);
- VALIDATE ('\n');
-
- /* Enter a macro having a builtin function as a definition. */
- {
- m4_module *module = NULL;
- m4_symbol_value *token;
-
- // Builtins cannot contain a NUL byte.
- if (strlen (string[1]) < number[1])
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, invalid builtin %s encountered"),
- quotearg_style_mem (locale_quoting_style, string[1],
- number[1]));
- if (number[2] > 0)
- {
- if (strlen (string[2]) < number[2])
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, invalid module %s encountered"),
- quotearg_style_mem (locale_quoting_style,
- string[2], number[2]));
- module = m4__module_find (context, string[2]);
- }
- token = m4_builtin_find_by_name (context, module, string[1]);
-
- if (token == NULL)
- {
- token = (m4_symbol_value *) xzalloc (sizeof *token);
- m4_set_symbol_value_placeholder (token, xstrdup (string[1]));
- VALUE_MODULE (token) = module;
- VALUE_MIN_ARGS (token) = 0;
- VALUE_MAX_ARGS (token) = -1;
- }
- m4_symbol_pushdef (M4SYMTAB, string[0], number[0], token);
- }
- break;
-
- case 'M':
-
- /* Load a module, but *without* perturbing the symbol table.
- Note that any expansion from loading the module which would
- have been seen when loading it originally is discarded
- when loading it from a frozen file. */
-
- if (version < 2)
- {
- /* 'M' operator is not supported in format version 1. */
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, version 2 directive `%c' encountered"), 'M');
- }
-
- GET_CHARACTER;
- GET_NUMBER (number[0], false);
- VALIDATE ('\n');
- GET_STRING (file, string[0], allocated[0], number[0], false);
- VALIDATE ('\n');
-
- if (strlen (string[0]) < number[0])
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, invalid module %s encountered"),
- quotearg_style_mem (locale_quoting_style,
- string[0], number[0]));
- m4__module_open (context, string[0], NULL);
-
- break;
-
- case 'R':
-
- if (version < 2)
- {
- /* 'R' operator is not supported in format version 1. */
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, version 2 directive `%c' encountered"), 'R');
- }
-
- GET_CHARACTER;
- GET_NUMBER (number[0], false);
- VALIDATE ('\n');
- GET_STRING (file, string[0], allocated[0], number[0], false);
- VALIDATE ('\n');
-
- m4_set_regexp_syntax_opt (context,
- m4_regexp_syntax_encode (string[0]));
- if (m4_get_regexp_syntax_opt (context) < 0
- || strlen (string[0]) < number[0])
- {
- m4_error (context, EXIT_FAILURE, 0, NULL,
- _("bad syntax-spec %s"),
- quotearg_style_mem (locale_quoting_style, string[0],
- number[0]));
- }
-
- break;
-
- case 'S':
-
- if (version < 2)
- {
- /* 'S' operator is not supported in format version 1. */
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, version 2 directive `%c' encountered"), 'S');
- }
-
- GET_CHARACTER;
- syntax = character;
- GET_CHARACTER;
- GET_NUMBER (number[0], false);
- VALIDATE ('\n');
- GET_STRING (file, string[0], allocated[0], number[0], false);
-
- /* Syntax under M4_SYNTAX_MASKS is handled specially; all
- other characters are additive. */
- if ((m4_set_syntax (M4SYNTAX, syntax,
- (m4_syntax_code (syntax) & M4_SYNTAX_MASKS
- ? '=' : '+'), string[0], number[0]) < 0)
- && (syntax != '\0'))
- {
- m4_error (context, 0, 0, NULL,
- _("undefined syntax code %c"), syntax);
- }
- break;
-
- case 't':
- /* Trace a macro name. */
- if (version < 2)
- {
- /* 't' operator is not supported in format version 1. */
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, version 2 directive `%c' encountered"), 't');
- }
-
- GET_CHARACTER;
- GET_NUMBER (number[0], false);
- VALIDATE ('\n');
- GET_STRING (file, string[0], allocated[0], number[0], false);
- VALIDATE ('\n');
-
- m4_set_symbol_name_traced (M4SYMTAB, string[0], number[0], true);
-
- break;
-
- case 'C':
- case 'D':
- case 'Q':
- operation = character;
- GET_CHARACTER;
-
- /* Get string lengths. */
-
- if (operation == 'D' && character == '-')
- {
- /* Accept a negative diversion number. */
- 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');
-
- /* Get string contents. */
- if (operation != 'D')
- {
- GET_STRING (file, string[0], allocated[0], number[0], false);
- if (version > 1)
- {
- VALIDATE ('\n');
- GET_CHARACTER;
- }
- }
- else
- GET_CHARACTER;
- GET_STRING (file, string[1], allocated[1], number[1], true);
- VALIDATE ('\n');
-
- /* Act according to operation letter. */
-
- switch (operation)
- {
- case 'C':
-
- /* Change comment strings. */
-
- m4_set_comment (M4SYNTAX, string[0], number[0], string[1],
- number[1]);
- break;
-
- case 'D':
-
- /* Select a diversion and add a string to it. */
-
- m4_make_diversion (context, number[0]);
- if (number[1] > 0)
- m4_output_text (context, string[1], number[1]);
- break;
-
- case 'Q':
-
- /* Change quote strings. */
-
- m4_set_quotes (M4SYNTAX, string[0], number[0], string[1],
- number[1]);
- break;
-
- default:
-
- /* Cannot happen. */
-
- break;
- }
- break;
-
- case 'T':
- GET_CHARACTER;
-
- /* Get string lengths. */
-
- GET_NUMBER (number[0], false);
- VALIDATE (',');
- GET_CHARACTER;
- GET_NUMBER (number[1], false);
-
- if (character == ',')
- {
- if (version > 1)
- {
- /* 'T' operator accepts an optional third argument for
- format versions 2 or later. */
- GET_CHARACTER;
- GET_NUMBER (number[2], false);
- }
- else
- {
- /* 3 argument 'T' operations are invalid for format
- version 1. */
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, version 2 directive `%c' encountered"), 'T');
- }
- }
- else
- number[2] = 0;
-
- VALIDATE ('\n');
-
- /* Get string contents. */
- GET_STRING (file, string[0], allocated[0], number[0], false);
- if (version > 1)
- {
- VALIDATE ('\n');
- GET_CHARACTER;
- }
- GET_STRING (file, string[1], allocated[1], number[1], true);
- if (version > 1 && number[2])
- {
- VALIDATE ('\n');
- GET_CHARACTER;
- }
- GET_STRING (file, string[2], allocated[2], number[2], true);
- VALIDATE ('\n');
-
- /* Enter a macro having an expansion text as a definition. */
- {
- m4_symbol_value *token;
- m4_module *module = NULL;
-
- token = (m4_symbol_value *) xzalloc (sizeof *token);
- if (number[2] > 0)
- {
- if (strlen (string[2]) < number[2])
- m4_error (context, EXIT_FAILURE, 0, NULL, _("\
-ill-formed frozen file, invalid module %s encountered"),
- quotearg_style_mem (locale_quoting_style,
- string[2], number[2]));
- module = m4__module_find (context, string[2]);
- }
-
- m4_set_symbol_value_text (token, xmemdup0 (string[1], number[1]),
- number[1], 0);
- VALUE_MODULE (token) = module;
- VALUE_MAX_ARGS (token) = -1;
-
- m4_symbol_pushdef (M4SYMTAB, string[0], number[0], token);
- }
- break;
-
- }
- GET_DIRECTIVE;
- }
-
- free (string[0]);
- free (string[1]);
- free (string[2]);
- if (close_stream (file) != 0)
- m4_error (context, EXIT_FAILURE, errno, NULL,
- _("unable to read frozen state"));
- m4_set_current_file (context, NULL);
- m4_set_current_line (context, 0);
-
-#undef GET_STRING
-#undef GET_CHARACTER
-#undef GET_NUMBER
-#undef VALIDATE
-#undef CHECK_ALLOCATION
-#undef GET_DIRECTIVE
-}
diff --git a/src/m4.h b/src/m4.h
deleted file mode 100644
index acd8fa9b..00000000
--- a/src/m4.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* GNU m4 -- A simple macro processor
- Copyright (C) 1989-1994, 2006-2007, 2010, 2013-2014, 2017 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/>.
-*/
-
-#ifndef M4_H
-#define M4_H
-
-#include <signal.h>
-
-#include "m4private.h"
-
-#include "gettext.h"
-
-/* Error handling. */
-#ifdef USE_STACKOVF
-void setup_stackovf_trap (char *const *, char *const *,
- void (*handler) (void));
-void stackovf_exit (void);
-#endif
-
-
-/* File: freeze.c --- frozen state files. */
-
-void produce_frozen_state (m4 *context, const char *);
-void reload_frozen_state (m4 *context, const char *);
-
-#endif /* M4_H */
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index 4b897e34..00000000
--- a/src/main.c
+++ /dev/null
@@ -1,762 +0,0 @@
-/* GNU m4 -- A simple macro processor
-
- Copyright (C) 1989-1994, 1999-2000, 2003-2010, 2013-2014, 2017 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 <config.h>
-
-#include <locale.h>
-
-#include "m4.h"
-
-#include "closein.h"
-#include "configmake.h"
-#include "getopt.h"
-#include "propername.h"
-#include "quotearg.h"
-#include "version-etc.h"
-#include "xstrtol.h"
-
-#define AUTHORS \
- proper_name_utf8 ("Rene' Seindal", "Ren\xc3\xa9 Seindal"), \
- proper_name ("Gary V. Vaughan"), \
- proper_name ("Eric Blake")
-
-typedef struct deferred
-{
- struct deferred *next;
- int code; /* deferred optchar */
- const char *value;
-} deferred;
-
-
-/* Error handling functions. */
-
-#ifdef USE_STACKOVF
-
-/* Tell user stack overflowed and abort. */
-static void
-stackovf_handler (void)
-{
- /* FIXME - calling gettext and error inside a signal handler is dangerous,
- since these functions invoke functions that are not signal-safe. We
- are sort of justified by the fact that we will exit and never return,
- but this should really be fixed. */
- error (EXIT_FAILURE, 0, _("stack overflow (infinite define recursion?)"));
-}
-
-#endif /* USE_STACKOVF */
-
-
-
-/* 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"),
- m4_get_program_name ());
- else
- {
- xprintf (_("Usage: %s [OPTION]... [FILE]...\n"), m4_get_program_name ());
- fputs (_("\
-Process macros in FILEs.\n\
-If no FILE or if FILE is `-', standard input is read. If no FILE, and both\n\
-standard input and standard error are terminals, -i is implied.\n\
-"), stdout);
- puts ("");
- fputs (_("\
-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);
- fputs (_("\
- -b, --batch buffer output, process interrupts\n\
- -c, --discard-comments do not copy comments to the output\n\
- -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\
- -r, --regexp-syntax[=SPEC] set default regexp syntax to SPEC [GNU_M4]\n\
- --safer disable potentially unsafe builtins\n\
- -W, --warnings enable all warnings\n\
-"), stdout);
- puts ("");
- fputs (_("\
-SPEC is any one of:\n\
- AWK, BASIC, BSD_M4, ED, EMACS, EXTENDED, GNU_AWK, GNU_EGREP, GNU_M4,\n\
- GREP, POSIX_AWK, POSIX_EGREP, MINIMAL, MINIMAL_BASIC, SED.\n\
-"), stdout);
- puts ("");
- fputs (_("\
-Preprocessor features:\n\
- -B, --prepend-include=DIR add DIR to include path before `.'\n\
- -D, --define=NAME[=VALUE] define NAME as having VALUE, or empty\n\
- --import-environment import all environment variables as macros\n\
- -I, --include=DIR add DIR to include path after `.'\n\
-"), stdout);
- fputs (_("\
- --popdef=NAME popdef NAME\n\
- -p, --pushdef=NAME[=VALUE] pushdef NAME as having VALUE, or empty\n\
- -s, --synclines short for --syncoutput=1\n\
- --syncoutput[=STATE] set generation of `#line NUM \"FILE\"' lines\n\
- to STATE (0=off, 1=on, default 0)\n\
- -U, --undefine=NAME undefine NAME\n\
-"), stdout);
- puts ("");
- fputs (_("\
-Limits control:\n\
- -g, --gnu override -G to re-enable GNU extensions\n\
- -G, --traditional, --posix suppress all GNU extensions\n\
- -L, --nesting-limit=NUMBER change artificial nesting limit [1024]\n\
-"), stdout);
- 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);
- puts ("");
- fputs (_("\
-Debugging:\n\
- -d, --debug[=[-|+]FLAGS], --debugmode[=[-|+]FLAGS]\n\
- set debug level (no FLAGS implies `+adeq')\n\
- --debugfile[=FILE] redirect debug and trace output to FILE\n\
- (default stderr, discard if empty string)\n\
- -l, --debuglen=NUM restrict macro tracing size\n\
- -t, --trace=NAME, --traceon=NAME\n\
- trace NAME when it is defined\n\
- --traceoff=NAME no longer trace NAME\n\
-"), stdout);
- puts ("");
- fputs (_("\
-FLAGS is any of:\n\
- a show actual arguments in trace\n\
- c show collection line in trace\n\
- d warn when dereferencing undefined macros (default on unless -E)\n\
- e show expansion in trace\n\
- f include current input file name in trace and debug\n\
- i show changes in input files in debug\n\
- l include current input line number in trace and debug\n\
-"), stdout);
- fputs (_("\
- m show module information in trace, debug, and dumpdef\n\
- o output dumpdef to stderr rather than debug file\n\
- p show results of path searches in debug\n\
- q quote values in dumpdef and trace, useful with a or e\n\
- s show full stack of pushdef values in dumpdef\n\
- t trace all macro calls, regardless of per-macro traceon state\n\
- x include unique macro call id in trace, useful with c\n\
- V shorthand for all of the above flags\n\
-"), stdout);
- puts ("");
- fputs (_("\
-If defined, the environment variable `M4PATH' is a colon-separated list\n\
-of directories included after any specified by `-I' or `-B'. The\n\
-environment variable `POSIXLY_CORRECT' implies -G -Q; otherwise GNU\n\
-extensions are enabled by default.\n\
-"), stdout);
- puts ("");
- fputs (_("\
-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);
-}
-
-/* For long options that have no equivalent short option, use a
- non-character as a pseudo short option, starting with CHAR_MAX + 1. */
-enum
-{
- ARGLENGTH_OPTION = CHAR_MAX + 1, /* not quite -l, because of message */
- DEBUGFILE_OPTION, /* no short opt */
- ERROR_OUTPUT_OPTION, /* not quite -o, because of message */
- HASHSIZE_OPTION, /* not quite -H, because of message */
- IMPORT_ENVIRONMENT_OPTION, /* no short opt */
- POPDEF_OPTION, /* no short opt */
- PREPEND_INCLUDE_OPTION, /* not quite -B, because of message */
- SAFER_OPTION, /* -S still has old no-op semantics */
- SYNCOUTPUT_OPTION, /* not quite -s, because of opt arg */
- TRACEOFF_OPTION, /* no short opt */
- WORD_REGEXP_OPTION, /* deprecated, used to be -W */
-
- HELP_OPTION, /* no short opt */
- VERSION_OPTION /* no short opt */
-};
-
-/* Decode options and launch execution. */
-static const struct option long_options[] =
-{
- {"batch", no_argument, NULL, 'b'},
- {"debug", optional_argument, NULL, 'd'},
- {"debuglen", required_argument, NULL, 'l'},
- {"debugmode", optional_argument, NULL, 'd'},
- {"define", required_argument, NULL, 'D'},
- {"discard-comments", no_argument, NULL, 'c'},
- {"fatal-warnings", no_argument, NULL, 'E'},
- {"freeze-state", required_argument, NULL, 'F'},
- {"gnu", no_argument, NULL, 'g'},
- {"include", required_argument, NULL, 'I'},
- {"interactive", no_argument, NULL, 'i'},
- {"nesting-limit", required_argument, NULL, 'L'},
- {"posix", no_argument, NULL, 'G'},
- {"prefix-builtins", no_argument, NULL, 'P'},
- {"pushdef", required_argument, NULL, 'p'},
- {"quiet", no_argument, NULL, 'Q'},
- {"regexp-syntax", optional_argument, NULL, 'r'},
- {"reload-state", required_argument, NULL, 'R'},
- {"silent", no_argument, NULL, 'Q'},
- {"synclines", no_argument, NULL, 's'},
- {"trace", required_argument, NULL, 't'},
- {"traceon", required_argument, NULL, 't'},
- {"traditional", no_argument, NULL, 'G'},
- {"undefine", required_argument, NULL, 'U'},
- {"warnings", no_argument, NULL, 'W'},
-
- {"arglength", required_argument, NULL, ARGLENGTH_OPTION},
- {"debugfile", optional_argument, NULL, DEBUGFILE_OPTION},
- {"hashsize", required_argument, NULL, HASHSIZE_OPTION},
- {"error-output", required_argument, NULL, ERROR_OUTPUT_OPTION},
- {"import-environment", no_argument, NULL, IMPORT_ENVIRONMENT_OPTION},
- {"popdef", required_argument, NULL, POPDEF_OPTION},
- {"prepend-include", required_argument, NULL, PREPEND_INCLUDE_OPTION},
- {"safer", no_argument, NULL, SAFER_OPTION},
- {"syncoutput", optional_argument, NULL, SYNCOUTPUT_OPTION},
- {"traceoff", required_argument, NULL, TRACEOFF_OPTION},
- {"word-regexp", required_argument, NULL, WORD_REGEXP_OPTION},
-
- {"help", no_argument, NULL, HELP_OPTION},
- {"version", no_argument, NULL, VERSION_OPTION},
-
- { NULL, 0, NULL, 0 },
-};
-
-/* 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. */
-#define OPTSTRING "-B:D:EF:GH:I:L:PQR:S:T:U:Wbcd::egil:o:p:r::st:"
-
-/* For determining whether to be interactive. */
-enum interactive_choice
-{
- INTERACTIVE_UNKNOWN, /* Still processing arguments, no -b or -i yet */
- INTERACTIVE_YES, /* -i specified last */
- INTERACTIVE_NO /* -b specified last */
-};
-
-/* Convert OPT to size_t, reporting an error using long option index
- OI or short option character OPTCHAR if it does not fit. */
-static size_t
-size_opt (char const *opt, int oi, int optchar)
-{
- unsigned long int size;
- strtol_error status = xstrtoul (opt, NULL, 10, &size, "kKmMgGtTPEZY0");
- if (SIZE_MAX < size && status == LONGINT_OK)
- status = LONGINT_OVERFLOW;
- if (status != LONGINT_OK)
- xstrtol_fatal (status, oi, optchar, long_options, opt);
- return size;
-}
-
-/* Process a command line file NAME. */
-static bool
-process_file (m4 *context, const char *name)
-{
- bool new_input = true;
-
- if (STREQ (name, "-"))
- /* TRANSLATORS: This is a short name for `standard input', used
- when a command line file was given as `-'. */
- m4_push_file (context, stdin, _("stdin"), false);
- else
- new_input = m4_load_filename (context, NULL, name, NULL, false);
-
- if (new_input)
- m4_macro_expand_input (context);
-
- return new_input;
-}
-
-
-/* Main entry point. Parse arguments, load modules, then parse input. */
-int
-main (int argc, char *const *argv, char *const *envp)
-{
- deferred *head = NULL; /* head of deferred argument list */
- deferred *tail = NULL;
- deferred *defn;
- size_t size; /* for parsing numeric option arguments */
-
- bool import_environment = false; /* true to import environment */
- bool seen_file = false;
- const char *debugfile = NULL;
- const char *frozen_file_to_read = NULL;
- const char *frozen_file_to_write = NULL;
- enum interactive_choice interactive = INTERACTIVE_UNKNOWN;
-
- m4 *context;
-
- int exit_status;
-
- /* Initialize gnulib error module. */
- m4_set_program_name (argv[0]);
- atexit (close_stdin);
-
- setlocale (LC_ALL, "");
-#ifdef ENABLE_NLS
- textdomain (PACKAGE);
-#endif
-
- context = m4_create ();
-
-#ifdef USE_STACKOVF
- setup_stackovf_trap (argv, envp, stackovf_handler);
-#endif
-
- if (getenv ("POSIXLY_CORRECT"))
- {
- m4_set_posixly_correct_opt (context, true);
- m4_set_suppress_warnings_opt (context, true);
- }
- set_quoting_style (NULL, escape_quoting_style);
- set_char_quoting (NULL, ':', 1);
-
- /* First, we decode the arguments, to size up tables and stuff.
- Avoid lasting side effects; for example 'm4 --debugfile=oops
- --help' must not create the file `oops'. */
- while (1)
- {
- int oi = -1;
- int optchar = getopt_long (argc, (char **) argv, OPTSTRING,
- long_options, &oi);
- if (optchar == -1)
- break;
-
- switch (optchar)
- {
- default:
- usage (EXIT_FAILURE);
-
- case 'H':
- case HASHSIZE_OPTION:
- /* -H was supported in 1.4.x, but is a no-op now. FIXME -
- remove support for -H after 2.0. */
- error (0, 0, _("warning: `%s' is deprecated"),
- optchar == 'H' ? "-H" : "--hashsize");
- break;
-
- 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: `-%c' is deprecated"),
- optchar);
- break;
-
- case WORD_REGEXP_OPTION:
- /* Supported in 1.4.x as -W, but no longer present. */
- error (0, 0, _("warning: `%s' is deprecated"), "--word-regexp");
- break;
-
- case 's':
- optchar = SYNCOUTPUT_OPTION;
- optarg = "1";
- /* fall through */
- case 'D':
- case 'U':
- case 'p':
- case 'r':
- case 't':
- case POPDEF_OPTION:
- case SYNCOUTPUT_OPTION:
- case TRACEOFF_OPTION:
- defer:
- /* Arguments that cannot be handled until later are accumulated. */
-
- defn = (deferred *) xmalloc (sizeof *defn);
- defn->code = optchar;
- defn->value = optarg;
- defn->next = NULL;
-
- if (head == NULL)
- head = defn;
- else
- tail->next = defn;
- tail = defn;
- break;
-
- case '\1':
- seen_file = true;
- goto defer;
-
- case 'B':
- /* In 1.4.x, -B<num> was a no-op option for compatibility with
- Solaris m4. Warn if optarg is all numeric. FIXME -
- silence this warning after 2.0. */
- if (isdigit (to_uchar (*optarg)))
- {
- char *end;
- errno = 0;
- strtol (optarg, &end, 10);
- if (*end == '\0' && errno == 0)
- error (0, 0, _("warning: recommend using `-B ./%s' instead"),
- optarg);
- }
- /* fall through */
- case PREPEND_INCLUDE_OPTION:
- m4_add_include_directory (context, optarg, true);
- break;
-
- case 'E':
- m4_debug_decode (context, "-d", SIZE_MAX);
- if (m4_get_fatal_warnings_opt (context))
- m4_set_warnings_exit_opt (context, true);
- else
- m4_set_fatal_warnings_opt (context, true);
- break;
-
- case 'F':
- frozen_file_to_write = optarg;
- break;
-
- case 'G':
- m4_set_posixly_correct_opt (context, true);
- break;
-
- case 'I':
- m4_add_include_directory (context, optarg, false);
- break;
-
- case 'L':
- size = size_opt (optarg, oi, optchar);
- if (!size)
- size = SIZE_MAX;
- m4_set_nesting_limit_opt (context, size);
- break;
-
- case 'P':
- m4_set_prefix_builtins_opt (context, true);
- break;
-
- case 'Q':
- m4_set_suppress_warnings_opt (context, true);
- break;
-
- case 'R':
- frozen_file_to_read = optarg;
- break;
-
- case 'W':
- /* FIXME - should W take an optional argument, to allow -Wall,
- -Wnone, -Werror, -Wcategory, -Wno-category? If so, then have
- -W == -Wall. */
- m4_set_suppress_warnings_opt (context, false);
- break;
-
- case 'b':
- interactive = INTERACTIVE_NO;
- break;
-
- case 'c':
- m4_set_discard_comments_opt (context, true);
- break;
-
- case 'd':
- /* Staggered handling of 'd', since -dm is useful prior to
- first file and prior to reloading, but other -d must also
- have effect between files. */
- if (seen_file || frozen_file_to_read)
- goto defer;
- if (m4_debug_decode (context, optarg, SIZE_MAX) < 0)
- error (0, 0, _("bad debug flags: %s"),
- quotearg_style (locale_quoting_style, optarg));
- break;
-
- case 'e':
- error (0, 0, _("warning: `%s' is deprecated, use `%s' instead"),
- "-e", "-i");
- /* fall through */
- case 'i':
- interactive = INTERACTIVE_YES;
- break;
-
- case 'g':
- m4_set_posixly_correct_opt (context, false);
- break;
-
- case ARGLENGTH_OPTION:
- error (0, 0, _("warning: `%s' is deprecated, use `%s' instead"),
- "--arglength", "--debuglen");
- /* fall through */
- case 'l':
- size = size_opt (optarg, oi, optchar);
- if (!size)
- size = SIZE_MAX;
- m4_set_max_debug_arg_length_opt (context, size);
- break;
-
- case DEBUGFILE_OPTION:
- /* Staggered handling of '--debugfile', since it is useful
- prior to first file and prior to reloading, but other
- uses must also have effect between files. */
- if (seen_file || frozen_file_to_read)
- goto defer;
- debugfile = optarg;
- break;
-
- case 'o':
- case ERROR_OUTPUT_OPTION:
- /* FIXME: -o is inconsistent with other tools' use of
- -o/--output for creating an output file instead of using
- stdout, and --error-output is misnamed since it does not
- affect error messages to stderr. Change the meaning of -o
- after 2.1. */
- error (0, 0, _("warning: `%s' is deprecated, use `%s' instead"),
- optchar == 'o' ? "-o" : "--error-output", "--debugfile");
- /* Don't call m4_debug_set_output here, as it has side effects. */
- debugfile = optarg;
- break;
-
- case IMPORT_ENVIRONMENT_OPTION:
- import_environment = true;
- break;
-
- case SAFER_OPTION:
- m4_set_safer_opt (context, true);
- break;
-
- case VERSION_OPTION:
- version_etc (stdout, PACKAGE, PACKAGE_NAME, VERSION, AUTHORS, NULL);
- exit (EXIT_SUCCESS);
- break;
-
- case HELP_OPTION:
- usage (EXIT_SUCCESS);
- break;
- }
- }
-
- /* Do the basic initializations. */
- if (debugfile && !m4_debug_set_output (context, NULL, debugfile))
- m4_error (context, 0, errno, NULL, _("cannot set debug file %s"),
- quotearg_style (locale_quoting_style, debugfile));
- m4_input_init (context);
- m4_output_init (context);
-
- if (frozen_file_to_read)
- reload_frozen_state (context, frozen_file_to_read);
- else
- {
- m4_module_load (context, "m4", NULL);
- if (m4_get_posixly_correct_opt (context))
- m4_module_load (context, "traditional", NULL);
- else
- m4_module_load (context, "gnu", NULL);
- }
-
- /* Import environment variables as macros. The definition are
- prepended to the macro definition list, so -U can override
- environment variables. */
-
- if (import_environment)
- {
- char *const *env;
-
- for (env = envp; *env != NULL; env++)
- {
- defn = (deferred *) xmalloc (sizeof *defn);
- defn->code = 'D';
- defn->value = *env;
- defn->next = head;
- head = defn;
- }
- }
-
- /* Handle deferred command line macro definitions. Must come after
- initialization of the symbol table. */
- defn = head;
- while (defn != NULL)
- {
- deferred *next;
- const char *arg = defn->value;
-
- switch (defn->code)
- {
- case 'D':
- case 'p':
- {
- m4_symbol_value *value = m4_symbol_value_create ();
-
- const char *str = strchr (arg, '=');
- size_t len = str ? str - arg : strlen (arg);
-
- m4_set_symbol_value_text (value, xstrdup (str ? str + 1 : ""),
- str ? strlen (str + 1) : 0, 0);
-
- if (defn->code == 'D')
- m4_symbol_define (M4SYMTAB, arg, len, value);
- else
- m4_symbol_pushdef (M4SYMTAB, arg, len, value);
- }
- break;
-
- case 'U':
- m4_symbol_delete (M4SYMTAB, arg, strlen (arg));
- break;
-
- case 'd':
- if (m4_debug_decode (context, arg, SIZE_MAX) < 0)
- error (0, 0, _("bad debug flags: %s"),
- quotearg_style (locale_quoting_style, arg));
- break;
-
- case 'r':
- m4_set_regexp_syntax_opt (context, m4_regexp_syntax_encode (arg));
- if (m4_get_regexp_syntax_opt (context) < 0)
- m4_error (context, EXIT_FAILURE, 0, NULL,
- _("bad syntax-spec: %s"),
- quotearg_style (locale_quoting_style, arg));
- break;
-
- case 't':
- m4_set_symbol_name_traced (M4SYMTAB, arg, strlen (arg), true);
- break;
-
- case '\1':
- if (process_file (context, arg))
- seen_file = true;
- break;
-
- case DEBUGFILE_OPTION:
- if (!m4_debug_set_output (context, NULL, arg))
- m4_error (context, 0, errno, NULL, _("cannot set debug file %s"),
- quotearg_style (locale_quoting_style,
- arg ? arg : _("stderr")));
- break;
-
- case POPDEF_OPTION:
- {
- size_t len = strlen (arg);
- if (m4_symbol_lookup (M4SYMTAB, arg, len))
- m4_symbol_popdef (M4SYMTAB, arg, len);
- }
- break;
-
- case SYNCOUTPUT_OPTION:
- {
- bool previous = m4_get_syncoutput_opt (context);
- m4_call_info info = {0};
- info.name = "--syncoutput";
- info.name_len = strlen (info.name);
- m4_set_syncoutput_opt (context,
- m4_parse_truth_arg (context, &info, arg,
- SIZE_MAX, previous));
- }
- break;
-
- case TRACEOFF_OPTION:
- m4_set_symbol_name_traced (M4SYMTAB, arg, strlen (arg), false);
- break;
-
- default:
- assert (!"INTERNAL ERROR: bad code in deferred arguments");
- abort ();
- }
-
- next = defn->next;
- free (defn);
- defn = next;
- }
-
-
- /* Interactive if specified, or if no input files and stdin and
- stderr are terminals, to match sh behavior. Interactive mode
- means unbuffered output, and interrupts ignored. */
-
- m4_set_interactive_opt (context, (interactive == INTERACTIVE_YES
- || (interactive == INTERACTIVE_UNKNOWN
- && optind == argc && !seen_file
- && isatty (STDIN_FILENO)
- && isatty (STDERR_FILENO))));
- if (m4_get_interactive_opt (context))
- {
- signal (SIGINT, SIG_IGN);
- setbuf (stdout, NULL);
- }
- else
- signal (SIGPIPE, SIG_DFL);
-
-
- /* Handle remaining input files. Each file is pushed on the input,
- and the input read. */
-
- if (optind == argc && !seen_file)
- process_file (context, "-");
- else
- for (; optind < argc; optind++)
- process_file (context, argv[optind]);
-
- /* Now handle wrapup text.
- FIXME - when -F is in effect, should wrapped text be frozen? */
- while (m4_pop_wrapup (context))
- m4_macro_expand_input (context);
-
- if (frozen_file_to_write)
- produce_frozen_state (context, frozen_file_to_write);
- else
- {
- m4_make_diversion (context, 0);
- m4_undivert_all (context);
- }
-
- /* The remaining cleanup functions systematically free all of the
- memory we still have pointers to. By definition, if there is
- anything left when we're done: it was caused by a memory leak.
- Strictly, we don't need to do this, but it makes leak detection
- a whole lot easier! */
-
- m4_output_exit ();
- m4_input_exit ();
-
- /* 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. */
- m4_debug_set_output (context, NULL, NULL);
-
- exit_status = m4_get_exit_status (context);
- m4_delete (context);
-
- m4_hash_exit ();
- quotearg_free ();
-
-#ifdef USE_STACKOVF
- stackovf_exit ();
-#endif
-
- exit (exit_status);
-}
diff --git a/src/stackovf.c b/src/stackovf.c
deleted file mode 100644
index 3d0468ab..00000000
--- a/src/stackovf.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* Detect stack overflow (when getrlimit and sigaction or sigvec are available)
- Copyright (C) 1993-1994, 2006-2007, 2010, 2013-2014, 2017 Free
- Software Foundation, Inc.
- Jim Avera <jima@netcom.com>, October 1993.
-
- 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/>.
- */
-
-/* Compiled only when USE_STACKOVF is defined, which itself requires
- getrlimit with the RLIMIT_STACK option, and support for alternate
- signal stacks using either SVR4 or BSD interfaces.
-
- This should compile on ANY system which supports either sigaltstack()
- or sigstack(), with or without <siginfo.h> or another way to determine
- the fault address.
-
- There is no completely portable way to determine if a SIGSEGV signal
- indicates a stack overflow. The fault address can be used to infer
- this. However, the fault address is passed to the signal handler in
- different ways on various systems. One of three methods are used to
- determine the fault address:
-
- 1. The siginfo parameter (with siginfo.h, i.e., SVR4).
-
- 2. 4th "addr" parameter (assumed if struct sigcontext is defined,
- i.e., SunOS 4.x/BSD).
-
- 3. None (if no method is available). This case just prints a
- message before aborting with a core dump. That way the user at
- least knows that it *might* be a recursion problem.
-
- Jim Avera <jima@netcom.com> writes, on Tue, 5 Oct 93 19:27 PDT:
-
- "I got interested finding out how a program could catch and
- diagnose its own stack overflow, and ended up modifying m4 to do
- this. Now it prints a nice error message and exits.
-
- How it works: SIGSEGV is caught using a separate signal stack. The
- signal handler declares a stack overflow if the fault address is
- near the end of the stack region, or if the maximum VM address
- space limit has been reached. Otherwise, it returns to re-execute
- the instruction with SIG_DFL set, so that any real bugs cause a
- core dump as usual."
-
- Jim Avera <jima@netcom.com> writes, on Fri, 24 Jun 94 12:14 PDT:
-
- "The stack-overflow detection code would still be needed to avoid a
- SIGSEGV abort if swap space was exhausted at the moment the stack
- tried to grow. This is probably unlikely to occur with the
- explicit nesting limit option of GNU m4."
-
- Jim Avera <jima@netcom.com> writes, on Wed, 6 Jul 1994 14:41 PDT:
-
- "When a stack overflow occurs, a SIGSEGV signal is sent, which by
- default aborts the process with a core dump.
-
- The code in stackovf.c catches SIGSEGV using a separate signal
- stack. The signal handler determines whether or not the SIGSEGV
- arose from a stack overflow. If it is a stack overflow, an
- external function is called (which, in m4, prints a message an
- exits). Otherwise the SIGSEGV represents an m4 bug, and the signal
- is re-raised with SIG_DFL set, which results in an abort and core
- dump in the usual way. It seems important (to me) that internal m4
- bugs not be reported as user recursion errors, or vice-versa." */
-
-/* Define this to see runtime debug info. Implied by DEBUG. */
-/*#define DEBUG_STKOVF */
-
-#include <config.h>
-
-#include "m4.h"
-
-#ifdef USE_STACKOVF
-
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#if HAVE_SIGINFO_H
-# include <siginfo.h>
-#endif
-
-#ifndef SA_RESETHAND
-# define SA_RESETHAND 0
-#endif
-#ifndef SA_SIGINFO
-# define SA_SIGINFO 0
-#endif
-
-#ifndef SIGSTKSZ
-# define SIGSTKSZ 8192
-#endif
-
-/* If the trap address is within STACKOVF_DETECT bytes of the calculated
- stack limit, we diagnose a stack overflow. This must be large enough
- to cover errors in our estimatation of the limit address, and to
- account for the maximum size of local variables (the amount the
- trapping reference might exceed the stack limit). Also, some machines
- may report an arbitrary address within the same page frame.
- If the value is too large, we might call some other SIGSEGV a stack
- overflow, masking a bug. */
-
-#ifndef STACKOVF_DETECT
-# define STACKOVF_DETECT 16384
-#endif
-
-typedef void (*handler_t) (void);
-
-#if defined __ultrix && defined __vax
-extern char *sbrk (int);
-extern int getrlimit (int, struct rlimit *);
-extern int sigstack (struct sigstack *, struct sigstack *);
-extern int sigvec (int, struct sigvec *, struct sigvec *);
-#endif
-
-static void *stackbuf;
-static const char *stackbot;
-static const char *stackend;
-static const char *arg0;
-static handler_t stackovf_handler;
-
-/* The following OS-independent procedure is called from the SIGSEGV
- signal handler. The signal handler obtains information about the trap
- in an OS-dependent manner, and passes a parameter with the meanings as
- explained below.
-
- If the OS explicitly identifies a stack overflow trap, either pass
- PARAM_STACKOVF if a stack overflow, or pass PARAM_NOSTACKOVF if not
- (id est, it is a random bounds violation). Otherwise, if the fault
- address is available, pass the fault address. Otherwise (if no
- information is available), pass NULL.
-
- Not given an explicit indication, we compare the fault address with
- the estimated stack limit, and test to see if overall VM space is
- exhausted.
-
- If a stack overflow is identified, then the external *stackovf_handler
- function is called, which should print an error message and exit. If
- it is NOT a stack overflow, then we silently abort with a core dump by
- returning to re-raise the SIGSEGV with SIG_DFL set. If indeterminate,
- then we do not call *stackovf_handler, but instead print an ambiguous
- message and abort with a core dump. This only occurs on systems which
- provide no information, but is better than nothing. */
-
-#define PARAM_STACKOVF ((const char *) (1 + STACKOVF_DETECT))
-#define PARAM_NOSTACKOVF ((const char *) (2 + STACKOVF_DETECT))
-
-static void
-process_sigsegv (int signo, const char *p)
-{
- ptrdiff_t diff;
- diff = (p - stackend);
-
-#ifdef DEBUG_STKOVF
- {
- char buf[200];
-
- sprintf (buf,
- "process_sigsegv: p=%p stackend=%p diff=%" PRIdPTR "bot=%p\n",
- p, stackend, diff, stackbot);
- write (2, buf, strlen (buf));
- }
-#endif
-
- if (p != PARAM_NOSTACKOVF)
- {
- if ((long) sbrk (8192) == (long) -1)
- {
- const char *cp;
-
- /* sbrk failed. Assume the RLIMIT_VMEM prevents expansion even
- if the stack limit has not been reached. */
-
- /* FIXME - calling gettext inside a signal handler is
- dangerous, since it can call malloc, which is not signal
- safe. We can sort of justify it by the fact that this
- handler is designed to exit() the program, but it could
- really use a better fix. */
- cp = _("VMEM limit exceeded?\n");
- write (2, cp, strlen (cp));
- p = PARAM_STACKOVF;
- }
- if (diff >= -STACKOVF_DETECT && diff <= STACKOVF_DETECT)
- {
-
- /* The fault address is "sufficiently close" to the stack lim. */
-
- p = PARAM_STACKOVF;
- }
- if (p == PARAM_STACKOVF)
- {
-
- /* We have determined that this is indeed a stack overflow. */
-
- (*stackovf_handler) (); /* should call exit() */
- }
- }
- if (p == NULL)
- {
- const char *cp;
-
- /* FIXME - calling gettext inside a signal handler is dangerous,
- since it can call malloc, which is not signal safe. */
- cp = _("\
-Memory bounds violation detected (SIGSEGV). Either a stack overflow\n\
-occurred, or there is a bug in ");
- write (2, cp, strlen (cp));
- write (2, arg0, strlen (arg0));
- cp = _(". Check for possible infinite recursion.\n");
- write (2, cp, strlen (cp));
- }
-
- /* Return to re-execute the instruction which caused the trap with
- SIGSEGV set to SIG_DFL. An abort with core dump should occur. */
-
- signal (signo, SIG_DFL);
-}
-
-#if HAVE_STRUCT_SIGACTION_SA_SIGACTION
-
-/* POSIX. */
-
-static void
-sigsegv_handler (int signo, siginfo_t *ip, void *context)
-{
- process_sigsegv
- (signo, (ip != NULL
- && ip->si_signo == SIGSEGV ? (char *) ip->si_addr : NULL));
-}
-
-#elif HAVE_SIGINFO_T
-
-/* SVR4. */
-
-static void
-sigsegv_handler (int signo, siginfo_t *ip)
-{
- process_sigsegv
- (signo, (ip != NULL
- && ip->si_signo == SIGSEGV ? (char *) ip->si_addr : NULL));
-}
-
-#elif HAVE_SIGCONTEXT
-
-/* SunOS 4.x (and BSD?). (not tested) */
-
-static void
-sigsegv_handler (int signo, int code, struct sigcontext *scp, char *addr)
-{
- process_sigsegv (signo, addr);
-}
-
-#else /* not HAVE_SIGCONTEXT */
-
-/* OS provides no information. */
-
-static void
-sigsegv_handler (int signo)
-{
- process_sigsegv (signo, NULL);
-}
-
-#endif /* not HAVE_SIGCONTEXT */
-
-/* Arrange to trap a stack-overflow and call a specified handler. The
- call is on a dedicated signal stack.
-
- argv and envp are as passed to main.
-
- If a stack overflow is not detected, then the SIGSEGV is re-raised
- with action set to SIG_DFL, causing an abort and coredump in the usual
- way.
-
- Detection of a stack overflow depends on the trap address being near
- the stack limit address. The stack limit cannot be directly
- determined in a portable way, but we make an estimate based on the
- address of the argv and environment vectors, their contents, and the
- maximum stack size obtained using getrlimit. */
-
-void
-setup_stackovf_trap (char *const *argv, char *const *envp, handler_t handler)
-{
- struct rlimit rl;
- rlim_t stack_len;
- int grows_upward;
- register char *const *v;
- register char *p;
-#if HAVE_SIGACTION && defined SA_ONSTACK
- struct sigaction act;
-#elif HAVE_SIGVEC && defined SV_ONSTACK
- struct sigvec vec;
-#else
-
-Error - Do not know how to set up stack-ovf trap handler...
-
-#endif
-
- arg0 = argv[0];
- stackovf_handler = handler;
-
- /* Calculate the approximate expected addr for a stack-ovf trap. */
-
- if (getrlimit (RLIMIT_STACK, &rl) < 0)
- error (EXIT_FAILURE, errno, _("getrlimit"));
- stack_len = (rl.rlim_cur < rl.rlim_max ? rl.rlim_cur : rl.rlim_max);
- stackbot = (char *) argv;
- grows_upward = ((char *) &stack_len > stackbot);
- if (grows_upward)
- {
-
- /* Grows toward increasing addresses. */
-
- for (v = argv; (p = (char *) *v) != NULL; v++)
- {
- if (p < stackbot)
- stackbot = p;
- }
- if ((char *) envp < stackbot)
- stackbot = (char *) envp;
- for (v = envp; (p = (char *) *v) != NULL; v++)
- {
- if (p < stackbot)
- stackbot = p;
- }
- stackend = stackbot + stack_len;
- }
- else
- {
-
- /* The stack grows "downward" (toward decreasing addresses). */
-
- for (v = argv; (p = (char *) *v) != NULL; v++)
- {
- if (p > stackbot)
- stackbot = p;
- }
- if ((char *) envp > stackbot)
- stackbot = (char *) envp;
- for (v = envp; (p = (char *) *v) != NULL; v++)
- {
- if (p > stackbot)
- stackbot = p;
- }
- stackend = stackbot - stack_len;
- }
-
- /* Allocate a separate signal-handler stack. */
-
-#if HAVE_SIGALTSTACK && (HAVE_SIGINFO_T || ! HAVE_SIGSTACK)
-
- /* Use sigaltstack only if siginfo_t is available, unless there is no
- choice. */
-
- {
- stack_t ss;
-# ifndef HAVE_STACK_T_SS_SP
- /* This workaround is for BSD/OS 4.0.1:
- http://lists.gnu.org/archive/html/bug-m4/2006-12/msg00004.html */
-# define ss_sp ss_base
-# endif /* ! HAVE_STACK_T_SS_SP */
-
- stackbuf = xmalloc (SIGSTKSZ);
-
- ss.ss_size = SIGSTKSZ;
- ss.ss_sp = stackbuf;
- ss.ss_flags = 0;
- if (sigaltstack (&ss, NULL) < 0)
- {
- /* Oops - sigstack exists but doesn't work. We can't install
- the overflow detector, but should gracefully treat it as
- though sigstack doesn't exist. For example, this happens
- when compiled with Linux 2.1 headers but run against Linux
- 2.0 kernel. */
- free (stackbuf);
- if (errno == ENOSYS)
- return;
- error (EXIT_FAILURE, errno, _("sigaltstack"));
- }
- }
-
-#elif HAVE_SIGSTACK
-
- {
- struct sigstack ss;
- stackbuf = xmalloc (2 * SIGSTKSZ);
-
- ss.ss_sp = stackbuf + SIGSTKSZ;
- ss.ss_onstack = 0;
- if (sigstack (&ss, NULL) < 0)
- {
- /* Oops - sigstack exists but doesn't work. We can't install
- the overflow detector, but should gracefully treat it as
- though sigstack doesn't exist. For example, this happens
- when compiled with Linux 2.1 headers but run against Linux
- 2.0 kernel. */
- free (stackbuf);
- if (errno == ENOSYS)
- return;
- error (EXIT_FAILURE, errno, _("sigstack"));
- }
- }
-
-#else /* not HAVE_SIGSTACK */
-
-Error - Do not know how to set up stack-ovf trap handler...
-
-#endif /* not HAVE_SIGSTACK */
-
- /* Arm the SIGSEGV signal handler. */
-
-#if HAVE_SIGACTION && defined SA_ONSTACK
-
- sigaction (SIGSEGV, NULL, &act);
-# if HAVE_STRUCT_SIGACTION_SA_SIGACTION
- act.sa_sigaction = sigsegv_handler;
-# else /* ! HAVE_STRUCT_SIGACTION_SA_SIGACTION */
- act.sa_handler = (RETSIGTYPE (*) (int)) sigsegv_handler;
-# endif /* ! HAVE_STRUCT_SIGACTION_SA_SIGACTION */
- sigemptyset (&act.sa_mask);
- act.sa_flags = (SA_ONSTACK | SA_RESETHAND | SA_SIGINFO);
- if (sigaction (SIGSEGV, &act, NULL) < 0)
- error (EXIT_FAILURE, errno, _("sigaction"));
-
-#else /* ! HAVE_SIGACTION */
-
- vec.sv_handler = (RETSIGTYPE (*) (int)) sigsegv_handler;
- vec.sv_mask = 0;
- vec.sv_flags = (SV_ONSTACK | SV_RESETHAND);
- if (sigvec (SIGSEGV, &vec, NULL) < 0)
- error (EXIT_FAILURE, errno, _("sigvec"));
-
-#endif /* ! HAVE_SIGACTION */
-
-}
-
-void
-stackovf_exit (void)
-{
- DELETE (stackbuf);
-}
-
-#endif /* USE_STACKOVF */