Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / texinfo / intl / printf-parse.c
blobb04622930b2653274fe348c707df2fa75e59d72d
1 /* $NetBSD$ */
3 /* Formatted output to strings.
4 Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Library General Public License as published
8 by the Free Software Foundation; either version 2, or (at your option)
9 any later version.
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 GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 USA. */
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 /* Specification. */
26 #if WIDE_CHAR_VERSION
27 # include "wprintf-parse.h"
28 #else
29 # include "printf-parse.h"
30 #endif
32 /* Get size_t, NULL. */
33 #include <stddef.h>
35 /* Get intmax_t. */
36 #if HAVE_STDINT_H_WITH_UINTMAX
37 # include <stdint.h>
38 #endif
39 #if HAVE_INTTYPES_H_WITH_UINTMAX
40 # include <inttypes.h>
41 #endif
43 /* malloc(), realloc(), free(). */
44 #include <stdlib.h>
46 /* Checked size_t computations. */
47 #include "xsize.h"
49 #if WIDE_CHAR_VERSION
50 # define PRINTF_PARSE wprintf_parse
51 # define CHAR_T wchar_t
52 # define DIRECTIVE wchar_t_directive
53 # define DIRECTIVES wchar_t_directives
54 #else
55 # define PRINTF_PARSE printf_parse
56 # define CHAR_T char
57 # define DIRECTIVE char_directive
58 # define DIRECTIVES char_directives
59 #endif
61 #ifdef STATIC
62 STATIC
63 #endif
64 int
65 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
67 const CHAR_T *cp = format; /* pointer into format */
68 size_t arg_posn = 0; /* number of regular arguments consumed */
69 size_t d_allocated; /* allocated elements of d->dir */
70 size_t a_allocated; /* allocated elements of a->arg */
71 size_t max_width_length = 0;
72 size_t max_precision_length = 0;
74 d->count = 0;
75 d_allocated = 1;
76 d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
77 if (d->dir == NULL)
78 /* Out of memory. */
79 return -1;
81 a->count = 0;
82 a_allocated = 0;
83 a->arg = NULL;
85 #define REGISTER_ARG(_index_,_type_) \
86 { \
87 size_t n = (_index_); \
88 if (n >= a_allocated) \
89 { \
90 size_t memory_size; \
91 argument *memory; \
93 a_allocated = xtimes (a_allocated, 2); \
94 if (a_allocated <= n) \
95 a_allocated = xsum (n, 1); \
96 memory_size = xtimes (a_allocated, sizeof (argument)); \
97 if (size_overflow_p (memory_size)) \
98 /* Overflow, would lead to out of memory. */ \
99 goto error; \
100 memory = (a->arg \
101 ? realloc (a->arg, memory_size) \
102 : malloc (memory_size)); \
103 if (memory == NULL) \
104 /* Out of memory. */ \
105 goto error; \
106 a->arg = memory; \
108 while (a->count <= n) \
109 a->arg[a->count++].type = TYPE_NONE; \
110 if (a->arg[n].type == TYPE_NONE) \
111 a->arg[n].type = (_type_); \
112 else if (a->arg[n].type != (_type_)) \
113 /* Ambiguous type for positional argument. */ \
114 goto error; \
117 while (*cp != '\0')
119 CHAR_T c = *cp++;
120 if (c == '%')
122 size_t arg_index = ARG_NONE;
123 DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
125 /* Initialize the next directive. */
126 dp->dir_start = cp - 1;
127 dp->flags = 0;
128 dp->width_start = NULL;
129 dp->width_end = NULL;
130 dp->width_arg_index = ARG_NONE;
131 dp->precision_start = NULL;
132 dp->precision_end = NULL;
133 dp->precision_arg_index = ARG_NONE;
134 dp->arg_index = ARG_NONE;
136 /* Test for positional argument. */
137 if (*cp >= '0' && *cp <= '9')
139 const CHAR_T *np;
141 for (np = cp; *np >= '0' && *np <= '9'; np++)
143 if (*np == '$')
145 size_t n = 0;
147 for (np = cp; *np >= '0' && *np <= '9'; np++)
148 n = xsum (xtimes (n, 10), *np - '0');
149 if (n == 0)
150 /* Positional argument 0. */
151 goto error;
152 if (size_overflow_p (n))
153 /* n too large, would lead to out of memory later. */
154 goto error;
155 arg_index = n - 1;
156 cp = np + 1;
160 /* Read the flags. */
161 for (;;)
163 if (*cp == '\'')
165 dp->flags |= FLAG_GROUP;
166 cp++;
168 else if (*cp == '-')
170 dp->flags |= FLAG_LEFT;
171 cp++;
173 else if (*cp == '+')
175 dp->flags |= FLAG_SHOWSIGN;
176 cp++;
178 else if (*cp == ' ')
180 dp->flags |= FLAG_SPACE;
181 cp++;
183 else if (*cp == '#')
185 dp->flags |= FLAG_ALT;
186 cp++;
188 else if (*cp == '0')
190 dp->flags |= FLAG_ZERO;
191 cp++;
193 else
194 break;
197 /* Parse the field width. */
198 if (*cp == '*')
200 dp->width_start = cp;
201 cp++;
202 dp->width_end = cp;
203 if (max_width_length < 1)
204 max_width_length = 1;
206 /* Test for positional argument. */
207 if (*cp >= '0' && *cp <= '9')
209 const CHAR_T *np;
211 for (np = cp; *np >= '0' && *np <= '9'; np++)
213 if (*np == '$')
215 size_t n = 0;
217 for (np = cp; *np >= '0' && *np <= '9'; np++)
218 n = xsum (xtimes (n, 10), *np - '0');
219 if (n == 0)
220 /* Positional argument 0. */
221 goto error;
222 if (size_overflow_p (n))
223 /* n too large, would lead to out of memory later. */
224 goto error;
225 dp->width_arg_index = n - 1;
226 cp = np + 1;
229 if (dp->width_arg_index == ARG_NONE)
231 dp->width_arg_index = arg_posn++;
232 if (dp->width_arg_index == ARG_NONE)
233 /* arg_posn wrapped around. */
234 goto error;
236 REGISTER_ARG (dp->width_arg_index, TYPE_INT);
238 else if (*cp >= '0' && *cp <= '9')
240 size_t width_length;
242 dp->width_start = cp;
243 for (; *cp >= '0' && *cp <= '9'; cp++)
245 dp->width_end = cp;
246 width_length = dp->width_end - dp->width_start;
247 if (max_width_length < width_length)
248 max_width_length = width_length;
251 /* Parse the precision. */
252 if (*cp == '.')
254 cp++;
255 if (*cp == '*')
257 dp->precision_start = cp - 1;
258 cp++;
259 dp->precision_end = cp;
260 if (max_precision_length < 2)
261 max_precision_length = 2;
263 /* Test for positional argument. */
264 if (*cp >= '0' && *cp <= '9')
266 const CHAR_T *np;
268 for (np = cp; *np >= '0' && *np <= '9'; np++)
270 if (*np == '$')
272 size_t n = 0;
274 for (np = cp; *np >= '0' && *np <= '9'; np++)
275 n = xsum (xtimes (n, 10), *np - '0');
276 if (n == 0)
277 /* Positional argument 0. */
278 goto error;
279 if (size_overflow_p (n))
280 /* n too large, would lead to out of memory
281 later. */
282 goto error;
283 dp->precision_arg_index = n - 1;
284 cp = np + 1;
287 if (dp->precision_arg_index == ARG_NONE)
289 dp->precision_arg_index = arg_posn++;
290 if (dp->precision_arg_index == ARG_NONE)
291 /* arg_posn wrapped around. */
292 goto error;
294 REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
296 else
298 size_t precision_length;
300 dp->precision_start = cp - 1;
301 for (; *cp >= '0' && *cp <= '9'; cp++)
303 dp->precision_end = cp;
304 precision_length = dp->precision_end - dp->precision_start;
305 if (max_precision_length < precision_length)
306 max_precision_length = precision_length;
311 arg_type type;
313 /* Parse argument type/size specifiers. */
315 int flags = 0;
317 for (;;)
319 if (*cp == 'h')
321 flags |= (1 << (flags & 1));
322 cp++;
324 else if (*cp == 'L')
326 flags |= 4;
327 cp++;
329 else if (*cp == 'l')
331 flags += 8;
332 cp++;
334 #ifdef HAVE_INTMAX_T
335 else if (*cp == 'j')
337 if (sizeof (intmax_t) > sizeof (long))
339 /* intmax_t = long long */
340 flags += 16;
342 else if (sizeof (intmax_t) > sizeof (int))
344 /* intmax_t = long */
345 flags += 8;
347 cp++;
349 #endif
350 else if (*cp == 'z' || *cp == 'Z')
352 /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
353 because the warning facility in gcc-2.95.2 understands
354 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
355 if (sizeof (size_t) > sizeof (long))
357 /* size_t = long long */
358 flags += 16;
360 else if (sizeof (size_t) > sizeof (int))
362 /* size_t = long */
363 flags += 8;
365 cp++;
367 else if (*cp == 't')
369 if (sizeof (ptrdiff_t) > sizeof (long))
371 /* ptrdiff_t = long long */
372 flags += 16;
374 else if (sizeof (ptrdiff_t) > sizeof (int))
376 /* ptrdiff_t = long */
377 flags += 8;
379 cp++;
381 else
382 break;
385 /* Read the conversion character. */
386 c = *cp++;
387 switch (c)
389 case 'd': case 'i':
390 #ifdef HAVE_LONG_LONG
391 if (flags >= 16 || (flags & 4))
392 type = TYPE_LONGLONGINT;
393 else
394 #endif
395 if (flags >= 8)
396 type = TYPE_LONGINT;
397 else if (flags & 2)
398 type = TYPE_SCHAR;
399 else if (flags & 1)
400 type = TYPE_SHORT;
401 else
402 type = TYPE_INT;
403 break;
404 case 'o': case 'u': case 'x': case 'X':
405 #ifdef HAVE_LONG_LONG
406 if (flags >= 16 || (flags & 4))
407 type = TYPE_ULONGLONGINT;
408 else
409 #endif
410 if (flags >= 8)
411 type = TYPE_ULONGINT;
412 else if (flags & 2)
413 type = TYPE_UCHAR;
414 else if (flags & 1)
415 type = TYPE_USHORT;
416 else
417 type = TYPE_UINT;
418 break;
419 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
420 case 'a': case 'A':
421 #ifdef HAVE_LONG_DOUBLE
422 if (flags >= 16 || (flags & 4))
423 type = TYPE_LONGDOUBLE;
424 else
425 #endif
426 type = TYPE_DOUBLE;
427 break;
428 case 'c':
429 if (flags >= 8)
430 #ifdef HAVE_WINT_T
431 type = TYPE_WIDE_CHAR;
432 #else
433 goto error;
434 #endif
435 else
436 type = TYPE_CHAR;
437 break;
438 #ifdef HAVE_WINT_T
439 case 'C':
440 type = TYPE_WIDE_CHAR;
441 c = 'c';
442 break;
443 #endif
444 case 's':
445 if (flags >= 8)
446 #ifdef HAVE_WCHAR_T
447 type = TYPE_WIDE_STRING;
448 #else
449 goto error;
450 #endif
451 else
452 type = TYPE_STRING;
453 break;
454 #ifdef HAVE_WCHAR_T
455 case 'S':
456 type = TYPE_WIDE_STRING;
457 c = 's';
458 break;
459 #endif
460 case 'p':
461 type = TYPE_POINTER;
462 break;
463 case 'n':
464 #ifdef HAVE_LONG_LONG
465 if (flags >= 16 || (flags & 4))
466 type = TYPE_COUNT_LONGLONGINT_POINTER;
467 else
468 #endif
469 if (flags >= 8)
470 type = TYPE_COUNT_LONGINT_POINTER;
471 else if (flags & 2)
472 type = TYPE_COUNT_SCHAR_POINTER;
473 else if (flags & 1)
474 type = TYPE_COUNT_SHORT_POINTER;
475 else
476 type = TYPE_COUNT_INT_POINTER;
477 break;
478 case '%':
479 type = TYPE_NONE;
480 break;
481 default:
482 /* Unknown conversion character. */
483 goto error;
487 if (type != TYPE_NONE)
489 dp->arg_index = arg_index;
490 if (dp->arg_index == ARG_NONE)
492 dp->arg_index = arg_posn++;
493 if (dp->arg_index == ARG_NONE)
494 /* arg_posn wrapped around. */
495 goto error;
497 REGISTER_ARG (dp->arg_index, type);
499 dp->conversion = c;
500 dp->dir_end = cp;
503 d->count++;
504 if (d->count >= d_allocated)
506 size_t memory_size;
507 DIRECTIVE *memory;
509 d_allocated = xtimes (d_allocated, 2);
510 memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
511 if (size_overflow_p (memory_size))
512 /* Overflow, would lead to out of memory. */
513 goto error;
514 memory = realloc (d->dir, memory_size);
515 if (memory == NULL)
516 /* Out of memory. */
517 goto error;
518 d->dir = memory;
522 d->dir[d->count].dir_start = cp;
524 d->max_width_length = max_width_length;
525 d->max_precision_length = max_precision_length;
526 return 0;
528 error:
529 if (a->arg)
530 free (a->arg);
531 if (d->dir)
532 free (d->dir);
533 return -1;
536 #undef DIRECTIVES
537 #undef DIRECTIVE
538 #undef CHAR_T
539 #undef PRINTF_PARSE