1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1989-1994, 2006-2011 Free Software Foundation, Inc.
5 This file is part of GNU M4.
7 GNU M4 is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU M4 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 /* printf like formatting for m4. */
24 #include "xvasprintf.h"
26 /* Simple varargs substitute. We assume int and unsigned int are the
27 same size; likewise for long and unsigned long. */
29 /* Parse STR as an integer, reporting warnings. */
31 arg_int (const char *str)
35 size_t len = strlen (str);
39 M4ERROR ((warning_status, 0, _("empty string treated as 0")));
43 value = strtol (str, &endp, 10);
45 M4ERROR ((warning_status, 0, _("non-numeric argument %s"), str));
46 else if (isspace (to_uchar (*str)))
47 M4ERROR ((warning_status, 0, _("leading whitespace ignored")));
48 else if (errno == ERANGE || (int) value != value)
49 M4ERROR ((warning_status, 0, _("numeric overflow detected")));
53 /* Parse STR as a long, reporting warnings. */
55 arg_long (const char *str)
59 size_t len = strlen (str);
63 M4ERROR ((warning_status, 0, _("empty string treated as 0")));
67 value = strtol (str, &endp, 10);
69 M4ERROR ((warning_status, 0, _("non-numeric argument %s"), str));
70 else if (isspace (to_uchar (*str)))
71 M4ERROR ((warning_status, 0, _("leading whitespace ignored")));
72 else if (errno == ERANGE)
73 M4ERROR ((warning_status, 0, _("numeric overflow detected")));
77 /* Parse STR as a double, reporting warnings. */
79 arg_double (const char *str)
83 size_t len = strlen (str);
87 M4ERROR ((warning_status, 0, _("empty string treated as 0")));
91 value = strtod (str, &endp);
93 M4ERROR ((warning_status, 0, _("non-numeric argument %s"), str));
94 else if (isspace (to_uchar (*str)))
95 M4ERROR ((warning_status, 0, _("leading whitespace ignored")));
96 else if (errno == ERANGE)
97 M4ERROR ((warning_status, 0, _("numeric overflow detected")));
101 #define ARG_INT(argc, argv) \
103 (--argc, argv++, arg_int (TOKEN_DATA_TEXT (argv[-1]))))
105 #define ARG_LONG(argc, argv) \
107 (--argc, argv++, arg_long (TOKEN_DATA_TEXT (argv[-1]))))
109 #define ARG_STR(argc, argv) \
110 ((argc == 0) ? "" : \
111 (--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
113 #define ARG_DOUBLE(argc, argv) \
115 (--argc, argv++, arg_double (TOKEN_DATA_TEXT (argv[-1]))))
118 /*------------------------------------------------------------------.
119 | The main formatting function. Output is placed on the obstack |
120 | OBS, the first argument in ARGV is the formatting string, and the |
121 | rest is arguments for the string. Warn rather than invoke |
122 | unspecified behavior in the underlying printf when we do not |
123 | recognize a format. |
124 `------------------------------------------------------------------*/
127 expand_format (struct obstack *obs, int argc, token_data **argv)
129 const char *f; /* format control string */
130 const char *fmt; /* position within f */
131 char fstart[] = "%'+- 0#*.*hhd"; /* current format spec */
132 char *p; /* position within fstart */
133 unsigned char c; /* a simple character */
136 char flags; /* flags to use in fstart */
138 THOUSANDS = 0x01, /* ' */
140 MINUS = 0x04, /* - */
144 DONE = 0x40 /* no more flags */
147 /* Precision specifiers. */
148 int width; /* minimum field width */
149 int prec; /* precision */
150 char lflag; /* long flag */
152 /* Specifiers we are willing to accept. ok['x'] implies %x is ok.
153 Various modifiers reduce the set, in order to avoid undefined
154 behavior in printf. */
157 /* Buffer and stuff. */
158 char *str; /* malloc'd buffer of formatted text */
159 enum {CHAR, INT, LONG, DOUBLE, STR} datatype;
161 f = fmt = ARG_STR (argc, argv);
162 memset (ok, 0, sizeof ok);
165 const char *percent = strchr (fmt, '%');
168 obstack_grow (obs, fmt, strlen (fmt));
171 obstack_grow (obs, fmt, percent - fmt);
176 obstack_1grow (obs, '%');
181 p = fstart + 1; /* % */
183 ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E']
184 = ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o']
185 = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1;
193 case '\'': /* thousands separator */
194 ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E']
195 = ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0;
199 case '+': /* mandatory sign */
200 ok['c'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 0;
204 case ' ': /* space instead of positive sign */
205 ok['c'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 0;
209 case '0': /* zero padding */
210 ok['c'] = ok['s'] = 0;
214 case '#': /* alternate output */
215 ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0;
219 case '-': /* left justification */
228 while (!(flags & DONE) && fmt++);
229 if (flags & THOUSANDS)
242 /* Minimum field width; an explicit 0 is the same as not giving
248 width = ARG_INT (argc, argv);
252 while (isdigit (to_uchar (*fmt)))
254 width = 10 * width + *fmt - '0';
258 /* Maximum precision; an explicit negative precision is the same
259 as not giving the precision. A lone '.' is a precision of 0. */
268 prec = ARG_INT (argc, argv);
274 while (isdigit (to_uchar (*fmt)))
276 prec = 10 * prec + *fmt - '0';
282 /* Length modifiers. We don't yet recognize ll, j, t, or z. */
288 ok['c'] = ok['s'] = 0;
290 else if (*fmt == 'h')
299 ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = ok['f'] = ok['F']
300 = ok['g'] = ok['G'] = ok['s'] = 0;
304 if (sizeof ok <= c || !ok[c])
306 M4ERROR ((warning_status, 0,
307 "Warning: unrecognized specifier in `%s'", f));
313 /* Specifiers. We don't yet recognize C, S, n, or p. */
318 p -= 2; /* %.*c is undefined, so undo the '.*'. */
331 datatype = lflag ? LONG : INT;
354 str = xasprintf (fstart, width, ARG_INT(argc, argv));
358 str = xasprintf (fstart, width, prec, ARG_INT(argc, argv));
362 str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv));
366 str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv));
370 str = xasprintf (fstart, width, prec, ARG_STR(argc, argv));
377 /* NULL was returned on failure, such as invalid format string. For
378 now, just silently ignore that bad specifier. */
382 obstack_grow (obs, str, strlen (str));