1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007
4 Free Software Foundation, Inc.
6 This file is part of GNU M4.
8 GNU M4 is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU M4 is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* printf like formatting for m4. */
25 #include "xvasprintf.h"
27 /* Simple varargs substitute. We assume int and unsigned int are the
28 same size; likewise for long and unsigned long. */
30 #define ARG_INT(argc, argv) \
32 (--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1]))))
34 #define ARG_LONG(argc, argv) \
36 (--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1]))))
38 #define ARG_STR(argc, argv) \
40 (--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
42 #define ARG_DOUBLE(argc, argv) \
44 (--argc, argv++, atof (TOKEN_DATA_TEXT (argv[-1]))))
47 /*------------------------------------------------------------------.
48 | The main formatting function. Output is placed on the obstack |
49 | OBS, the first argument in ARGV is the formatting string, and the |
50 | rest is arguments for the string. Warn rather than invoke |
51 | unspecified behavior in the underlying printf when we do not |
52 | recognize a format. |
53 `------------------------------------------------------------------*/
56 format (struct obstack
*obs
, int argc
, token_data
**argv
)
58 const char *me
= TOKEN_DATA_TEXT (argv
[0]);
59 const char *f
; /* format control string */
60 const char *fmt
; /* position within f */
61 char fstart
[] = "%'+- 0#*.*hhd"; /* current format spec */
62 char *p
; /* position within fstart */
63 unsigned char c
; /* a simple character */
66 char flags
; /* flags to use in fstart */
68 THOUSANDS
= 0x01, /* ' */
74 DONE
= 0x40 /* no more flags */
77 /* Precision specifiers. */
78 int width
; /* minimum field width */
79 int prec
; /* precision */
80 char lflag
; /* long flag */
82 /* Specifiers we are willing to accept. ok['x'] implies %x is ok.
83 Various modifiers reduce the set, in order to avoid undefined
84 behavior in printf. */
87 /* Buffer and stuff. */
88 char *str
; /* malloc'd buffer of formatted text */
89 enum {CHAR
, INT
, LONG
, DOUBLE
, STR
} datatype
;
93 f
= fmt
= ARG_STR (argc
, argv
);
94 memset (ok
, 0, sizeof ok
);
97 while ((c
= *fmt
++) != '%')
101 obstack_1grow (obs
, c
);
106 obstack_1grow (obs
, '%');
111 p
= fstart
+ 1; /* % */
113 ok
['a'] = ok
['A'] = ok
['c'] = ok
['d'] = ok
['e'] = ok
['E']
114 = ok
['f'] = ok
['F'] = ok
['g'] = ok
['G'] = ok
['i'] = ok
['o']
115 = ok
['s'] = ok
['u'] = ok
['x'] = ok
['X'] = 1;
123 case '\'': /* thousands separator */
124 ok
['a'] = ok
['A'] = ok
['c'] = ok
['e'] = ok
['E']
125 = ok
['o'] = ok
['s'] = ok
['x'] = ok
['X'] = 0;
129 case '+': /* mandatory sign */
130 ok
['c'] = ok
['o'] = ok
['s'] = ok
['u'] = ok
['x'] = ok
['X'] = 0;
134 case ' ': /* space instead of positive sign */
135 ok
['c'] = ok
['o'] = ok
['s'] = ok
['u'] = ok
['x'] = ok
['X'] = 0;
139 case '0': /* zero padding */
140 ok
['c'] = ok
['s'] = 0;
144 case '#': /* alternate output */
145 ok
['c'] = ok
['d'] = ok
['i'] = ok
['s'] = ok
['u'] = 0;
149 case '-': /* left justification */
158 while (!(flags
& DONE
) && fmt
++);
159 if (flags
& THOUSANDS
)
172 /* Minimum field width; an explicit 0 is the same as not giving
178 width
= ARG_INT (argc
, argv
);
182 while (isdigit (to_uchar (*fmt
)))
184 width
= 10 * width
+ *fmt
- '0';
188 /* Maximum precision; an explicit negative precision is the same
189 as not giving the precision. A lone '.' is a precision of 0. */
198 prec
= ARG_INT (argc
, argv
);
204 while (isdigit (to_uchar (*fmt
)))
206 prec
= 10 * prec
+ *fmt
- '0';
212 /* Length modifiers. We don't yet recognize ll, j, t, or z. */
218 ok
['c'] = ok
['s'] = 0;
220 else if (*fmt
== 'h')
229 ok
['a'] = ok
['A'] = ok
['c'] = ok
['e'] = ok
['E'] = ok
['f'] = ok
['F']
230 = ok
['g'] = ok
['G'] = ok
['s'] = 0;
234 if (c
> sizeof ok
|| !ok
[c
])
236 m4_warn (0, me
, _("unrecognized specifier in `%s'"), f
);
242 /* Specifiers. We don't yet recognize C, S, n, or p. */
247 p
-= 2; /* %.*c is undefined, so undo the '.*'. */
260 datatype
= lflag
? LONG
: INT
;
283 str
= xasprintf (fstart
, width
, ARG_INT(argc
, argv
));
287 str
= xasprintf (fstart
, width
, prec
, ARG_INT(argc
, argv
));
291 str
= xasprintf (fstart
, width
, prec
, ARG_LONG(argc
, argv
));
295 str
= xasprintf (fstart
, width
, prec
, ARG_DOUBLE(argc
, argv
));
299 str
= xasprintf (fstart
, width
, prec
, ARG_STR(argc
, argv
));
306 /* NULL was returned on failure, such as invalid format string.
307 Issue a warning, then proceed. */
310 m4_warn (0, me
, _("unable to format output for `%s'"), f
);
314 obstack_grow (obs
, str
, strlen (str
));