comparison lib/printf-parse.c @ 4224:83eabea25586

New modules vasnprintf and vasprintf.
author Bruno Haible <bruno@clisp.org>
date Thu, 30 Jan 2003 13:48:21 +0000
parents
children e58a1c05a6ba
comparison
equal deleted inserted replaced
4223:94b829dffa17 4224:83eabea25586
1 /* Formatted output to strings.
2 Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published
6 by the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA. */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 /* Specification. */
24 #include "printf-parse.h"
25
26 /* Get size_t, NULL. */
27 #include <stddef.h>
28
29 /* Get intmax_t. */
30 #if HAVE_STDINT_H_WITH_UINTMAX
31 # include <stdint.h>
32 #endif
33 #if HAVE_INTTYPES_H_WITH_UINTMAX
34 # include <inttypes.h>
35 #endif
36
37 /* malloc(), realloc(), free(). */
38 #include <stdlib.h>
39
40 #ifdef STATIC
41 STATIC
42 #endif
43 int
44 printf_parse (const char *format, char_directives *d, arguments *a)
45 {
46 const char *cp = format; /* pointer into format */
47 int arg_posn = 0; /* number of regular arguments consumed */
48 unsigned int d_allocated; /* allocated elements of d->dir */
49 unsigned int a_allocated; /* allocated elements of a->arg */
50 unsigned int max_width_length = 0;
51 unsigned int max_precision_length = 0;
52
53 d->count = 0;
54 d_allocated = 1;
55 d->dir = malloc (d_allocated * sizeof (char_directive));
56 if (d->dir == NULL)
57 /* Out of memory. */
58 return -1;
59
60 a->count = 0;
61 a_allocated = 0;
62 a->arg = NULL;
63
64 #define REGISTER_ARG(_index_,_type_) \
65 { \
66 unsigned int n = (_index_); \
67 if (n >= a_allocated) \
68 { \
69 argument *memory; \
70 a_allocated = 2 * a_allocated; \
71 if (a_allocated <= n) \
72 a_allocated = n + 1; \
73 memory = (a->arg \
74 ? realloc (a->arg, a_allocated * sizeof (argument)) \
75 : malloc (a_allocated * sizeof (argument))); \
76 if (memory == NULL) \
77 /* Out of memory. */ \
78 goto error; \
79 a->arg = memory; \
80 } \
81 while (a->count <= n) \
82 a->arg[a->count++].type = TYPE_NONE; \
83 if (a->arg[n].type == TYPE_NONE) \
84 a->arg[n].type = (_type_); \
85 else if (a->arg[n].type != (_type_)) \
86 /* Ambiguous type for positional argument. */ \
87 goto error; \
88 }
89
90 while (*cp != '\0')
91 {
92 char c = *cp++;
93 if (c == '%')
94 {
95 int arg_index = -1;
96 char_directive *dp = &d->dir[d->count];/* pointer to next directive */
97
98 /* Initialize the next directive. */
99 dp->dir_start = cp - 1;
100 dp->flags = 0;
101 dp->width_start = NULL;
102 dp->width_end = NULL;
103 dp->width_arg_index = -1;
104 dp->precision_start = NULL;
105 dp->precision_end = NULL;
106 dp->precision_arg_index = -1;
107 dp->arg_index = -1;
108
109 /* Test for positional argument. */
110 if (*cp >= '0' && *cp <= '9')
111 {
112 const char *np;
113
114 for (np = cp; *np >= '0' && *np <= '9'; np++)
115 ;
116 if (*np == '$')
117 {
118 unsigned int n = 0;
119
120 for (np = cp; *np >= '0' && *np <= '9'; np++)
121 n = 10 * n + (*np - '0');
122 if (n == 0)
123 /* Positional argument 0. */
124 goto error;
125 arg_index = n - 1;
126 cp = np + 1;
127 }
128 }
129
130 /* Read the flags. */
131 for (;;)
132 {
133 if (*cp == '\'')
134 {
135 dp->flags |= FLAG_GROUP;
136 cp++;
137 }
138 else if (*cp == '-')
139 {
140 dp->flags |= FLAG_LEFT;
141 cp++;
142 }
143 else if (*cp == '+')
144 {
145 dp->flags |= FLAG_SHOWSIGN;
146 cp++;
147 }
148 else if (*cp == ' ')
149 {
150 dp->flags |= FLAG_SPACE;
151 cp++;
152 }
153 else if (*cp == '#')
154 {
155 dp->flags |= FLAG_ALT;
156 cp++;
157 }
158 else if (*cp == '0')
159 {
160 dp->flags |= FLAG_ZERO;
161 cp++;
162 }
163 else
164 break;
165 }
166
167 /* Parse the field width. */
168 if (*cp == '*')
169 {
170 dp->width_start = cp;
171 cp++;
172 dp->width_end = cp;
173 if (max_width_length < 1)
174 max_width_length = 1;
175
176 /* Test for positional argument. */
177 if (*cp >= '0' && *cp <= '9')
178 {
179 const char *np;
180
181 for (np = cp; *np >= '0' && *np <= '9'; np++)
182 ;
183 if (*np == '$')
184 {
185 unsigned int n = 0;
186
187 for (np = cp; *np >= '0' && *np <= '9'; np++)
188 n = 10 * n + (*np - '0');
189 if (n == 0)
190 /* Positional argument 0. */
191 goto error;
192 dp->width_arg_index = n - 1;
193 cp = np + 1;
194 }
195 }
196 if (dp->width_arg_index < 0)
197 dp->width_arg_index = arg_posn++;
198 REGISTER_ARG (dp->width_arg_index, TYPE_INT);
199 }
200 else if (*cp >= '0' && *cp <= '9')
201 {
202 unsigned int width_length;
203
204 dp->width_start = cp;
205 for (; *cp >= '0' && *cp <= '9'; cp++)
206 ;
207 dp->width_end = cp;
208 width_length = dp->width_end - dp->width_start;
209 if (max_width_length < width_length)
210 max_width_length = width_length;
211 }
212
213 /* Parse the precision. */
214 if (*cp == '.')
215 {
216 cp++;
217 if (*cp == '*')
218 {
219 dp->precision_start = cp - 1;
220 cp++;
221 dp->precision_end = cp;
222 if (max_precision_length < 2)
223 max_precision_length = 2;
224
225 /* Test for positional argument. */
226 if (*cp >= '0' && *cp <= '9')
227 {
228 const char *np;
229
230 for (np = cp; *np >= '0' && *np <= '9'; np++)
231 ;
232 if (*np == '$')
233 {
234 unsigned int n = 0;
235
236 for (np = cp; *np >= '0' && *np <= '9'; np++)
237 n = 10 * n + (*np - '0');
238 if (n == 0)
239 /* Positional argument 0. */
240 goto error;
241 dp->precision_arg_index = n - 1;
242 cp = np + 1;
243 }
244 }
245 if (dp->precision_arg_index < 0)
246 dp->precision_arg_index = arg_posn++;
247 REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
248 }
249 else
250 {
251 unsigned int precision_length;
252
253 dp->precision_start = cp - 1;
254 for (; *cp >= '0' && *cp <= '9'; cp++)
255 ;
256 dp->precision_end = cp;
257 precision_length = dp->precision_end - dp->precision_start;
258 if (max_precision_length < precision_length)
259 max_precision_length = precision_length;
260 }
261 }
262
263 {
264 arg_type type;
265
266 /* Parse argument type/size specifiers. */
267 {
268 int flags = 0;
269
270 for (;;)
271 {
272 if (*cp == 'h')
273 {
274 flags |= (1 << (flags & 1));
275 cp++;
276 }
277 else if (*cp == 'L')
278 {
279 flags |= 4;
280 cp++;
281 }
282 else if (*cp == 'l')
283 {
284 flags += 8;
285 cp++;
286 }
287 #ifdef HAVE_INTMAX_T
288 else if (*cp == 'j')
289 {
290 if (sizeof (intmax_t) > sizeof (long))
291 {
292 /* intmax_t = long long */
293 flags += 16;
294 }
295 else if (sizeof (intmax_t) > sizeof (int))
296 {
297 /* intmax_t = long */
298 flags += 8;
299 }
300 cp++;
301 }
302 #endif
303 else if (*cp == 'z' || *cp == 'Z')
304 {
305 /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
306 because the warning facility in gcc-2.95.2 understands
307 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
308 if (sizeof (size_t) > sizeof (long))
309 {
310 /* size_t = long long */
311 flags += 16;
312 }
313 else if (sizeof (size_t) > sizeof (int))
314 {
315 /* size_t = long */
316 flags += 8;
317 }
318 cp++;
319 }
320 else if (*cp == 't')
321 {
322 if (sizeof (ptrdiff_t) > sizeof (long))
323 {
324 /* ptrdiff_t = long long */
325 flags += 16;
326 }
327 else if (sizeof (ptrdiff_t) > sizeof (int))
328 {
329 /* ptrdiff_t = long */
330 flags += 8;
331 }
332 cp++;
333 }
334 else
335 break;
336 }
337
338 /* Read the conversion character. */
339 c = *cp++;
340 switch (c)
341 {
342 case 'd': case 'i':
343 #ifdef HAVE_LONG_LONG
344 if (flags >= 16 || (flags & 4))
345 type = TYPE_LONGLONGINT;
346 else
347 #endif
348 if (flags >= 8)
349 type = TYPE_LONGINT;
350 else if (flags & 2)
351 type = TYPE_SCHAR;
352 else if (flags & 1)
353 type = TYPE_SHORT;
354 else
355 type = TYPE_INT;
356 break;
357 case 'o': case 'u': case 'x': case 'X':
358 #ifdef HAVE_LONG_LONG
359 if (flags >= 16 || (flags & 4))
360 type = TYPE_ULONGLONGINT;
361 else
362 #endif
363 if (flags >= 8)
364 type = TYPE_ULONGINT;
365 else if (flags & 2)
366 type = TYPE_UCHAR;
367 else if (flags & 1)
368 type = TYPE_USHORT;
369 else
370 type = TYPE_UINT;
371 break;
372 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
373 case 'a': case 'A':
374 #ifdef HAVE_LONG_DOUBLE
375 if (flags >= 16 || (flags & 4))
376 type = TYPE_LONGDOUBLE;
377 else
378 #endif
379 type = TYPE_DOUBLE;
380 break;
381 case 'c':
382 if (flags >= 8)
383 #ifdef HAVE_WINT_T
384 type = TYPE_WIDE_CHAR;
385 #else
386 goto error;
387 #endif
388 else
389 type = TYPE_CHAR;
390 break;
391 #ifdef HAVE_WINT_T
392 case 'C':
393 type = TYPE_WIDE_CHAR;
394 c = 'c';
395 break;
396 #endif
397 case 's':
398 if (flags >= 8)
399 #ifdef HAVE_WCHAR_T
400 type = TYPE_WIDE_STRING;
401 #else
402 goto error;
403 #endif
404 else
405 type = TYPE_STRING;
406 break;
407 #ifdef HAVE_WCHAR_T
408 case 'S':
409 type = TYPE_WIDE_STRING;
410 c = 's';
411 break;
412 #endif
413 case 'p':
414 type = TYPE_POINTER;
415 break;
416 case 'n':
417 #ifdef HAVE_LONG_LONG
418 if (flags >= 16 || (flags & 4))
419 type = TYPE_COUNT_LONGLONGINT_POINTER;
420 else
421 #endif
422 if (flags >= 8)
423 type = TYPE_COUNT_LONGINT_POINTER;
424 else if (flags & 2)
425 type = TYPE_COUNT_SCHAR_POINTER;
426 else if (flags & 1)
427 type = TYPE_COUNT_SHORT_POINTER;
428 else
429 type = TYPE_COUNT_INT_POINTER;
430 break;
431 case '%':
432 type = TYPE_NONE;
433 break;
434 default:
435 /* Unknown conversion character. */
436 goto error;
437 }
438 }
439
440 if (type != TYPE_NONE)
441 {
442 dp->arg_index = arg_index;
443 if (dp->arg_index < 0)
444 dp->arg_index = arg_posn++;
445 REGISTER_ARG (dp->arg_index, type);
446 }
447 dp->conversion = c;
448 dp->dir_end = cp;
449 }
450
451 d->count++;
452 if (d->count >= d_allocated)
453 {
454 char_directive *memory;
455
456 d_allocated = 2 * d_allocated;
457 memory = realloc (d->dir, d_allocated * sizeof (char_directive));
458 if (memory == NULL)
459 /* Out of memory. */
460 goto error;
461 d->dir = memory;
462 }
463 }
464 }
465 d->dir[d->count].dir_start = cp;
466
467 d->max_width_length = max_width_length;
468 d->max_precision_length = max_precision_length;
469 return 0;
470
471 error:
472 if (a->arg)
473 free (a->arg);
474 if (d->dir)
475 free (d->dir);
476 return -1;
477 }