source: vendor/m4/1.4.8/src/format.c

Last change on this file was 3090, checked in by bird, 18 years ago

m4 1.4.8

File size: 6.7 KB
Line 
1/* GNU m4 -- A simple macro processor
2
3 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006
4 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA
20*/
21
22/* printf like formatting for m4. */
23
24#include "m4.h"
25#include "xvasprintf.h"
26
27/* Simple varargs substitute. */
28
29#define ARG_INT(argc, argv) \
30 ((argc == 0) ? 0 : \
31 (--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1]))))
32
33#define ARG_UINT(argc, argv) \
34 ((argc == 0) ? 0 : \
35 (--argc, argv++, (unsigned int) atoi (TOKEN_DATA_TEXT (argv[-1]))))
36
37#define ARG_LONG(argc, argv) \
38 ((argc == 0) ? 0 : \
39 (--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1]))))
40
41#define ARG_ULONG(argc, argv) \
42 ((argc == 0) ? 0 : \
43 (--argc, argv++, (unsigned long) atol (TOKEN_DATA_TEXT (argv[-1]))))
44
45#define ARG_STR(argc, argv) \
46 ((argc == 0) ? "" : \
47 (--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
48
49#define ARG_DOUBLE(argc, argv) \
50 ((argc == 0) ? 0 : \
51 (--argc, argv++, atof (TOKEN_DATA_TEXT (argv[-1]))))
52
53
54
55/*------------------------------------------------------------------------.
56| The main formatting function. Output is placed on the obstack OBS, the |
57| first argument in ARGV is the formatting string, and the rest is |
58| arguments for the string. |
59`------------------------------------------------------------------------*/
60
61void
62format (struct obstack *obs, int argc, token_data **argv)
63{
64 char *fmt; /* format control string */
65 const char *fstart; /* beginning of current format spec */
66 int c; /* a simple character */
67
68 /* Flags. */
69 char flags; /* 1 iff treating flags */
70
71 /* Precision specifiers. */
72 int width; /* minimum field width */
73 int prec; /* precision */
74 char lflag; /* long flag */
75 char hflag; /* short flag */
76
77 /* Buffer and stuff. */
78 char *str; /* malloc'd buffer of formatted text */
79 enum {INT, UINT, LONG, ULONG, DOUBLE, STR} datatype;
80
81 fmt = (char *) ARG_STR (argc, argv);
82 for (;;)
83 {
84 while ((c = *fmt++) != '%')
85 {
86 if (c == 0)
87 return;
88 obstack_1grow (obs, c);
89 }
90
91 fstart = fmt - 1;
92
93 if (*fmt == '%')
94 {
95 obstack_1grow (obs, '%');
96 fmt++;
97 continue;
98 }
99
100 /* Parse flags. */
101 flags = 1;
102 do
103 {
104 switch (*fmt)
105 {
106 case '-': /* left justification */
107 case '+': /* mandatory sign */
108 case ' ': /* space instead of positive sign */
109 case '0': /* zero padding */
110 case '#': /* alternate output */
111 break;
112
113 default:
114 flags = 0;
115 break;
116 }
117 }
118 while (flags && fmt++);
119
120 /* Minimum field width. */
121 width = -1;
122 if (*fmt == '*')
123 {
124 width = ARG_INT (argc, argv);
125 fmt++;
126 }
127 else if (isdigit (to_uchar (*fmt)))
128 {
129 do
130 {
131 fmt++;
132 }
133 while (isdigit (to_uchar (*fmt)));
134 }
135
136 /* Maximum precision. */
137 prec = -1;
138 if (*fmt == '.')
139 {
140 if (*(++fmt) == '*')
141 {
142 prec = ARG_INT (argc, argv);
143 ++fmt;
144 }
145 else if (isdigit (to_uchar (*fmt)))
146 {
147 do
148 {
149 fmt++;
150 }
151 while (isdigit (to_uchar (*fmt)));
152 }
153 }
154
155 /* Length modifiers. */
156 lflag = (*fmt == 'l');
157 hflag = (*fmt == 'h');
158 if (lflag || hflag)
159 fmt++;
160
161 switch (*fmt++)
162 {
163
164 case '\0':
165 return;
166
167 case 'c':
168 datatype = INT;
169 break;
170
171 case 's':
172 datatype = STR;
173 break;
174
175 case 'd':
176 case 'i':
177 if (lflag)
178 {
179 datatype = LONG;
180 }
181 else
182 {
183 datatype = INT;
184 }
185 break;
186
187 case 'o':
188 case 'x':
189 case 'X':
190 case 'u':
191 if (lflag)
192 {
193 datatype = ULONG;
194 }
195 else
196 {
197 datatype = UINT;
198 }
199 break;
200
201 case 'e':
202 case 'E':
203 case 'f':
204 case 'F':
205 case 'g':
206 case 'G':
207 datatype = DOUBLE;
208 break;
209
210 default:
211 continue;
212 }
213
214 c = *fmt;
215 *fmt = '\0';
216
217 switch(datatype)
218 {
219 case INT:
220 if (width != -1 && prec != -1)
221 str = xasprintf (fstart, width, prec, ARG_INT(argc, argv));
222 else if (width != -1)
223 str = xasprintf (fstart, width, ARG_INT(argc, argv));
224 else if (prec != -1)
225 str = xasprintf (fstart, prec, ARG_INT(argc, argv));
226 else
227 str = xasprintf (fstart, ARG_INT(argc, argv));
228 break;
229
230 case UINT:
231 if (width != -1 && prec != -1)
232 str = xasprintf (fstart, width, prec, ARG_UINT(argc, argv));
233 else if (width != -1)
234 str = xasprintf (fstart, width, ARG_UINT(argc, argv));
235 else if (prec != -1)
236 str = xasprintf (fstart, prec, ARG_UINT(argc, argv));
237 else
238 str = xasprintf (fstart, ARG_UINT(argc, argv));
239 break;
240
241 case LONG:
242 if (width != -1 && prec != -1)
243 str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv));
244 else if (width != -1)
245 str = xasprintf (fstart, width, ARG_LONG(argc, argv));
246 else if (prec != -1)
247 str = xasprintf (fstart, prec, ARG_LONG(argc, argv));
248 else
249 str = xasprintf (fstart, ARG_LONG(argc, argv));
250 break;
251
252 case ULONG:
253 if (width != -1 && prec != -1)
254 str = xasprintf (fstart, width, prec, ARG_ULONG(argc, argv));
255 else if (width != -1)
256 str = xasprintf (fstart, width, ARG_ULONG(argc, argv));
257 else if (prec != -1)
258 str = xasprintf (fstart, prec, ARG_ULONG(argc, argv));
259 else
260 str = xasprintf (fstart, ARG_ULONG(argc, argv));
261 break;
262
263 case DOUBLE:
264 if (width != -1 && prec != -1)
265 str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv));
266 else if (width != -1)
267 str = xasprintf (fstart, width, ARG_DOUBLE(argc, argv));
268 else if (prec != -1)
269 str = xasprintf (fstart, prec, ARG_DOUBLE(argc, argv));
270 else
271 str = xasprintf (fstart, ARG_DOUBLE(argc, argv));
272 break;
273
274 case STR:
275 if (width != -1 && prec != -1)
276 str = xasprintf (fstart, width, prec, ARG_STR(argc, argv));
277 else if (width != -1)
278 str = xasprintf (fstart, width, ARG_STR(argc, argv));
279 else if (prec != -1)
280 str = xasprintf (fstart, prec, ARG_STR(argc, argv));
281 else
282 str = xasprintf (fstart, ARG_STR(argc, argv));
283 break;
284
285 default:
286 abort();
287 }
288
289 *fmt = c;
290
291 /* NULL was returned on failure, such as invalid format string. For
292 now, just silently ignore that bad specifier. */
293 if (str == NULL)
294 continue;
295
296 obstack_grow (obs, str, strlen (str));
297 free (str);
298 }
299}
Note: See TracBrowser for help on using the repository browser.