More error messages tied to macro names.
[m4/ericb.git] / src / format.c
blob96ac5628423c5bb67946d2eae38e2193d3b59ee9
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. */
24 #include "m4.h"
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) \
31 ((argc == 0) ? 0 : \
32 (--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1]))))
34 #define ARG_LONG(argc, argv) \
35 ((argc == 0) ? 0 : \
36 (--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1]))))
38 #define ARG_STR(argc, argv) \
39 ((argc == 0) ? "" : \
40 (--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
42 #define ARG_DOUBLE(argc, argv) \
43 ((argc == 0) ? 0 : \
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 `------------------------------------------------------------------*/
55 void
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 */
65 /* Flags. */
66 char flags; /* flags to use in fstart */
67 enum {
68 THOUSANDS = 0x01, /* ' */
69 PLUS = 0x02, /* + */
70 MINUS = 0x04, /* - */
71 SPACE = 0x08, /* */
72 ZERO = 0x10, /* 0 */
73 ALT = 0x20, /* # */
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. */
85 char ok[128];
87 /* Buffer and stuff. */
88 char *str; /* malloc'd buffer of formatted text */
89 enum {CHAR, INT, LONG, DOUBLE, STR} datatype;
91 argv++;
92 argc--;
93 f = fmt = ARG_STR (argc, argv);
94 memset (ok, 0, sizeof ok);
95 for (;;)
97 while ((c = *fmt++) != '%')
99 if (c == '\0')
100 return;
101 obstack_1grow (obs, c);
104 if (*fmt == '%')
106 obstack_1grow (obs, '%');
107 fmt++;
108 continue;
111 p = fstart + 1; /* % */
112 lflag = 0;
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;
117 /* Parse flags. */
118 flags = 0;
121 switch (*fmt)
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;
126 flags |= THOUSANDS;
127 break;
129 case '+': /* mandatory sign */
130 ok['c'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 0;
131 flags |= PLUS;
132 break;
134 case ' ': /* space instead of positive sign */
135 ok['c'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = 0;
136 flags |= SPACE;
137 break;
139 case '0': /* zero padding */
140 ok['c'] = ok['s'] = 0;
141 flags |= ZERO;
142 break;
144 case '#': /* alternate output */
145 ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0;
146 flags |= ALT;
147 break;
149 case '-': /* left justification */
150 flags |= MINUS;
151 break;
153 default:
154 flags |= DONE;
155 break;
158 while (!(flags & DONE) && fmt++);
159 if (flags & THOUSANDS)
160 *p++ = '\'';
161 if (flags & PLUS)
162 *p++ = '+';
163 if (flags & MINUS)
164 *p++ = '-';
165 if (flags & SPACE)
166 *p++ = ' ';
167 if (flags & ZERO)
168 *p++ = '0';
169 if (flags & ALT)
170 *p++ = '#';
172 /* Minimum field width; an explicit 0 is the same as not giving
173 the width. */
174 width = 0;
175 *p++ = '*';
176 if (*fmt == '*')
178 width = ARG_INT (argc, argv);
179 fmt++;
181 else
182 while (isdigit (to_uchar (*fmt)))
184 width = 10 * width + *fmt - '0';
185 fmt++;
188 /* Maximum precision; an explicit negative precision is the same
189 as not giving the precision. A lone '.' is a precision of 0. */
190 prec = -1;
191 *p++ = '.';
192 *p++ = '*';
193 if (*fmt == '.')
195 ok['c'] = 0;
196 if (*(++fmt) == '*')
198 prec = ARG_INT (argc, argv);
199 ++fmt;
201 else
203 prec = 0;
204 while (isdigit (to_uchar (*fmt)))
206 prec = 10 * prec + *fmt - '0';
207 fmt++;
212 /* Length modifiers. We don't yet recognize ll, j, t, or z. */
213 if (*fmt == 'l')
215 *p++ = 'l';
216 lflag = 1;
217 fmt++;
218 ok['c'] = ok['s'] = 0;
220 else if (*fmt == 'h')
222 *p++ = 'h';
223 fmt++;
224 if (*fmt == 'h')
226 *p++ = 'h';
227 fmt++;
229 ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = ok['f'] = ok['F']
230 = ok['g'] = ok['G'] = ok['s'] = 0;
233 c = *fmt++;
234 if (c > sizeof ok || !ok[c])
236 m4_warn (0, me, _("unrecognized specifier in `%s'"), f);
237 if (c == '\0')
238 fmt--;
239 continue;
242 /* Specifiers. We don't yet recognize C, S, n, or p. */
243 switch (c)
245 case 'c':
246 datatype = CHAR;
247 p -= 2; /* %.*c is undefined, so undo the '.*'. */
248 break;
250 case 's':
251 datatype = STR;
252 break;
254 case 'd':
255 case 'i':
256 case 'o':
257 case 'x':
258 case 'X':
259 case 'u':
260 datatype = lflag ? LONG : INT;
261 break;
263 case 'a':
264 case 'A':
265 case 'e':
266 case 'E':
267 case 'f':
268 case 'F':
269 case 'g':
270 case 'G':
271 datatype = DOUBLE;
272 break;
274 default:
275 abort ();
277 *p++ = c;
278 *p = '\0';
280 switch (datatype)
282 case CHAR:
283 str = xasprintf (fstart, width, ARG_INT(argc, argv));
284 break;
286 case INT:
287 str = xasprintf (fstart, width, prec, ARG_INT(argc, argv));
288 break;
290 case LONG:
291 str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv));
292 break;
294 case DOUBLE:
295 str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv));
296 break;
298 case STR:
299 str = xasprintf (fstart, width, prec, ARG_STR(argc, argv));
300 break;
302 default:
303 abort();
306 /* NULL was returned on failure, such as invalid format string.
307 Issue a warning, then proceed. */
308 if (str == NULL)
310 m4_warn (0, me, _("unable to format output for `%s'"), f);
311 continue;
314 obstack_grow (obs, str, strlen (str));
315 free (str);