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 *f
; /* format control string */
59 const char *fmt
; /* position within f */
60 char fstart
[] = "%'+- 0#*.*hhd"; /* current format spec */
61 char *p
; /* position within fstart */
62 unsigned char c
; /* a simple character */
65 char flags
; /* flags to use in fstart */
67 THOUSANDS
= 0x01, /* ' */
73 DONE
= 0x40 /* no more flags */
76 /* Precision specifiers. */
77 int width
; /* minimum field width */
78 int prec
; /* precision */
79 char lflag
; /* long flag */
81 /* Specifiers we are willing to accept. ok['x'] implies %x is ok.
82 Various modifiers reduce the set, in order to avoid undefined
83 behavior in printf. */
86 /* Buffer and stuff. */
87 char *str
; /* malloc'd buffer of formatted text */
88 enum {CHAR
, INT
, LONG
, DOUBLE
, STR
} datatype
;
90 f
= fmt
= ARG_STR (argc
, argv
);
91 memset (ok
, 0, sizeof ok
);
94 while ((c
= *fmt
++) != '%')
98 obstack_1grow (obs
, c
);
103 obstack_1grow (obs
, '%');
108 p
= fstart
+ 1; /* % */
110 ok
['a'] = ok
['A'] = ok
['c'] = ok
['d'] = ok
['e'] = ok
['E']
111 = ok
['f'] = ok
['F'] = ok
['g'] = ok
['G'] = ok
['i'] = ok
['o']
112 = ok
['s'] = ok
['u'] = ok
['x'] = ok
['X'] = 1;
120 case '\'': /* thousands separator */
121 ok
['a'] = ok
['A'] = ok
['c'] = ok
['e'] = ok
['E']
122 = ok
['o'] = ok
['s'] = ok
['x'] = ok
['X'] = 0;
126 case '+': /* mandatory sign */
127 ok
['c'] = ok
['o'] = ok
['s'] = ok
['u'] = ok
['x'] = ok
['X'] = 0;
131 case ' ': /* space instead of positive sign */
132 ok
['c'] = ok
['o'] = ok
['s'] = ok
['u'] = ok
['x'] = ok
['X'] = 0;
136 case '0': /* zero padding */
137 ok
['c'] = ok
['s'] = 0;
141 case '#': /* alternate output */
142 ok
['c'] = ok
['d'] = ok
['i'] = ok
['s'] = ok
['u'] = 0;
146 case '-': /* left justification */
155 while (!(flags
& DONE
) && fmt
++);
156 if (flags
& THOUSANDS
)
169 /* Minimum field width; an explicit 0 is the same as not giving
175 width
= ARG_INT (argc
, argv
);
179 while (isdigit (to_uchar (*fmt
)))
181 width
= 10 * width
+ *fmt
- '0';
185 /* Maximum precision; an explicit negative precision is the same
186 as not giving the precision. A lone '.' is a precision of 0. */
195 prec
= ARG_INT (argc
, argv
);
201 while (isdigit (to_uchar (*fmt
)))
203 prec
= 10 * prec
+ *fmt
- '0';
209 /* Length modifiers. We don't yet recognize ll, j, t, or z. */
215 ok
['c'] = ok
['s'] = 0;
217 else if (*fmt
== 'h')
226 ok
['a'] = ok
['A'] = ok
['c'] = ok
['e'] = ok
['E'] = ok
['f'] = ok
['F']
227 = ok
['g'] = ok
['G'] = ok
['s'] = 0;
231 if (c
> sizeof ok
|| !ok
[c
])
233 M4ERROR ((warning_status
, 0,
234 "Warning: unrecognized specifier in `%s'", f
));
240 /* Specifiers. We don't yet recognize C, S, n, or p. */
245 p
-= 2; /* %.*c is undefined, so undo the '.*'. */
258 datatype
= lflag
? LONG
: INT
;
281 str
= xasprintf (fstart
, width
, ARG_INT(argc
, argv
));
285 str
= xasprintf (fstart
, width
, prec
, ARG_INT(argc
, argv
));
289 str
= xasprintf (fstart
, width
, prec
, ARG_LONG(argc
, argv
));
293 str
= xasprintf (fstart
, width
, prec
, ARG_DOUBLE(argc
, argv
));
297 str
= xasprintf (fstart
, width
, prec
, ARG_STR(argc
, argv
));
304 /* NULL was returned on failure, such as invalid format string.
305 Issue a warning, then proceed. */
308 M4ERROR ((warning_status
, 0,
309 "Warning: unable to format output for `%s'", f
));
313 obstack_grow (obs
, str
, strlen (str
));