[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Changes to m4/src/Attic/format.c,v [branch-1_4]
From: |
Eric Blake |
Subject: |
Changes to m4/src/Attic/format.c,v [branch-1_4] |
Date: |
Tue, 29 May 2007 13:19:49 +0000 |
CVSROOT: /sources/m4
Module name: m4
Branch: branch-1_4
Changes by: Eric Blake <ericb> 07/05/29 13:19:48
Index: src/format.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/format.c,v
retrieving revision 1.1.1.1.2.6
retrieving revision 1.1.1.1.2.7
diff -u -b -r1.1.1.1.2.6 -r1.1.1.1.2.7
--- src/format.c 26 Oct 2006 21:11:56 -0000 1.1.1.1.2.6
+++ src/format.c 29 May 2007 13:19:47 -0000 1.1.1.1.2.7
@@ -1,6 +1,6 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006
+ Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
@@ -24,24 +24,17 @@
#include "m4.h"
#include "xvasprintf.h"
-/* Simple varargs substitute. */
+/* Simple varargs substitute. We assume int and unsigned int are the
+ same size; likewise for long and unsigned long. */
#define ARG_INT(argc, argv) \
((argc == 0) ? 0 : \
(--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1]))))
-#define ARG_UINT(argc, argv) \
- ((argc == 0) ? 0 : \
- (--argc, argv++, (unsigned int) atoi (TOKEN_DATA_TEXT (argv[-1]))))
-
#define ARG_LONG(argc, argv) \
((argc == 0) ? 0 : \
(--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1]))))
-#define ARG_ULONG(argc, argv) \
- ((argc == 0) ? 0 : \
- (--argc, argv++, (unsigned long) atol (TOKEN_DATA_TEXT (argv[-1]))))
-
#define ARG_STR(argc, argv) \
((argc == 0) ? "" : \
(--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
@@ -51,44 +44,60 @@
(--argc, argv++, atof (TOKEN_DATA_TEXT (argv[-1]))))
-/*------------------------------------------------------------------------.
-| The main formatting function. Output is placed on the obstack OBS, the |
-| first argument in ARGV is the formatting string, and the rest is |
-| arguments for the string. |
-`------------------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| The main formatting function. Output is placed on the obstack |
+| OBS, the first argument in ARGV is the formatting string, and the |
+| rest is arguments for the string. Warn rather than invoke |
+| unspecified behavior in the underlying printf when we do not |
+| recognize a format. |
+`------------------------------------------------------------------*/
void
format (struct obstack *obs, int argc, token_data **argv)
{
- char *fmt; /* format control string */
- const char *fstart; /* beginning of current format spec */
- int c; /* a simple character */
+ const char *f; /* format control string */
+ const char *fmt; /* position within f */
+ char fstart[] = "%'+- 0#*.*hhd"; /* current format spec */
+ char *p; /* position within fstart */
+ unsigned char c; /* a simple character */
/* Flags. */
- char flags; /* 1 iff treating 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 */
- char hflag; /* short flag */
+
+ /* Specifiers we are willing to accept. ok['x'] implies %x is ok.
+ Various modifiers reduce the set, in order to avoid undefined
+ behavior in printf. */
+ char ok[128];
/* Buffer and stuff. */
char *str; /* malloc'd buffer of formatted text */
- enum {INT, UINT, LONG, ULONG, DOUBLE, STR} datatype;
+ enum {INT, LONG, DOUBLE, STR} datatype;
- fmt = (char *) ARG_STR (argc, argv);
+ f = fmt = (const char *) ARG_STR (argc, argv);
+ memset (ok, 0, sizeof ok);
for (;;)
{
while ((c = *fmt++) != '%')
{
- if (c == 0)
+ if (c == '\0')
return;
obstack_1grow (obs, c);
}
- fstart = fmt - 1;
-
if (*fmt == '%')
{
obstack_1grow (obs, '%');
@@ -96,73 +105,145 @@
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 = 1;
+ flags = 0;
do
{
switch (*fmt)
{
- case '-': /* left justification */
+ 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 = 0;
+ flags |= DONE;
break;
}
}
- while (flags && fmt++);
-
- /* Minimum field width. */
- width = -1;
+ while (!(flags & DONE) && fmt++);
+ if (flags & THOUSANDS)
+ *p++ = '\'';
+ if (flags & PLUS)
+ *p++ = '+';
+ if (flags & MINUS)
+ *p++ = '-';
+ if (flags & SPACE)
+ *p++ = ' ';
+ if (flags & ZERO)
+ *p++ = '0';
+ if (flags & ALT)
+ *p++ = '#';
+
+ /* Minimum field width; an explicit 0 is the same as not giving
+ the width. */
+ width = 0;
+ *p++ = '*';
if (*fmt == '*')
{
width = ARG_INT (argc, argv);
fmt++;
}
- else if (isdigit (to_uchar (*fmt)))
+ else
{
- do
+ while (isdigit (to_uchar (*fmt)))
{
+ width = 10 * width + *fmt - '0';
fmt++;
}
- while (isdigit (to_uchar (*fmt)));
}
- /* Maximum precision. */
+ /* Maximum precision; an explicit negative precision is the same
+ as not giving the precision. A lone '.' is a precision of 0. */
prec = -1;
+ *p++ = '.';
+ *p++ = '*';
if (*fmt == '.')
{
+ ok['c'] = 0;
if (*(++fmt) == '*')
{
prec = ARG_INT (argc, argv);
++fmt;
}
- else if (isdigit (to_uchar (*fmt)))
+ else
{
- do
+ prec = 0;
+ while (isdigit (to_uchar (*fmt)))
{
+ prec = 10 * prec + *fmt - '0';
fmt++;
}
- while (isdigit (to_uchar (*fmt)));
}
}
- /* Length modifiers. */
- lflag = (*fmt == 'l');
- hflag = (*fmt == 'h');
- if (lflag || hflag)
+ /* Length modifiers. We don't yet recognize ll, j, t, or z. */
+ if (*fmt == 'l')
+ {
+ *p++ = 'l';
+ lflag = 1;
fmt++;
-
- switch (*fmt++)
+ ok['c'] = ok['s'] = 0;
+ }
+ else if (*fmt == 'h')
{
+ *p++ = 'h';
+ fmt++;
+ if (*fmt == 'h')
+ {
+ *p++ = 'h';
+ fmt++;
+ }
+ ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = ok['f'] = ok['F']
+ = ok['g'] = ok['G'] = ok['s'] = 0;
+ }
- case '\0':
- return;
+ c = *fmt++;
+ if (c > sizeof ok || !ok[c])
+ {
+ M4ERROR ((warning_status, 0,
+ "Warning: unrecognized specifier in `%s'", f));
+ if (c == '\0')
+ fmt--;
+ continue;
+ }
+ *p++ = c;
+ *p = '\0';
+ /* Specifiers. We don't yet recognize C, S, n, or p. */
+ switch (c)
+ {
case 'c':
datatype = INT;
break;
@@ -173,30 +254,15 @@
case 'd':
case 'i':
- if (lflag)
- {
- datatype = LONG;
- }
- else
- {
- datatype = INT;
- }
- break;
-
case 'o':
case 'x':
case 'X':
case 'u':
- if (lflag)
- {
- datatype = ULONG;
- }
- else
- {
- datatype = UINT;
- }
+ datatype = lflag ? LONG : INT;
break;
+ case 'a':
+ case 'A':
case 'e':
case 'E':
case 'f':
@@ -207,86 +273,31 @@
break;
default:
- continue;
+ abort ();
}
- c = *fmt;
- *fmt = '\0';
-
switch(datatype)
{
case INT:
- if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_INT(argc, argv));
- else if (width != -1)
- str = xasprintf (fstart, width, ARG_INT(argc, argv));
- else if (prec != -1)
- str = xasprintf (fstart, prec, ARG_INT(argc, argv));
- else
- str = xasprintf (fstart, ARG_INT(argc, argv));
- break;
-
- case UINT:
- if (width != -1 && prec != -1)
- str = xasprintf (fstart, width, prec, ARG_UINT(argc, argv));
- else if (width != -1)
- str = xasprintf (fstart, width, ARG_UINT(argc, argv));
- else if (prec != -1)
- str = xasprintf (fstart, prec, ARG_UINT(argc, argv));
- else
- str = xasprintf (fstart, ARG_UINT(argc, argv));
break;
case LONG:
- if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv));
- else if (width != -1)
- str = xasprintf (fstart, width, ARG_LONG(argc, argv));
- else if (prec != -1)
- str = xasprintf (fstart, prec, ARG_LONG(argc, argv));
- else
- str = xasprintf (fstart, ARG_LONG(argc, argv));
- break;
-
- case ULONG:
- if (width != -1 && prec != -1)
- str = xasprintf (fstart, width, prec, ARG_ULONG(argc, argv));
- else if (width != -1)
- str = xasprintf (fstart, width, ARG_ULONG(argc, argv));
- else if (prec != -1)
- str = xasprintf (fstart, prec, ARG_ULONG(argc, argv));
- else
- str = xasprintf (fstart, ARG_ULONG(argc, argv));
break;
case DOUBLE:
- if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv));
- else if (width != -1)
- str = xasprintf (fstart, width, ARG_DOUBLE(argc, argv));
- else if (prec != -1)
- str = xasprintf (fstart, prec, ARG_DOUBLE(argc, argv));
- else
- str = xasprintf (fstart, ARG_DOUBLE(argc, argv));
break;
case STR:
- if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_STR(argc, argv));
- else if (width != -1)
- str = xasprintf (fstart, width, ARG_STR(argc, argv));
- else if (prec != -1)
- str = xasprintf (fstart, prec, ARG_STR(argc, argv));
- else
- str = xasprintf (fstart, ARG_STR(argc, argv));
break;
default:
abort();
}
- *fmt = c;
-
/* NULL was returned on failure, such as invalid format string. For
now, just silently ignore that bad specifier. */
if (str == NULL)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Changes to m4/src/Attic/format.c,v [branch-1_4],
Eric Blake <=