Fix typo.
[shishi.git] / gl / printf-parse.c
blobbdfe88fe8f8942f57fe26295a34bd2bc5e35e9c2
1 /* Formatted output to strings.
2 Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
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.
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.
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. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 /* Specification. */
24 #include "printf-parse.h"
26 /* Get size_t, NULL. */
27 #include <stddef.h>
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
37 /* malloc(), realloc(), free(). */
38 #include <stdlib.h>
40 #ifdef STATIC
41 STATIC
42 #endif
43 int
44 printf_parse (const char *format, char_directives *d, arguments *a)
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;
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;
60 a->count = 0;
61 a_allocated = 0;
62 a->arg = NULL;
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; \
90 while (*cp != '\0')
92 char c = *cp++;
93 if (c == '%')
95 int arg_index = -1;
96 char_directive *dp = &d->dir[d->count];/* pointer to next directive */
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;
109 /* Test for positional argument. */
110 if (*cp >= '0' && *cp <= '9')
112 const char *np;
114 for (np = cp; *np >= '0' && *np <= '9'; np++)
116 if (*np == '$')
118 unsigned int n = 0;
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;
130 /* Read the flags. */
131 for (;;)
133 if (*cp == '\'')
135 dp->flags |= FLAG_GROUP;
136 cp++;
138 else if (*cp == '-')
140 dp->flags |= FLAG_LEFT;
141 cp++;
143 else if (*cp == '+')
145 dp->flags |= FLAG_SHOWSIGN;
146 cp++;
148 else if (*cp == ' ')
150 dp->flags |= FLAG_SPACE;
151 cp++;
153 else if (*cp == '#')
155 dp->flags |= FLAG_ALT;
156 cp++;
158 else if (*cp == '0')
160 dp->flags |= FLAG_ZERO;
161 cp++;
163 else
164 break;
167 /* Parse the field width. */
168 if (*cp == '*')
170 dp->width_start = cp;
171 cp++;
172 dp->width_end = cp;
173 if (max_width_length < 1)
174 max_width_length = 1;
176 /* Test for positional argument. */
177 if (*cp >= '0' && *cp <= '9')
179 const char *np;
181 for (np = cp; *np >= '0' && *np <= '9'; np++)
183 if (*np == '$')
185 unsigned int n = 0;
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;
196 if (dp->width_arg_index < 0)
197 dp->width_arg_index = arg_posn++;
198 REGISTER_ARG (dp->width_arg_index, TYPE_INT);
200 else if (*cp >= '0' && *cp <= '9')
202 unsigned int width_length;
204 dp->width_start = cp;
205 for (; *cp >= '0' && *cp <= '9'; cp++)
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;
213 /* Parse the precision. */
214 if (*cp == '.')
216 cp++;
217 if (*cp == '*')
219 dp->precision_start = cp - 1;
220 cp++;
221 dp->precision_end = cp;
222 if (max_precision_length < 2)
223 max_precision_length = 2;
225 /* Test for positional argument. */
226 if (*cp >= '0' && *cp <= '9')
228 const char *np;
230 for (np = cp; *np >= '0' && *np <= '9'; np++)
232 if (*np == '$')
234 unsigned int n = 0;
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;
245 if (dp->precision_arg_index < 0)
246 dp->precision_arg_index = arg_posn++;
247 REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
249 else
251 unsigned int precision_length;
253 dp->precision_start = cp - 1;
254 for (; *cp >= '0' && *cp <= '9'; cp++)
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;
264 arg_type type;
266 /* Parse argument type/size specifiers. */
268 int flags = 0;
270 for (;;)
272 if (*cp == 'h')
274 flags |= (1 << (flags & 1));
275 cp++;
277 else if (*cp == 'L')
279 flags |= 4;
280 cp++;
282 else if (*cp == 'l')
284 flags += 8;
285 cp++;
287 #ifdef HAVE_INTMAX_T
288 else if (*cp == 'j')
290 if (sizeof (intmax_t) > sizeof (long))
292 /* intmax_t = long long */
293 flags += 16;
295 else if (sizeof (intmax_t) > sizeof (int))
297 /* intmax_t = long */
298 flags += 8;
300 cp++;
302 #endif
303 else if (*cp == 'z' || *cp == 'Z')
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))
310 /* size_t = long long */
311 flags += 16;
313 else if (sizeof (size_t) > sizeof (int))
315 /* size_t = long */
316 flags += 8;
318 cp++;
320 else if (*cp == 't')
322 if (sizeof (ptrdiff_t) > sizeof (long))
324 /* ptrdiff_t = long long */
325 flags += 16;
327 else if (sizeof (ptrdiff_t) > sizeof (int))
329 /* ptrdiff_t = long */
330 flags += 8;
332 cp++;
334 else
335 break;
338 /* Read the conversion character. */
339 c = *cp++;
340 switch (c)
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;
440 if (type != TYPE_NONE)
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);
447 dp->conversion = c;
448 dp->dir_end = cp;
451 d->count++;
452 if (d->count >= d_allocated)
454 char_directive *memory;
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;
465 d->dir[d->count].dir_start = cp;
467 d->max_width_length = max_width_length;
468 d->max_precision_length = max_precision_length;
469 return 0;
471 error:
472 if (a->arg)
473 free (a->arg);
474 if (d->dir)
475 free (d->dir);
476 return -1;