summaryrefslogtreecommitdiff
path: root/modules/m4.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/m4.c')
-rw-r--r--modules/m4.c1324
1 files changed, 0 insertions, 1324 deletions
diff --git a/modules/m4.c b/modules/m4.c
deleted file mode 100644
index ed06942b..00000000
--- a/modules/m4.c
+++ /dev/null
@@ -1,1324 +0,0 @@
-/* GNU m4 -- A simple macro processor
- Copyright (C) 2000, 2002-2004, 2006-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>
-
-/* Build using only the exported interfaces, unless NDEBUG is set, in
- which case use private symbols to speed things up as much as possible. */
-#ifndef NDEBUG
-# include <m4/m4module.h>
-#else
-# include "m4private.h"
-#endif
-
-#include "execute.h"
-#include "memchr2.h"
-#include "memcmp2.h"
-#include "quotearg.h"
-#include "stdlib--.h"
-#include "tempname.h"
-#include "unistd--.h"
-
-#include <modules/m4.h>
-
-extern void m4_set_sysval (int);
-extern void m4_sysval_flush (m4 *, bool);
-extern void m4_dump_symbols (m4 *, m4_dump_symbol_data *, size_t,
- m4_macro_args *, bool);
-extern const char *m4_expand_ranges (const char *, size_t *, m4_obstack *);
-extern void m4_make_temp (m4 *, m4_obstack *, const m4_call_info *,
- const char *, size_t, bool);
-
-/* Maintain each of the builtins implemented in this modules along
- with their details in a single table for easy maintenance.
-
- function macros blind side minargs maxargs */
-#define builtin_functions \
- BUILTIN (changecom, false, false, false, 0, 2 ) \
- BUILTIN (changequote, false, false, false, 0, 2 ) \
- BUILTIN (decr, false, true, true, 1, 1 ) \
- BUILTIN (define, true, true, false, 1, 2 ) \
- BUILTIN (defn, true, true, false, 1, -1 ) \
- BUILTIN (divert, false, false, false, 0, 2 ) \
- BUILTIN (divnum, false, false, false, 0, 0 ) \
- BUILTIN (dnl, false, false, false, 0, 0 ) \
- BUILTIN (dumpdef, true, false, false, 0, -1 ) \
- BUILTIN (errprint, false, true, false, 1, -1 ) \
- BUILTIN (eval, false, true, true, 1, 3 ) \
- BUILTIN (ifdef, true, true, false, 2, 3 ) \
- BUILTIN (ifelse, true, true, false, 1, -1 ) \
- BUILTIN (include, false, true, false, 1, 1 ) \
- BUILTIN (incr, false, true, true, 1, 1 ) \
- BUILTIN (index, false, true, true, 2, 3 ) \
- BUILTIN (len, false, true, true, 1, 1 ) \
- BUILTIN (m4exit, false, false, false, 0, 1 ) \
- BUILTIN (m4wrap, true, true, false, 1, -1 ) \
- BUILTIN (maketemp, false, true, false, 1, 1 ) \
- BUILTIN (mkstemp, false, true, false, 1, 1 ) \
- BUILTIN (popdef, true, true, false, 1, -1 ) \
- BUILTIN (pushdef, true, true, false, 1, 2 ) \
- BUILTIN (shift, true, true, false, 1, -1 ) \
- BUILTIN (sinclude, false, true, false, 1, 1 ) \
- BUILTIN (substr, false, true, true, 2, 4 ) \
- BUILTIN (syscmd, false, true, true, 1, 1 ) \
- BUILTIN (sysval, false, false, false, 0, 0 ) \
- BUILTIN (traceoff, true, false, false, 0, -1 ) \
- BUILTIN (traceon, true, false, false, 0, -1 ) \
- BUILTIN (translit, false, true, true, 2, 3 ) \
- BUILTIN (undefine, true, true, false, 1, -1 ) \
- BUILTIN (undivert, false, false, false, 0, -1 ) \
-
-
-typedef intmax_t number;
-typedef uintmax_t unumber;
-
-static void include (m4 *context, m4_obstack *obs, size_t argc,
- m4_macro_args *argv, bool silent);
-static int dumpdef_cmp_CB (const void *s1, const void *s2);
-static void * dump_symbol_CB (m4_symbol_table *, const char *, size_t,
- m4_symbol *symbol, void *userdata);
-static const char *ntoa (number value, int radix);
-static void numb_obstack (m4_obstack *obs, number value,
- int radix, int min);
-
-
-/* Generate prototypes for each builtin handler function. */
-#define BUILTIN(handler, macros, blind, side, min, max) M4BUILTIN (handler)
- builtin_functions
-#undef BUILTIN
-
-
-/* Generate a table for mapping m4 symbol names to handler functions. */
-static const m4_builtin m4_builtin_table[] =
-{
-#define BUILTIN(handler, macros, blind, side, min, max) \
- M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max)
-
- builtin_functions
-#undef BUILTIN
-
- { NULL, NULL, 0, 0, 0 },
-};
-
-
-void
-include_m4 (m4 *context, m4_module *module, m4_obstack *obs)
-{
- m4_install_builtins (context, module, m4_builtin_table);
-}
-
-
-
-/* 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 builtin_MACRONAME (m4_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. */
-
-M4BUILTIN_HANDLER (define)
-{
- const m4_call_info *me = m4_arg_info (argv);
-
- if (m4_is_arg_text (argv, 1))
- {
- m4_symbol_value *value = m4_symbol_value_create ();
-
- if (m4_symbol_value_copy (context, value, m4_arg_symbol (argv, 2)))
- m4_warn (context, 0, me, _("cannot concatenate builtins"));
- m4_symbol_define (M4SYMTAB, M4ARG (1), M4ARGLEN (1), value);
- }
- else
- m4_warn (context, 0, me, _("invalid macro name ignored"));
-}
-
-M4BUILTIN_HANDLER (undefine)
-{
- size_t i;
- for (i = 1; i < argc; i++)
- if (m4_symbol_value_lookup (context, argv, i, true))
- m4_symbol_delete (M4SYMTAB, M4ARG (i), M4ARGLEN (i));
-}
-
-M4BUILTIN_HANDLER (pushdef)
-{
- const m4_call_info *me = m4_arg_info (argv);
-
- if (m4_is_arg_text (argv, 1))
- {
- m4_symbol_value *value = m4_symbol_value_create ();
-
- if (m4_symbol_value_copy (context, value, m4_arg_symbol (argv, 2)))
- m4_warn (context, 0, me, _("cannot concatenate builtins"));
- m4_symbol_pushdef (M4SYMTAB, M4ARG (1), M4ARGLEN (1), value);
- }
- else
- m4_warn (context, 0, me, _("invalid macro name ignored"));
-}
-
-M4BUILTIN_HANDLER (popdef)
-{
- size_t i;
- for (i = 1; i < argc; i++)
- if (m4_symbol_value_lookup (context, argv, i, true))
- m4_symbol_popdef (M4SYMTAB, M4ARG (i), M4ARGLEN (i));
-}
-
-
-
-/* --- CONDITIONALS OF M4 --- */
-
-
-M4BUILTIN_HANDLER (ifdef)
-{
- m4_push_arg (context, obs, argv,
- m4_symbol_value_lookup (context, argv, 1, false) ? 2 : 3);
-}
-
-M4BUILTIN_HANDLER (ifelse)
-{
- const m4_call_info *me = m4_arg_info (argv);
- size_t i;
-
- /* The valid ranges of argc for ifelse is discontinuous, we cannot
- rely on the regular mechanisms. */
- if (argc == 2 || m4_bad_argc (context, argc, me, 3, -1, false))
- return;
- else if (argc % 3 == 0)
- /* Diagnose excess arguments if 5, 8, 11, etc., actual arguments. */
- m4_bad_argc (context, argc, me, 0, argc - 2, false);
-
- i = 1;
- argc--;
-
- while (true)
- {
- if (m4_arg_equal (context, argv, i, i + 1))
- {
- m4_push_arg (context, obs, argv, i + 2);
- return;
- }
- switch (argc)
- {
- case 3:
- return;
-
- case 4:
- case 5:
- m4_push_arg (context, obs, argv, i + 3);
- return;
-
- default:
- argc -= 3;
- i += 3;
- }
- }
-}
-
-
-/* qsort comparison routine, for sorting the table made in m4_dumpdef (). */
-static int
-dumpdef_cmp_CB (const void *s1, const void *s2)
-{
- const m4_string *a = (const m4_string *) s1;
- const m4_string *b = (const m4_string *) s2;
- return memcmp2 (a->str, a->len, b->str, b->len);
-}
-
-/* The function m4_dump_symbols () is for use by "dumpdef". It builds up a
- table of all defined symbol names. */
-static void *
-dump_symbol_CB (m4_symbol_table *ignored M4_GNUC_UNUSED, const char *name,
- size_t len, m4_symbol *symbol, void *userdata)
-{
- m4_dump_symbol_data *symbol_data = (m4_dump_symbol_data *) userdata;
- m4_string *key;
-
- assert (name);
- assert (symbol);
- assert (!m4_is_symbol_value_void (m4_get_symbol_value (symbol)));
-
- if (symbol_data->size == 0)
- {
- char *base;
- size_t offset = obstack_object_size (symbol_data->obs);
- obstack_blank (symbol_data->obs, sizeof *symbol_data->base);
- symbol_data->size = (obstack_room (symbol_data->obs)
- / sizeof *symbol_data->base);
- base = (char *) obstack_base (symbol_data->obs) + offset;
- symbol_data->base = (m4_string *) base;
- }
- else
- {
- obstack_blank_fast (symbol_data->obs, sizeof *symbol_data->base);
- symbol_data->size--;
- }
-
- /* Safe to cast away const, since m4_dump_symbols adds it back. */
- key = (m4_string *) symbol_data->base++;
- key->str = (char *) name;
- key->len = len;
- return NULL;
-}
-
-/* If there are no arguments, build a sorted list of all defined
- symbols, otherwise, only the specified symbols. */
-void
-m4_dump_symbols (m4 *context, m4_dump_symbol_data *data, size_t argc,
- m4_macro_args *argv, bool complain)
-{
- assert (obstack_object_size (data->obs) == 0);
- data->size = obstack_room (data->obs) / sizeof *data->base;
- data->base = (m4_string *) obstack_base (data->obs);
-
- if (argc == 1)
- m4_symtab_apply (M4SYMTAB, false, dump_symbol_CB, data);
- else
- {
- size_t i;
- m4_symbol *symbol;
-
- for (i = 1; i < argc; i++)
- {
- symbol = m4_symbol_value_lookup (context, argv, i, complain);
- if (symbol)
- dump_symbol_CB (NULL, M4ARG (i), M4ARGLEN (i), symbol, data);
- }
- }
-
- data->size = obstack_object_size (data->obs) / sizeof *data->base;
- data->base = (m4_string *) obstack_finish (data->obs);
- /* Safe to cast away const, since we don't modify entries. */
- qsort ((m4_string *) data->base, data->size, sizeof *data->base,
- dumpdef_cmp_CB);
-}
-
-
-/* Implementation of "dumpdef" itself. It builds up a table of pointers to
- symbols, sorts it and prints the sorted table. */
-M4BUILTIN_HANDLER (dumpdef)
-{
- m4_dump_symbol_data data;
- const m4_string_pair *quotes = NULL;
- bool stack = m4_is_debug_bit (context, M4_DEBUG_TRACE_STACK);
- size_t arg_length = m4_get_max_debug_arg_length_opt (context);
- bool module = m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE);
- FILE *output = (m4_is_debug_bit (context, M4_DEBUG_TRACE_OUTPUT_DUMPDEF)
- ? stderr : m4_get_debug_file (context));
-
- if (!output)
- return;
- if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
- quotes = m4_get_syntax_quotes (M4SYNTAX);
- data.obs = m4_arg_scratch (context);
- m4_dump_symbols (context, &data, argc, argv, true);
- m4_sysval_flush (context, false);
-
- for (; data.size > 0; --data.size, data.base++)
- {
- m4_symbol *symbol = m4_symbol_lookup (M4SYMTAB, data.base->str,
- data.base->len);
- char *value;
- size_t len;
- assert (symbol);
-
- /* TODO - add debugmode(b) option to control quoting style. */
- obstack_grow (obs, data.base->str, data.base->len);
- obstack_1grow (obs, ':');
- obstack_1grow (obs, '\t');
- m4_symbol_print (context, symbol, obs, quotes, stack, arg_length,
- module);
- obstack_1grow (obs, '\n');
- len = obstack_object_size (obs);
- value = (char *) obstack_finish (obs);
- fwrite (value, 1, len, output);
- obstack_free (obs, value);
- }
-}
-
-/* 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. */
-M4BUILTIN_HANDLER (defn)
-{
- const m4_call_info *me = m4_arg_info (argv);
- size_t i;
-
- for (i = 1; i < argc; i++)
- {
- m4_symbol *symbol = m4_symbol_value_lookup (context, argv, i, true);
-
- if (!symbol)
- ;
- else if (m4_is_symbol_text (symbol))
- m4_shipout_string (context, obs, m4_get_symbol_text (symbol),
- m4_get_symbol_len (symbol), true);
- else if (m4_is_symbol_func (symbol))
- m4_push_builtin (context, obs, m4_get_symbol_value (symbol));
- else if (m4_is_symbol_placeholder (symbol))
- m4_warn (context, 0, me,
- _("%s: builtin %s requested by frozen file not found"),
- quotearg_n_mem (2, M4ARG (i), M4ARGLEN (i)),
- quotearg_style (locale_quoting_style,
- m4_get_symbol_placeholder (symbol)));
- else
- {
- assert (!"Bad token data type in m4_defn");
- abort ();
- }
- }
-}
-
-
-/* This section contains macros to handle the builtins "syscmd"
- and "sysval". */
-
-/* Exit code from last "syscmd" command. */
-/* FIXME - we should preserve this value across freezing. See
- http://lists.gnu.org/archive/html/bug-m4/2006-06/msg00059.html
- for ideas on how do to that. */
-static int m4_sysval = 0;
-
-void
-m4_set_sysval (int value)
-{
- m4_sysval = value;
-}
-
-/* Flush a given output STREAM. If REPORT, also print an error
- message and clear the stream error bit. */
-static void
-sysval_flush_helper (m4 *context, FILE *stream, bool report)
-{
- if (fflush (stream) == EOF && report)
- {
- m4_error (context, 0, errno, NULL, _("write error"));
- clearerr (stream);
- }
-}
-
-/* Flush all user output streams, prior to doing something that can
- could lose unflushed data or interleave debug and normal output
- incorrectly. If REPORT, then print an error message on failure and
- clear the stream error bit; otherwise a subsequent ferror can track
- that an error occurred. */
-void
-m4_sysval_flush (m4 *context, bool report)
-{
- FILE *debug_file = m4_get_debug_file (context);
-
- if (debug_file != stdout)
- sysval_flush_helper (context, stdout, report);
- if (debug_file != stderr)
- /* If we have problems with stderr, we can't really report that
- problem to stderr. The closeout module will ensure the exit
- status reflects the problem, though. */
- fflush (stderr);
- if (debug_file != NULL)
- sysval_flush_helper (context, debug_file, report);
- /* 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);
- }
-}
-
-M4BUILTIN_HANDLER (syscmd)
-{
- const m4_call_info *me = m4_arg_info (argv);
- const char *cmd = M4ARG (1);
- size_t len = M4ARGLEN (1);
- int status;
- int sig_status;
- const char *prog_args[4] = { "sh", "-c" };
-
- if (m4_get_safer_opt (context))
- {
- m4_error (context, 0, 0, m4_arg_info (argv), _("disabled by --safer"));
- return;
- }
- if (strlen (cmd) != len)
- m4_warn (context, 0, me, _("argument %s truncated"),
- quotearg_style_mem (locale_quoting_style, cmd, len));
-
- /* Optimize the empty command. */
- if (!*cmd)
- {
- m4_set_sysval (0);
- return;
- }
- m4_sysval_flush (context, false);
-#if W32_NATIVE
- if (strstr (M4_SYSCMD_SHELL, "cmd"))
- {
- prog_args[0] = "cmd";
- prog_args[1] = "/c";
- }
-#endif
- prog_args[2] = cmd;
- errno = 0;
- status = execute (m4_info_name (me), M4_SYSCMD_SHELL, (char **) prog_args,
- false, false, false, false, true, false, &sig_status);
- if (sig_status)
- {
- assert (status == 127);
- m4_sysval = sig_status << 8;
- }
- else
- {
- if (status == 127 && errno)
- m4_warn (context, errno, me, _("cannot run command %s"),
- quotearg_style (locale_quoting_style, cmd));
- m4_sysval = status;
- }
-}
-
-
-M4BUILTIN_HANDLER (sysval)
-{
- m4_shipout_int (obs, m4_sysval);
-}
-
-
-M4BUILTIN_HANDLER (incr)
-{
- int value;
-
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
- &value))
- return;
-
- m4_shipout_int (obs, value + 1);
-}
-
-M4BUILTIN_HANDLER (decr)
-{
- int value;
-
- if (!m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
- &value))
- return;
-
- m4_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. */
-M4BUILTIN_HANDLER (divert)
-{
- int i = 0;
-
- if (argc >= 2 && !m4_numeric_arg (context, m4_arg_info (argv), M4ARG (1),
- M4ARGLEN (1), &i))
- return;
- m4_make_diversion (context, i);
- m4_divert_text (context, NULL, M4ARG (2), M4ARGLEN (2),
- m4_get_current_line (context));
-}
-
-/* Expand to the current diversion number. */
-M4BUILTIN_HANDLER (divnum)
-{
- m4_shipout_int (obs, m4_get_current_diversion (context));
-}
-
-/* Bring back the diversion given by the argument list. If none is
- specified, bring back all diversions. GNU specific is the option
- of undiverting the named file, by passing a non-numeric argument to
- undivert (). */
-
-M4BUILTIN_HANDLER (undivert)
-{
- size_t i = 0;
- const m4_call_info *me = m4_arg_info (argv);
-
- if (argc == 1)
- m4_undivert_all (context);
- else
- for (i = 1; i < argc; i++)
- {
- const char *str = M4ARG (i);
- size_t len = M4ARGLEN (i);
- char *endp;
- int diversion = strtol (str, &endp, 10);
- if (endp - str == len && !isspace ((unsigned char) *str))
- m4_insert_diversion (context, diversion);
- else if (m4_get_posixly_correct_opt (context))
- m4_warn (context, 0, me, _("non-numeric argument %s"),
- quotearg_style_mem (locale_quoting_style, str, len));
- else if (strlen (str) != len)
- m4_warn (context, 0, me, _("invalid file name %s"),
- quotearg_style_mem (locale_quoting_style, str, len));
- else
- {
- char *filepath = m4_path_search (context, str, NULL);
- FILE *fp = m4_fopen (context, filepath, "r");
-
- free (filepath);
- if (fp != NULL)
- {
- m4_insert_file (context, fp);
- if (fclose (fp) == EOF)
- m4_error (context, 0, errno, me, _("error undiverting %s"),
- quotearg_style (locale_quoting_style, str));
- }
- else
- m4_error (context, 0, errno, me, _("cannot undivert %s"),
- quotearg_style (locale_quoting_style, str));
- }
- }
-}
-
-
-/* This section contains various macros, which does not fall into
- any specific group. These are "dnl", "shift", "changequote",
- "changecom" and "changesyntax" */
-
-/* Delete all subsequent whitespace from input. The function skip_line ()
- lives in input.c. */
-M4BUILTIN_HANDLER (dnl)
-{
- m4_skip_line (context, m4_arg_info (argv));
-}
-
-/* Shift all arguments one to the left, discarding the first argument.
- Each output argument is quoted with the current quotes. */
-M4BUILTIN_HANDLER (shift)
-{
- m4_push_args (context, obs, argv, true, true);
-}
-
-/* Change the current quotes. The function set_quotes () lives in
- syntax.c. */
-M4BUILTIN_HANDLER (changequote)
-{
- m4_set_quotes (M4SYNTAX,
- (argc >= 2) ? M4ARG (1) : NULL, M4ARGLEN (1),
- (argc >= 3) ? M4ARG (2) : NULL, M4ARGLEN (2));
-}
-
-/* Change the current comment delimiters. The function set_comment ()
- lives in syntax.c. */
-M4BUILTIN_HANDLER (changecom)
-{
- m4_set_comment (M4SYNTAX,
- (argc >= 2) ? M4ARG (1) : NULL, M4ARGLEN (1),
- (argc >= 3) ? M4ARG (2) : NULL, M4ARGLEN (2));
-}
-
-
-/* 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. */
-
-static void
-include (m4 *context, m4_obstack *obs, size_t argc, m4_macro_args *argv, bool silent)
-{
- const m4_call_info *me = m4_arg_info (argv);
- const char *arg = M4ARG (1);
- size_t len = M4ARGLEN (1);
-
- if (strlen (arg) != len)
- m4_warn (context, 0, me, _("argument %s truncated"),
- quotearg_style_mem (locale_quoting_style, arg, len));
- m4_load_filename (context, me, arg, obs, silent);
-}
-
-/* Include a file, complaining in case of errors. */
-M4BUILTIN_HANDLER (include)
-{
- include (context, obs, argc, argv, false);
-}
-
-/* Include a file, ignoring errors. */
-M4BUILTIN_HANDLER (sinclude)
-{
- include (context, obs, argc, argv, true);
-}
-
-
-/* More miscellaneous builtins -- "maketemp", "errprint". */
-
-/* Add trailing `X' to PATTERN of length LEN as necessary, then
- securely create the temporary file system object. If DIR, create a
- directory instead of a file. Report errors on behalf of CALLER. If
- successful, output the quoted resulting name on OBS. */
-void
-m4_make_temp (m4 *context, m4_obstack *obs, const m4_call_info *caller,
- const char *pattern, size_t len, bool dir)
-{
- int fd;
- int i;
- char *name;
- const m4_string_pair *quotes = m4_get_syntax_quotes (M4SYNTAX);
-
- if (m4_get_safer_opt (context))
- {
- m4_error (context, 0, 0, caller, _("disabled by --safer"));
- return;
- }
-
- /* Guarantee that there are six trailing 'X' characters, even if the
- user forgot to supply them. Output must be quoted if
- successful. */
- assert (obstack_object_size (obs) == 0);
- obstack_grow (obs, quotes->str1, quotes->len1);
- if (strlen (pattern) < len)
- {
- m4_warn (context, 0, caller, _("argument %s truncated"),
- quotearg_style_mem (locale_quoting_style, pattern, len));
- len = strlen (pattern);
- }
- obstack_grow (obs, pattern, len);
- for (i = 0; len > 0 && i < 6; i++)
- if (pattern[--len] != 'X')
- break;
- obstack_grow0 (obs, "XXXXXX", 6 - i);
- name = (char *) obstack_base (obs) + quotes->len1;
-
- /* Make the temporary object. */
- errno = 0;
- fd = gen_tempname (name, 0, 0, dir ? GT_DIR : GT_FILE);
- if (fd < 0)
- {
- /* This use of _() will need to change if xgettext ever changes
- its undocumented behavior of parsing both string options. */
-
- m4_warn (context, errno, caller,
- _(dir ? "cannot create directory from template %s"
- : "cannot create file from template %s"),
- quotearg_style (locale_quoting_style, pattern));
- obstack_free (obs, obstack_finish (obs));
- }
- else
- {
- if (!dir)
- close (fd);
- /* Remove NUL, then finish quote. */
- obstack_blank_fast (obs, -1);
- obstack_grow (obs, quotes->str2, quotes->len2);
- }
-}
-
-/* Use the first argument as at template for a temporary file name. */
-M4BUILTIN_HANDLER (maketemp)
-{
- const m4_call_info *me = m4_arg_info (argv);
- m4_warn (context, 0, me, _("recommend using mkstemp instead"));
- if (m4_get_posixly_correct_opt (context))
- {
- /* 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.
-
- 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 = M4ARG (1);
- size_t len = M4ARGLEN (1);
- size_t i;
- m4_obstack *scratch = m4_arg_scratch (context);
- size_t pid_len = obstack_printf (scratch, "%lu",
- (unsigned long) getpid ());
- char *pid = (char *) obstack_copy0 (scratch, "", 0);
-
- for (i = len; i > 1; i--)
- if (str[i - 1] != 'X')
- break;
- obstack_grow (obs, str, i);
- if (len - i < pid_len)
- obstack_grow (obs, pid + pid_len - (len - i), len - i);
- else
- obstack_printf (obs, "%.*d%s", (int) (len - i - pid_len), 0, pid);
- }
- else
- m4_make_temp (context, obs, me, M4ARG (1), M4ARGLEN (1), false);
-}
-
-/* Use the first argument as a template for a temporary file name. */
-M4BUILTIN_HANDLER (mkstemp)
-{
- m4_make_temp (context, obs, m4_arg_info (argv), M4ARG (1), M4ARGLEN (1),
- false);
-}
-
-/* Print all arguments on standard error. */
-M4BUILTIN_HANDLER (errprint)
-{
- size_t i;
-
- m4_sysval_flush (context, false);
- /* The close_stdin module makes it safe to skip checking the return
- values here. */
- fwrite (M4ARG (1), 1, M4ARGLEN (1), stderr);
- for (i = 2; i < m4_arg_argc (argv); i++)
- {
- fputc (' ', stderr);
- fwrite (M4ARG (i), 1, M4ARGLEN (i), stderr);
- }
- fflush (stderr);
-}
-
-
-/* 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 exitcode specified by the first argument, 0 if no
- arguments are present. */
-M4BUILTIN_HANDLER (m4exit)
-{
- const m4_call_info *me = m4_arg_info (argv);
- int exit_code = EXIT_SUCCESS;
-
- /* Warn on bad arguments, but still exit. */
- if (argc >= 2 && !m4_numeric_arg (context, me, M4ARG (1), M4ARGLEN (1),
- &exit_code))
- exit_code = EXIT_FAILURE;
- if (exit_code < 0 || exit_code > 255)
- {
- m4_warn (context, 0, me, _("exit status out of range: `%d'"), exit_code);
- exit_code = EXIT_FAILURE;
- }
-
- /* Ensure that atexit handlers see correct nonzero status. */
- if (exit_code != EXIT_SUCCESS)
- m4_set_exit_failure (exit_code);
-
- /* Change debug stream back to stderr, to force flushing debug
- stream and detect any errors. */
- m4_debug_set_output (context, me, NULL);
- m4_sysval_flush (context, true);
-
- /* Check for saved error. */
- if (exit_code == 0 && m4_get_exit_status (context) != 0)
- exit_code = m4_get_exit_status (context);
- 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. */
-M4BUILTIN_HANDLER (m4wrap)
-{
- m4_wrap_args (context, argv);
-}
-
-/* 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. */
-
-M4BUILTIN_HANDLER (traceon)
-{
- const m4_call_info *me = m4_arg_info (argv);
- size_t i;
-
- if (argc == 1)
- m4_set_debug_level_opt (context, (m4_get_debug_level_opt (context)
- | M4_DEBUG_TRACE_ALL));
- else
- for (i = 1; i < argc; i++)
- if (m4_is_arg_text (argv, i))
- m4_set_symbol_name_traced (M4SYMTAB, M4ARG (i), M4ARGLEN (i), true);
- else
- m4_warn (context, 0, me, _("invalid macro name ignored"));
-}
-
-/* Disable tracing of all specified macros, or all, if none is specified. */
-M4BUILTIN_HANDLER (traceoff)
-{
- const m4_call_info *me = m4_arg_info (argv);
- size_t i;
-
- if (argc == 1)
- m4_set_debug_level_opt (context, (m4_get_debug_level_opt (context)
- & ~M4_DEBUG_TRACE_ALL));
- else
- for (i = 1; i < argc; i++)
- if (m4_is_arg_text (argv, i))
- m4_set_symbol_name_traced (M4SYMTAB, M4ARG (i), M4ARGLEN (i), false);
- else
- m4_warn (context, 0, me, _("invalid macro name ignored"));
-}
-
-
-/* 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. */
-M4BUILTIN_HANDLER (len)
-{
- m4_shipout_int (obs, M4ARGLEN (1));
-}
-
-/* The macro expands to the first index of the second argument in the
- first argument. As an extension, start the search at the index
- indicated by the third argument. */
-M4BUILTIN_HANDLER (index)
-{
- const char *haystack = M4ARG (1);
- size_t haystack_len = M4ARGLEN (1);
- const char *needle = M4ARG (2);
- const char *result = NULL;
- int offset = 0;
- int retval = -1;
-
- if (!m4_arg_empty (argv, 3) && !m4_numeric_arg (context, m4_arg_info (argv),
- M4ARG (3), M4ARGLEN (3),
- &offset))
- return;
- if (offset < 0)
- {
- offset += haystack_len;
- if (offset < 0)
- offset = 0;
- }
- else if (haystack_len < offset)
- {
- m4_shipout_int (obs, -1);
- return;
- }
-
- /* Rely on the optimizations guaranteed by gnulib's memmem
- module. */
- result = (char *) memmem (haystack + offset, haystack_len - offset, needle,
- M4ARGLEN (2));
- if (result)
- retval = result - haystack;
-
- m4_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 or empty, the substring extends to the end of the first
- argument. As an extension, negative arguments are treated as
- indices relative to the string length. Also, if a fourth argument
- is supplied, the original string is output with the selected
- substring replaced by the argument. */
-M4BUILTIN_HANDLER (substr)
-{
- const m4_call_info *me = m4_arg_info (argv);
- const char *str = M4ARG (1);
- int start = 0;
- int end;
- int length;
-
- if (argc <= 2)
- {
- m4_push_arg (context, obs, argv, 1);
- return;
- }
-
- length = M4ARGLEN (1);
- if (!m4_arg_empty (argv, 2)
- && !m4_numeric_arg (context, me, M4ARG (2), M4ARGLEN (2), &start))
- return;
- if (start < 0)
- start += length;
-
- if (m4_arg_empty (argv, 3))
- end = length;
- else
- {
- if (!m4_numeric_arg (context, me, M4ARG (3), M4ARGLEN (3), &end))
- return;
- if (end < 0)
- end += length;
- else
- end += start;
- }
-
- if (5 <= argc)
- {
- /* Replacement text provided. */
- if (end < start)
- end = start;
- if (end < 0 || length < start)
- {
- m4_warn (context, 0, me, _("substring out of range"));
- return;
- }
- if (start < 0)
- start = 0;
- if (length < end)
- end = length;
- obstack_grow (obs, str, start);
- m4_push_arg (context, obs, argv, 4);
- obstack_grow (obs, str + end, length - end);
- return;
- }
-
- if (start < 0)
- start = 0;
- if (length < end)
- end = length;
- if (end <= start)
- return;
-
- obstack_grow (obs, str + start, end - start);
-}
-
-
-/* Any ranges in string S of length *LEN are expanded, using OBS for
- scratch space, and the expansion returned. *LEN is set to the
- expanded length. 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. */
-const char *
-m4_expand_ranges (const char *s, size_t *len, m4_obstack *obs)
-{
- unsigned char from;
- unsigned char to;
- const char *end = s + *len;
-
- assert (obstack_object_size (obs) == 0);
- assert (s != end);
- from = *s++;
- obstack_1grow (obs, from);
-
- for ( ; s != end; from = *s++)
- {
- if (*s == '-')
- {
- if (++s == end)
- {
- /* trailing dash */
- obstack_1grow (obs, '-');
- break;
- }
- to = *s;
- if (from <= to)
- {
- while (from++ < to)
- obstack_1grow (obs, from);
- }
- else
- {
- while (--from >= to)
- obstack_1grow (obs, from);
- }
- }
- else
- obstack_1grow (obs, *s);
- }
- *len = obstack_object_size (obs);
- 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. */
-M4BUILTIN_HANDLER (translit)
-{
- const char *data;
- const char *from;
- const char *to;
- size_t from_len;
- size_t to_len;
- char map[UCHAR_MAX + 1];
- char found[UCHAR_MAX + 1];
- unsigned char ch;
-
- enum { ASIS, REPLACE, DELETE };
-
- if (m4_arg_empty (argv, 1) || m4_arg_empty (argv, 2))
- {
- m4_push_arg (context, obs, argv, 1);
- return;
- }
-
- from = M4ARG (2);
- from_len = M4ARGLEN (2);
-
- to = M4ARG (3);
- to_len = M4ARGLEN (3);
- if (memchr (to, '-', to_len) != NULL)
- to = m4_expand_ranges (to, &to_len, m4_arg_scratch (context));
-
- /* 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_len <= 2)
- {
- const char *p;
- size_t len = M4ARGLEN (1);
- int second = from[from_len / 2];
- data = M4ARG (1);
- while ((p = (char *) memchr2 (data, from[0], second, len)))
- {
- obstack_grow (obs, data, p - data);
- len -= p - data + 1;
- data = p + 1;
- if (*p == from[0] && to_len)
- obstack_1grow (obs, to[0]);
- else if (*p == second && 1 < to_len)
- obstack_1grow (obs, to[1]);
- }
- obstack_grow (obs, data, len);
- return;
- }
-
- if (memchr (from, '-', from_len) != NULL)
- from = m4_expand_ranges (from, &from_len, m4_arg_scratch (context));
-
- /* Calling memchr(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);
- while (from_len--)
- {
- ch = *from++;
- if (found[ch] == ASIS)
- {
- if (to_len)
- {
- found[ch] = REPLACE;
- map[ch] = *to;
- }
- else
- found[ch] = DELETE;
- }
- if (to_len)
- {
- to++;
- to_len--;
- }
- }
-
- data = M4ARG (1);
- from_len = M4ARGLEN (1);
- while (from_len--)
- {
- ch = *data++;
- switch (found[ch])
- {
- case ASIS:
- obstack_1grow (obs, ch);
- break;
- case REPLACE:
- obstack_1grow (obs, map[ch]);
- break;
- case DELETE:
- break;
- default:
- assert (!"translit");
- abort ();
- }
- }
-}
-
-
-
-/* The rest of this file contains the functions to evaluate integer
- * expressions for the "eval" macro. `number' should be at least 32 bits.
- */
-#define numb_set(ans, x) ((ans) = (x))
-#define numb_set_si(ans, si) (*(ans) = (number) (si))
-
-#define numb_ZERO ((number) 0)
-#define numb_ONE ((number) 1)
-
-#define numb_init(x) ((x) = numb_ZERO)
-#define numb_fini(x)
-
-#define numb_incr(n) ((n) += numb_ONE)
-#define numb_decr(n) ((n) -= numb_ONE)
-
-#define numb_zerop(x) ((x) == numb_ZERO)
-#define numb_positivep(x) ((x) > numb_ZERO)
-#define numb_negativep(x) ((x) < numb_ZERO)
-
-#define numb_eq(x, y) ((x) = ((x) == (y)))
-#define numb_ne(x, y) ((x) = ((x) != (y)))
-#define numb_lt(x, y) ((x) = ((x) < (y)))
-#define numb_le(x, y) ((x) = ((x) <= (y)))
-#define numb_gt(x, y) ((x) = ((x) > (y)))
-#define numb_ge(x, y) ((x) = ((x) >= (y)))
-
-#define numb_lnot(x) ((x) = (!(x)))
-#define numb_lior(x, y) ((x) = ((x) || (y)))
-#define numb_land(x, y) ((x) = ((x) && (y)))
-
-#define numb_not(c, x) (*(x) = ~ *(x))
-#define numb_eor(c, x, y) (*(x) = *(x) ^ *(y))
-#define numb_ior(c, x, y) (*(x) = *(x) | *(y))
-#define numb_and(c, x, y) (*(x) = *(x) & *(y))
-
-#define numb_plus(x, y) ((x) = ((x) + (y)))
-#define numb_minus(x, y) ((x) = ((x) - (y)))
-#define numb_negate(x) ((x) = (- (x)))
-
-#define numb_times(x, y) ((x) = ((x) * (y)))
-/* Be careful of x86 SIGFPE. */
-#define numb_ratio(x, y) \
- (((y) == -1) ? (numb_negate (x)) : ((x) /= (y)))
-#define numb_divide(x, y) \
- ((*(y) == -1) ? (numb_negate (*(y))) : (*(x) /= *(y)))
-#define numb_modulo(c, x, y) \
- ((*(y) == -1) ? (*(x) = numb_ZERO) : (*(x) %= *(y)))
-/* numb_invert is only used in the context of x**-y, which integral math
- does not support. */
-#define numb_invert(x) return NEGATIVE_EXPONENT
-
-/* 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 wrap-around semantics,
- with implicit masking of shift amount. This code assumes that the
- implementation-defined overflow when casting unsigned to signed is
- a silent twos-complement wrap-around. */
-#define shift_mask (sizeof (number) * CHAR_BIT - 1)
-#define numb_lshift(c, x, y) \
- (*(x) = (number) ((unumber) *(x) << (*(y) & shift_mask)))
-#define numb_rshift(c, x, y) \
- (*(x) = (number) (*(x) < 0 \
- ? ~(~(unumber) *(x) >> (*(y) & shift_mask)) \
- : (unumber) *(x) >> (*(y) & shift_mask)))
-#define numb_urshift(c, x, y) \
- (*(x) = (number) ((unumber) *(x) >> (*(y) & shift_mask)))
-
-
-/* The function ntoa () converts VALUE to a signed ASCII representation in
- radix RADIX. Radix must be between 2 and 36, inclusive. */
-static const char *
-ntoa (number value, int radix)
-{
- /* Digits for number to ASCII conversions. */
- static char const ntoa_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-
- bool negative;
- unumber uvalue;
- /* Sized for radix 2, plus sign and trailing NUL. */
- static char str[sizeof value * CHAR_BIT + 2];
- char *s = &str[sizeof str];
-
- *--s = '\0';
-
- if (value < 0)
- {
- negative = true;
- uvalue = (unumber) -value;
- }
- else
- {
- negative = false;
- uvalue = (unumber) value;
- }
-
- do
- {
- *--s = ntoa_digits[uvalue % radix];
- uvalue /= radix;
- }
- while (uvalue > 0);
-
- if (negative)
- *--s = '-';
- return s;
-}
-
-static void
-numb_obstack (m4_obstack *obs, number value, int radix, int min)
-{
- const char *s;
- size_t len;
- unumber uvalue;
-
- if (radix == 1)
- {
- if (value < 0)
- {
- obstack_1grow (obs, '-');
- uvalue = -value;
- }
- else
- uvalue = value;
- if (uvalue < min)
- {
- obstack_blank (obs, min - uvalue);
- memset ((char *) obstack_next_free (obs) - (min - uvalue), '0',
- min - uvalue);
- }
- obstack_blank (obs, uvalue);
- memset ((char *) obstack_next_free (obs) - uvalue, '1', uvalue);
- return;
- }
-
- s = ntoa (value, radix);
-
- if (*s == '-')
- {
- obstack_1grow (obs, '-');
- s++;
- }
- len = strlen (s);
- if (len < min)
- {
- min -= len;
- obstack_blank (obs, min);
- memset ((char *) obstack_next_free (obs) - min, '0', min);
- }
- obstack_grow (obs, s, len);
-}
-
-
-static void
-numb_initialise (void)
-{
- ;
-}
-
-/* This macro defines the top level code for the "eval" builtin. The
- actual work is done in the function m4_evaluate (), which lives in
- evalparse.c. */
-#define m4_evaluate builtin_eval
-#include "evalparse.c"