diff options
Diffstat (limited to 'modules/format.c')
-rw-r--r-- | modules/format.c | 425 |
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); -} |