summaryrefslogtreecommitdiff
path: root/modules/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/format.c')
-rw-r--r--modules/format.c425
1 files changed, 0 insertions, 425 deletions
diff --git a/modules/format.c b/modules/format.c
deleted file mode 100644
index 2c87fcc3..00000000
--- a/modules/format.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/* GNU m4 -- A simple macro processor
- Copyright (C) 1989-1994, 2001, 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/>.
-*/
-
-/* printf like formatting for m4. */
-
-#include "vasnprintf.h"
-
-/* Simple varargs substitute. We assume int and unsigned int are the
- same size; likewise for long and unsigned long. We do not yet
- handle long double or long long. */
-
-/* Parse STR of length LEN as an integer, reporting warnings on behalf
- of ME. */
-static int
-arg_int (struct m4 *context, const m4_call_info *me, const char *str,
- size_t len)
-{
- char *endp;
- long value;
-
- /* TODO - also allow parsing `'a' or `"a' which results in the
- numeric value of 'a', as in printf(1). */
- if (!len)
- {
- m4_warn (context, 0, me, _("empty string treated as 0"));
- return 0;
- }
- errno = 0;
- value = strtol (str, &endp, 10);
- if (endp - str != len)
- m4_warn (context, 0, me, _("non-numeric argument %s"),
- quotearg_style_mem (locale_quoting_style, str, len));
- else if (isspace (to_uchar (*str)))
- m4_warn (context, 0, me, _("leading whitespace ignored"));
- else if (errno == ERANGE || (int) value != value)
- m4_warn (context, 0, me, _("numeric overflow detected"));
- return value;
-}
-
-/* Parse STR of length LEN as a long, reporting warnings on behalf of
- ME. */
-static long
-arg_long (struct m4 *context, const m4_call_info *me, const char *str,
- size_t len)
-{
- char *endp;
- long value;
-
- /* TODO - also allow parsing `'a' or `"a' which results in the
- numeric value of 'a', as in printf(1). */
- if (!len)
- {
- m4_warn (context, 0, me, _("empty string treated as 0"));
- return 0L;
- }
- errno = 0;
- value = strtol (str, &endp, 10);
- if (endp - str != len)
- m4_warn (context, 0, me, _("non-numeric argument %s"),
- quotearg_style_mem (locale_quoting_style, str, len));
- else if (isspace (to_uchar (*str)))
- m4_warn (context, 0, me, _("leading whitespace ignored"));
- else if (errno == ERANGE)
- m4_warn (context, 0, me, _("numeric overflow detected"));
- return value;
-}
-
-/* Check STR of length LEN for embedded NUL, reporting warnings on
- behalf of ME. */
-static const char *
-arg_string (struct m4 *context, const m4_call_info *me, const char *str,
- size_t len)
-{
- if (strlen (str) < len)
- m4_warn (context, 0, me, _("argument %s truncated"),
- quotearg_style_mem (locale_quoting_style, str, len));
- return str;
-}
-
-/* Parse STR of length LEN as a double, reporting warnings on behalf
- of ME. */
-static double
-arg_double (struct m4 *context, const m4_call_info *me, const char *str,
- size_t len)
-{
- char *endp;
- double value;
-
- if (!len)
- {
- m4_warn (context, 0, me, _("empty string treated as 0"));
- return 0.0;
- }
- errno = 0;
- value = strtod (str, &endp);
- if (endp - str != len)
- m4_warn (context, 0, me, _("non-numeric argument %s"),
- quotearg_style_mem (locale_quoting_style, str, len));
- else if (isspace (to_uchar (*str)))
- m4_warn (context, 0, me, _("leading whitespace ignored"));
- else if (errno == ERANGE)
- m4_warn (context, 0, me, _("numeric overflow detected"));
- return value;
-}
-
-#define ARG_INT(i, argc, argv) \
- ((argc <= ++i) ? 0 : arg_int (context, me, M4ARG (i), M4ARGLEN (i)))
-
-#define ARG_LONG(i, argc, argv) \
- ((argc <= ++i) ? 0L : arg_long (context, me, M4ARG (i), M4ARGLEN (i)))
-
-#define ARG_STR(i, argc, argv) \
- ((argc <= ++i) ? "" : arg_string (context, me, M4ARG (i), M4ARGLEN (i)))
-
-#define ARG_DOUBLE(i, argc, argv) \
- ((argc <= ++i) ? 0.0 : arg_double (context, me, M4ARG (i), M4ARGLEN (i)))
-
-
-/* The main formatting function. Output is placed on the obstack OBS,
- the first argument in ARGV is the formatting string, and the rest
- is arguments for the string. Warn rather than invoke unspecified
- behavior in the underlying printf when we do not recognize a
- format. */
-
-static void
-format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv)
-{
- const m4_call_info *me = m4_arg_info (argv);
- const char *f; /* Format control string. */
- size_t f_len; /* Length of f. */
- const char *fmt; /* Position within f. */
- char fstart[] = "%'+- 0#*.*hhd"; /* Current format spec. */
- char *p; /* Position within fstart. */
- unsigned char c; /* A simple character. */
- int i = 1; /* Index within argc used so far. */
- bool valid_format = true; /* True if entire format string ok. */
-
- /* Flags. */
- char flags; /* Flags to use in fstart. */
- enum {
- THOUSANDS = 0x01, /* '\''. */
- PLUS = 0x02, /* '+'. */
- MINUS = 0x04, /* '-'. */
- SPACE = 0x08, /* ' '. */
- ZERO = 0x10, /* '0'. */
- ALT = 0x20, /* '#'. */
- DONE = 0x40 /* No more flags. */
- };
-
- /* Precision specifiers. */
- int width; /* Minimum field width. */
- int prec; /* Precision. */
- char lflag; /* Long flag. */
-
- /* Specifiers we are willing to accept. ok['x'] implies %x is ok.
- Various modifiers reduce the set, in order to avoid undefined
- behavior in printf. */
- char ok[128];
-
- /* Check that formatted text succeeded with correct type. */
- int result = 0;
- enum {CHAR, INT, LONG, DOUBLE, STR} datatype;
-
- f = fmt = M4ARG (1);
- f_len = M4ARGLEN (1);
- assert (!f[f_len]); /* Requiring a terminating NUL makes parsing simpler. */
- memset (ok, 0, sizeof ok);
- while (1)
- {
- const char *percent = (char *) memchr (fmt, '%', f_len);
- if (!percent)
- {
- obstack_grow (obs, fmt, f_len);
- break;
- }
- obstack_grow (obs, fmt, percent - fmt);
- f_len -= percent - fmt + 1;
- fmt = percent + 1;
-
- if (*fmt == '%')
- {
- obstack_1grow (obs, '%');
- fmt++;
- f_len--;
- continue;
- }
-
- p = fstart + 1; /* % */
- lflag = 0;
- ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E']
- = ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o']
- = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1;
-
- /* Parse flags. */
- flags = 0;
- do
- {
- switch (*fmt)
- {
- case '\'': /* thousands separator */
- ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E']
- = ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0;
- flags |= THOUSANDS;
- break;
-
- case '+': /* mandatory sign */
- ok['c'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 0;
- flags |= PLUS;
- break;
-
- case ' ': /* space instead of positive sign */
- ok['c'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 0;
- flags |= SPACE;
- break;
-
- case '0': /* zero padding */
- ok['c'] = ok['s'] = 0;
- flags |= ZERO;
- break;
-
- case '#': /* alternate output */
- ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0;
- flags |= ALT;
- break;
-
- case '-': /* left justification */
- flags |= MINUS;
- break;
-
- default:
- flags |= DONE;
- break;
- }
- }
- while (!(flags & DONE) && (f_len--, fmt++));
- if (flags & THOUSANDS)
- *p++ = '\'';
- if (flags & PLUS)
- *p++ = '+';
- if (flags & MINUS)
- *p++ = '-';
- if (flags & SPACE)
- *p++ = ' ';
- if (flags & ZERO)
- *p++ = '0';
- if (flags & ALT)
- *p++ = '#';
-
- /* Minimum field width; an explicit 0 is the same as not giving
- the width. */
- width = 0;
- *p++ = '*';
- if (*fmt == '*')
- {
- width = ARG_INT (i, argc, argv);
- fmt++;
- f_len--;
- }
- else
- while (isdigit ((unsigned char) *fmt))
- {
- width = 10 * width + *fmt - '0';
- fmt++;
- f_len--;
- }
-
- /* Maximum precision; an explicit negative precision is the same
- as not giving the precision. A lone '.' is a precision of 0. */
- prec = -1;
- *p++ = '.';
- *p++ = '*';
- if (*fmt == '.')
- {
- ok['c'] = 0;
- f_len--;
- if (*(++fmt) == '*')
- {
- prec = ARG_INT (i, argc, argv);
- ++fmt;
- f_len--;
- }
- else
- {
- prec = 0;
- while (isdigit ((unsigned char) *fmt))
- {
- prec = 10 * prec + *fmt - '0';
- fmt++;
- f_len--;
- }
- }
- }
-
- /* Length modifiers. We don't yet recognize ll, j, t, or z. */
- if (*fmt == 'l')
- {
- *p++ = 'l';
- lflag = 1;
- fmt++;
- f_len--;
- ok['c'] = ok['s'] = 0;
- }
- else if (*fmt == 'h')
- {
- *p++ = 'h';
- fmt++;
- f_len--;
- if (*fmt == 'h')
- {
- *p++ = 'h';
- fmt++;
- f_len--;
- }
- ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = ok['f'] = ok['F']
- = ok['g'] = ok['G'] = ok['s'] = 0;
- }
-
- c = *fmt;
- if (sizeof ok <= c || !ok[c] || !f_len)
- {
- m4_warn (context, 0, me, _("unrecognized specifier in %s"),
- quotearg_style_mem (locale_quoting_style, f, M4ARGLEN (1)));
- valid_format = false;
- if (f_len > 0)
- {
- fmt++;
- f_len--;
- }
- continue;
- }
- fmt++;
- f_len--;
-
- /* Specifiers. We don't yet recognize C, S, n, or p. */
- switch (c)
- {
- case 'c':
- datatype = CHAR;
- p -= 2; /* %.*c is undefined, so undo the '.*'. */
- break;
-
- case 's':
- datatype = STR;
- break;
-
- case 'd':
- case 'i':
- case 'o':
- case 'x':
- case 'X':
- case 'u':
- datatype = lflag ? LONG : INT;
- break;
-
- case 'a':
- case 'A':
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- datatype = DOUBLE;
- break;
-
- default:
- abort ();
- }
- *p++ = c;
- *p = '\0';
-
- switch (datatype)
- {
- case CHAR:
- result = obstack_printf (obs, fstart, width,
- ARG_INT (i, argc, argv));
- break;
-
- case INT:
- result = obstack_printf (obs, fstart, width, prec,
- ARG_INT (i, argc, argv));
- break;
-
- case LONG:
- result = obstack_printf (obs, fstart, width, prec,
- ARG_LONG (i, argc, argv));
- break;
-
- case DOUBLE:
- result = obstack_printf (obs, fstart, width, prec,
- ARG_DOUBLE (i, argc, argv));
- break;
-
- case STR:
- result = obstack_printf (obs, fstart, width, prec,
- ARG_STR (i, argc, argv));
- break;
-
- default:
- abort ();
- }
- /* Since obstack_printf can only fail with EILSEQ or EINVAL, but
- we constructed fstart, the result should not be negative. */
- assert (0 <= result);
- }
- if (valid_format)
- m4_bad_argc (context, argc, me, i, i, true);
-}