Commit | Line | Data |
---|---|---|
c4b681fd | 1 | /* Formatted output to strings. |
5e69ceb7 | 2 | Copyright (C) 1999-2000, 2002-2003, 2006-2014 Free Software Foundation, Inc. |
c4b681fd LC |
3 | |
4 | This program is free software; you can redistribute it and/or modify | |
5 | it under the terms of the GNU Lesser General Public License as published by | |
6 | 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 | |
12 | GNU Lesser General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public License along | |
005de2e8 | 15 | with this program; if not, see <http://www.gnu.org/licenses/>. */ |
c4b681fd LC |
16 | |
17 | /* This file can be parametrized with the following macros: | |
18 | CHAR_T The element type of the format string. | |
19 | CHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters | |
20 | in the format string are ASCII. | |
21 | DIRECTIVE Structure denoting a format directive. | |
22 | Depends on CHAR_T. | |
23 | DIRECTIVES Structure denoting the set of format directives of a | |
24 | format string. Depends on CHAR_T. | |
25 | PRINTF_PARSE Function that parses a format string. | |
26 | Depends on CHAR_T. | |
27 | STATIC Set to 'static' to declare the function static. | |
28 | ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions. */ | |
29 | ||
30 | #ifndef PRINTF_PARSE | |
31 | # include <config.h> | |
32 | #endif | |
33 | ||
34 | /* Specification. */ | |
35 | #ifndef PRINTF_PARSE | |
36 | # include "printf-parse.h" | |
37 | #endif | |
38 | ||
39 | /* Default parameters. */ | |
40 | #ifndef PRINTF_PARSE | |
41 | # define PRINTF_PARSE printf_parse | |
42 | # define CHAR_T char | |
43 | # define DIRECTIVE char_directive | |
44 | # define DIRECTIVES char_directives | |
45 | #endif | |
46 | ||
47 | /* Get size_t, NULL. */ | |
48 | #include <stddef.h> | |
49 | ||
50 | /* Get intmax_t. */ | |
51 | #if defined IN_LIBINTL || defined IN_LIBASPRINTF | |
52 | # if HAVE_STDINT_H_WITH_UINTMAX | |
53 | # include <stdint.h> | |
54 | # endif | |
55 | # if HAVE_INTTYPES_H_WITH_UINTMAX | |
56 | # include <inttypes.h> | |
57 | # endif | |
58 | #else | |
59 | # include <stdint.h> | |
60 | #endif | |
61 | ||
62 | /* malloc(), realloc(), free(). */ | |
63 | #include <stdlib.h> | |
64 | ||
49114fd4 LC |
65 | /* memcpy(). */ |
66 | #include <string.h> | |
67 | ||
c4b681fd LC |
68 | /* errno. */ |
69 | #include <errno.h> | |
70 | ||
71 | /* Checked size_t computations. */ | |
72 | #include "xsize.h" | |
73 | ||
74 | #if CHAR_T_ONLY_ASCII | |
75 | /* c_isascii(). */ | |
76 | # include "c-ctype.h" | |
77 | #endif | |
78 | ||
79 | #ifdef STATIC | |
80 | STATIC | |
81 | #endif | |
82 | int | |
83 | PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | |
84 | { | |
49114fd4 | 85 | const CHAR_T *cp = format; /* pointer into format */ |
1cd4fffc | 86 | size_t arg_posn = 0; /* number of regular arguments consumed */ |
49114fd4 LC |
87 | size_t d_allocated; /* allocated elements of d->dir */ |
88 | size_t a_allocated; /* allocated elements of a->arg */ | |
c4b681fd LC |
89 | size_t max_width_length = 0; |
90 | size_t max_precision_length = 0; | |
91 | ||
92 | d->count = 0; | |
49114fd4 LC |
93 | d_allocated = N_DIRECT_ALLOC_DIRECTIVES; |
94 | d->dir = d->direct_alloc_dir; | |
c4b681fd LC |
95 | |
96 | a->count = 0; | |
49114fd4 LC |
97 | a_allocated = N_DIRECT_ALLOC_ARGUMENTS; |
98 | a->arg = a->direct_alloc_arg; | |
c4b681fd LC |
99 | |
100 | #define REGISTER_ARG(_index_,_type_) \ | |
1cd4fffc LC |
101 | { \ |
102 | size_t n = (_index_); \ | |
103 | if (n >= a_allocated) \ | |
104 | { \ | |
105 | size_t memory_size; \ | |
106 | argument *memory; \ | |
107 | \ | |
108 | a_allocated = xtimes (a_allocated, 2); \ | |
109 | if (a_allocated <= n) \ | |
110 | a_allocated = xsum (n, 1); \ | |
111 | memory_size = xtimes (a_allocated, sizeof (argument)); \ | |
112 | if (size_overflow_p (memory_size)) \ | |
113 | /* Overflow, would lead to out of memory. */ \ | |
114 | goto out_of_memory; \ | |
49114fd4 | 115 | memory = (argument *) (a->arg != a->direct_alloc_arg \ |
1cd4fffc LC |
116 | ? realloc (a->arg, memory_size) \ |
117 | : malloc (memory_size)); \ | |
118 | if (memory == NULL) \ | |
119 | /* Out of memory. */ \ | |
120 | goto out_of_memory; \ | |
49114fd4 LC |
121 | if (a->arg == a->direct_alloc_arg) \ |
122 | memcpy (memory, a->arg, a->count * sizeof (argument)); \ | |
1cd4fffc LC |
123 | a->arg = memory; \ |
124 | } \ | |
125 | while (a->count <= n) \ | |
126 | a->arg[a->count++].type = TYPE_NONE; \ | |
127 | if (a->arg[n].type == TYPE_NONE) \ | |
128 | a->arg[n].type = (_type_); \ | |
129 | else if (a->arg[n].type != (_type_)) \ | |
130 | /* Ambiguous type for positional argument. */ \ | |
131 | goto error; \ | |
c4b681fd LC |
132 | } |
133 | ||
134 | while (*cp != '\0') | |
135 | { | |
136 | CHAR_T c = *cp++; | |
137 | if (c == '%') | |
1cd4fffc LC |
138 | { |
139 | size_t arg_index = ARG_NONE; | |
140 | DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */ | |
141 | ||
142 | /* Initialize the next directive. */ | |
143 | dp->dir_start = cp - 1; | |
144 | dp->flags = 0; | |
145 | dp->width_start = NULL; | |
146 | dp->width_end = NULL; | |
147 | dp->width_arg_index = ARG_NONE; | |
148 | dp->precision_start = NULL; | |
149 | dp->precision_end = NULL; | |
150 | dp->precision_arg_index = ARG_NONE; | |
151 | dp->arg_index = ARG_NONE; | |
152 | ||
153 | /* Test for positional argument. */ | |
154 | if (*cp >= '0' && *cp <= '9') | |
155 | { | |
156 | const CHAR_T *np; | |
157 | ||
158 | for (np = cp; *np >= '0' && *np <= '9'; np++) | |
159 | ; | |
160 | if (*np == '$') | |
161 | { | |
162 | size_t n = 0; | |
163 | ||
164 | for (np = cp; *np >= '0' && *np <= '9'; np++) | |
165 | n = xsum (xtimes (n, 10), *np - '0'); | |
166 | if (n == 0) | |
167 | /* Positional argument 0. */ | |
168 | goto error; | |
169 | if (size_overflow_p (n)) | |
170 | /* n too large, would lead to out of memory later. */ | |
171 | goto error; | |
172 | arg_index = n - 1; | |
173 | cp = np + 1; | |
174 | } | |
175 | } | |
176 | ||
177 | /* Read the flags. */ | |
178 | for (;;) | |
179 | { | |
180 | if (*cp == '\'') | |
181 | { | |
182 | dp->flags |= FLAG_GROUP; | |
183 | cp++; | |
184 | } | |
185 | else if (*cp == '-') | |
186 | { | |
187 | dp->flags |= FLAG_LEFT; | |
188 | cp++; | |
189 | } | |
190 | else if (*cp == '+') | |
191 | { | |
192 | dp->flags |= FLAG_SHOWSIGN; | |
193 | cp++; | |
194 | } | |
195 | else if (*cp == ' ') | |
196 | { | |
197 | dp->flags |= FLAG_SPACE; | |
198 | cp++; | |
199 | } | |
200 | else if (*cp == '#') | |
201 | { | |
202 | dp->flags |= FLAG_ALT; | |
203 | cp++; | |
204 | } | |
205 | else if (*cp == '0') | |
206 | { | |
207 | dp->flags |= FLAG_ZERO; | |
208 | cp++; | |
209 | } | |
0f00f2c3 LC |
210 | #if __GLIBC__ >= 2 && !defined __UCLIBC__ |
211 | else if (*cp == 'I') | |
212 | { | |
213 | dp->flags |= FLAG_LOCALIZED; | |
214 | cp++; | |
215 | } | |
216 | #endif | |
1cd4fffc LC |
217 | else |
218 | break; | |
219 | } | |
220 | ||
221 | /* Parse the field width. */ | |
222 | if (*cp == '*') | |
223 | { | |
224 | dp->width_start = cp; | |
225 | cp++; | |
226 | dp->width_end = cp; | |
227 | if (max_width_length < 1) | |
228 | max_width_length = 1; | |
229 | ||
230 | /* Test for positional argument. */ | |
231 | if (*cp >= '0' && *cp <= '9') | |
232 | { | |
233 | const CHAR_T *np; | |
234 | ||
235 | for (np = cp; *np >= '0' && *np <= '9'; np++) | |
236 | ; | |
237 | if (*np == '$') | |
238 | { | |
239 | size_t n = 0; | |
240 | ||
241 | for (np = cp; *np >= '0' && *np <= '9'; np++) | |
242 | n = xsum (xtimes (n, 10), *np - '0'); | |
243 | if (n == 0) | |
244 | /* Positional argument 0. */ | |
245 | goto error; | |
246 | if (size_overflow_p (n)) | |
247 | /* n too large, would lead to out of memory later. */ | |
248 | goto error; | |
249 | dp->width_arg_index = n - 1; | |
250 | cp = np + 1; | |
251 | } | |
252 | } | |
253 | if (dp->width_arg_index == ARG_NONE) | |
254 | { | |
255 | dp->width_arg_index = arg_posn++; | |
256 | if (dp->width_arg_index == ARG_NONE) | |
257 | /* arg_posn wrapped around. */ | |
258 | goto error; | |
259 | } | |
260 | REGISTER_ARG (dp->width_arg_index, TYPE_INT); | |
261 | } | |
262 | else if (*cp >= '0' && *cp <= '9') | |
263 | { | |
264 | size_t width_length; | |
265 | ||
266 | dp->width_start = cp; | |
267 | for (; *cp >= '0' && *cp <= '9'; cp++) | |
268 | ; | |
269 | dp->width_end = cp; | |
270 | width_length = dp->width_end - dp->width_start; | |
271 | if (max_width_length < width_length) | |
272 | max_width_length = width_length; | |
273 | } | |
274 | ||
275 | /* Parse the precision. */ | |
276 | if (*cp == '.') | |
277 | { | |
278 | cp++; | |
279 | if (*cp == '*') | |
280 | { | |
281 | dp->precision_start = cp - 1; | |
282 | cp++; | |
283 | dp->precision_end = cp; | |
284 | if (max_precision_length < 2) | |
285 | max_precision_length = 2; | |
286 | ||
287 | /* Test for positional argument. */ | |
288 | if (*cp >= '0' && *cp <= '9') | |
289 | { | |
290 | const CHAR_T *np; | |
291 | ||
292 | for (np = cp; *np >= '0' && *np <= '9'; np++) | |
293 | ; | |
294 | if (*np == '$') | |
295 | { | |
296 | size_t n = 0; | |
297 | ||
298 | for (np = cp; *np >= '0' && *np <= '9'; np++) | |
299 | n = xsum (xtimes (n, 10), *np - '0'); | |
300 | if (n == 0) | |
301 | /* Positional argument 0. */ | |
302 | goto error; | |
303 | if (size_overflow_p (n)) | |
304 | /* n too large, would lead to out of memory | |
305 | later. */ | |
306 | goto error; | |
307 | dp->precision_arg_index = n - 1; | |
308 | cp = np + 1; | |
309 | } | |
310 | } | |
311 | if (dp->precision_arg_index == ARG_NONE) | |
312 | { | |
313 | dp->precision_arg_index = arg_posn++; | |
314 | if (dp->precision_arg_index == ARG_NONE) | |
315 | /* arg_posn wrapped around. */ | |
316 | goto error; | |
317 | } | |
318 | REGISTER_ARG (dp->precision_arg_index, TYPE_INT); | |
319 | } | |
320 | else | |
321 | { | |
322 | size_t precision_length; | |
323 | ||
324 | dp->precision_start = cp - 1; | |
325 | for (; *cp >= '0' && *cp <= '9'; cp++) | |
326 | ; | |
327 | dp->precision_end = cp; | |
328 | precision_length = dp->precision_end - dp->precision_start; | |
329 | if (max_precision_length < precision_length) | |
330 | max_precision_length = precision_length; | |
331 | } | |
332 | } | |
333 | ||
334 | { | |
335 | arg_type type; | |
336 | ||
337 | /* Parse argument type/size specifiers. */ | |
338 | { | |
339 | int flags = 0; | |
340 | ||
341 | for (;;) | |
342 | { | |
343 | if (*cp == 'h') | |
344 | { | |
345 | flags |= (1 << (flags & 1)); | |
346 | cp++; | |
347 | } | |
348 | else if (*cp == 'L') | |
349 | { | |
350 | flags |= 4; | |
351 | cp++; | |
352 | } | |
353 | else if (*cp == 'l') | |
354 | { | |
355 | flags += 8; | |
356 | cp++; | |
357 | } | |
358 | else if (*cp == 'j') | |
359 | { | |
360 | if (sizeof (intmax_t) > sizeof (long)) | |
361 | { | |
362 | /* intmax_t = long long */ | |
363 | flags += 16; | |
364 | } | |
365 | else if (sizeof (intmax_t) > sizeof (int)) | |
366 | { | |
367 | /* intmax_t = long */ | |
368 | flags += 8; | |
369 | } | |
370 | cp++; | |
371 | } | |
372 | else if (*cp == 'z' || *cp == 'Z') | |
373 | { | |
374 | /* 'z' is standardized in ISO C 99, but glibc uses 'Z' | |
375 | because the warning facility in gcc-2.95.2 understands | |
376 | only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ | |
377 | if (sizeof (size_t) > sizeof (long)) | |
378 | { | |
379 | /* size_t = long long */ | |
380 | flags += 16; | |
381 | } | |
382 | else if (sizeof (size_t) > sizeof (int)) | |
383 | { | |
384 | /* size_t = long */ | |
385 | flags += 8; | |
386 | } | |
387 | cp++; | |
388 | } | |
389 | else if (*cp == 't') | |
390 | { | |
391 | if (sizeof (ptrdiff_t) > sizeof (long)) | |
392 | { | |
393 | /* ptrdiff_t = long long */ | |
394 | flags += 16; | |
395 | } | |
396 | else if (sizeof (ptrdiff_t) > sizeof (int)) | |
397 | { | |
398 | /* ptrdiff_t = long */ | |
399 | flags += 8; | |
400 | } | |
401 | cp++; | |
402 | } | |
c4b681fd | 403 | #if defined __APPLE__ && defined __MACH__ |
005de2e8 | 404 | /* On Mac OS X 10.3, PRIdMAX is defined as "qd". |
1cd4fffc LC |
405 | We cannot change it to "lld" because PRIdMAX must also |
406 | be understood by the system's printf routines. */ | |
407 | else if (*cp == 'q') | |
408 | { | |
409 | if (64 / 8 > sizeof (long)) | |
410 | { | |
411 | /* int64_t = long long */ | |
412 | flags += 16; | |
413 | } | |
414 | else | |
415 | { | |
416 | /* int64_t = long */ | |
417 | flags += 8; | |
418 | } | |
419 | cp++; | |
420 | } | |
c4b681fd LC |
421 | #endif |
422 | #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | |
f0007cad | 423 | /* On native Windows, PRIdMAX is defined as "I64d". |
1cd4fffc LC |
424 | We cannot change it to "lld" because PRIdMAX must also |
425 | be understood by the system's printf routines. */ | |
426 | else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4') | |
427 | { | |
428 | if (64 / 8 > sizeof (long)) | |
429 | { | |
430 | /* __int64 = long long */ | |
431 | flags += 16; | |
432 | } | |
433 | else | |
434 | { | |
435 | /* __int64 = long */ | |
436 | flags += 8; | |
437 | } | |
438 | cp += 3; | |
439 | } | |
c4b681fd | 440 | #endif |
1cd4fffc LC |
441 | else |
442 | break; | |
443 | } | |
444 | ||
445 | /* Read the conversion character. */ | |
446 | c = *cp++; | |
447 | switch (c) | |
448 | { | |
449 | case 'd': case 'i': | |
c4b681fd | 450 | #if HAVE_LONG_LONG_INT |
1cd4fffc LC |
451 | /* If 'long long' exists and is larger than 'long': */ |
452 | if (flags >= 16 || (flags & 4)) | |
453 | type = TYPE_LONGLONGINT; | |
454 | else | |
c4b681fd | 455 | #endif |
1cd4fffc LC |
456 | /* If 'long long' exists and is the same as 'long', we parse |
457 | "lld" into TYPE_LONGINT. */ | |
458 | if (flags >= 8) | |
459 | type = TYPE_LONGINT; | |
460 | else if (flags & 2) | |
461 | type = TYPE_SCHAR; | |
462 | else if (flags & 1) | |
463 | type = TYPE_SHORT; | |
464 | else | |
465 | type = TYPE_INT; | |
466 | break; | |
467 | case 'o': case 'u': case 'x': case 'X': | |
c4b681fd | 468 | #if HAVE_LONG_LONG_INT |
1cd4fffc LC |
469 | /* If 'long long' exists and is larger than 'long': */ |
470 | if (flags >= 16 || (flags & 4)) | |
471 | type = TYPE_ULONGLONGINT; | |
472 | else | |
c4b681fd | 473 | #endif |
1cd4fffc LC |
474 | /* If 'unsigned long long' exists and is the same as |
475 | 'unsigned long', we parse "llu" into TYPE_ULONGINT. */ | |
476 | if (flags >= 8) | |
477 | type = TYPE_ULONGINT; | |
478 | else if (flags & 2) | |
479 | type = TYPE_UCHAR; | |
480 | else if (flags & 1) | |
481 | type = TYPE_USHORT; | |
482 | else | |
483 | type = TYPE_UINT; | |
484 | break; | |
485 | case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': | |
486 | case 'a': case 'A': | |
487 | if (flags >= 16 || (flags & 4)) | |
488 | type = TYPE_LONGDOUBLE; | |
489 | else | |
490 | type = TYPE_DOUBLE; | |
491 | break; | |
492 | case 'c': | |
493 | if (flags >= 8) | |
c4b681fd | 494 | #if HAVE_WINT_T |
1cd4fffc | 495 | type = TYPE_WIDE_CHAR; |
c4b681fd | 496 | #else |
1cd4fffc | 497 | goto error; |
c4b681fd | 498 | #endif |
1cd4fffc LC |
499 | else |
500 | type = TYPE_CHAR; | |
501 | break; | |
c4b681fd | 502 | #if HAVE_WINT_T |
1cd4fffc LC |
503 | case 'C': |
504 | type = TYPE_WIDE_CHAR; | |
505 | c = 'c'; | |
506 | break; | |
c4b681fd | 507 | #endif |
1cd4fffc LC |
508 | case 's': |
509 | if (flags >= 8) | |
c4b681fd | 510 | #if HAVE_WCHAR_T |
1cd4fffc | 511 | type = TYPE_WIDE_STRING; |
c4b681fd | 512 | #else |
1cd4fffc | 513 | goto error; |
c4b681fd | 514 | #endif |
1cd4fffc LC |
515 | else |
516 | type = TYPE_STRING; | |
517 | break; | |
c4b681fd | 518 | #if HAVE_WCHAR_T |
1cd4fffc LC |
519 | case 'S': |
520 | type = TYPE_WIDE_STRING; | |
521 | c = 's'; | |
522 | break; | |
c4b681fd | 523 | #endif |
1cd4fffc LC |
524 | case 'p': |
525 | type = TYPE_POINTER; | |
526 | break; | |
527 | case 'n': | |
c4b681fd | 528 | #if HAVE_LONG_LONG_INT |
1cd4fffc LC |
529 | /* If 'long long' exists and is larger than 'long': */ |
530 | if (flags >= 16 || (flags & 4)) | |
531 | type = TYPE_COUNT_LONGLONGINT_POINTER; | |
532 | else | |
c4b681fd | 533 | #endif |
1cd4fffc LC |
534 | /* If 'long long' exists and is the same as 'long', we parse |
535 | "lln" into TYPE_COUNT_LONGINT_POINTER. */ | |
536 | if (flags >= 8) | |
537 | type = TYPE_COUNT_LONGINT_POINTER; | |
538 | else if (flags & 2) | |
539 | type = TYPE_COUNT_SCHAR_POINTER; | |
540 | else if (flags & 1) | |
541 | type = TYPE_COUNT_SHORT_POINTER; | |
542 | else | |
543 | type = TYPE_COUNT_INT_POINTER; | |
544 | break; | |
c4b681fd | 545 | #if ENABLE_UNISTDIO |
1cd4fffc LC |
546 | /* The unistdio extensions. */ |
547 | case 'U': | |
548 | if (flags >= 16) | |
549 | type = TYPE_U32_STRING; | |
550 | else if (flags >= 8) | |
551 | type = TYPE_U16_STRING; | |
552 | else | |
553 | type = TYPE_U8_STRING; | |
554 | break; | |
c4b681fd | 555 | #endif |
1cd4fffc LC |
556 | case '%': |
557 | type = TYPE_NONE; | |
558 | break; | |
559 | default: | |
560 | /* Unknown conversion character. */ | |
561 | goto error; | |
562 | } | |
563 | } | |
564 | ||
565 | if (type != TYPE_NONE) | |
566 | { | |
567 | dp->arg_index = arg_index; | |
568 | if (dp->arg_index == ARG_NONE) | |
569 | { | |
570 | dp->arg_index = arg_posn++; | |
571 | if (dp->arg_index == ARG_NONE) | |
572 | /* arg_posn wrapped around. */ | |
573 | goto error; | |
574 | } | |
575 | REGISTER_ARG (dp->arg_index, type); | |
576 | } | |
577 | dp->conversion = c; | |
578 | dp->dir_end = cp; | |
579 | } | |
580 | ||
581 | d->count++; | |
582 | if (d->count >= d_allocated) | |
583 | { | |
584 | size_t memory_size; | |
585 | DIRECTIVE *memory; | |
586 | ||
587 | d_allocated = xtimes (d_allocated, 2); | |
588 | memory_size = xtimes (d_allocated, sizeof (DIRECTIVE)); | |
589 | if (size_overflow_p (memory_size)) | |
590 | /* Overflow, would lead to out of memory. */ | |
591 | goto out_of_memory; | |
49114fd4 LC |
592 | memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir |
593 | ? realloc (d->dir, memory_size) | |
594 | : malloc (memory_size)); | |
1cd4fffc LC |
595 | if (memory == NULL) |
596 | /* Out of memory. */ | |
597 | goto out_of_memory; | |
49114fd4 LC |
598 | if (d->dir == d->direct_alloc_dir) |
599 | memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE)); | |
1cd4fffc LC |
600 | d->dir = memory; |
601 | } | |
602 | } | |
c4b681fd LC |
603 | #if CHAR_T_ONLY_ASCII |
604 | else if (!c_isascii (c)) | |
1cd4fffc LC |
605 | { |
606 | /* Non-ASCII character. Not supported. */ | |
607 | goto error; | |
608 | } | |
c4b681fd LC |
609 | #endif |
610 | } | |
611 | d->dir[d->count].dir_start = cp; | |
612 | ||
613 | d->max_width_length = max_width_length; | |
614 | d->max_precision_length = max_precision_length; | |
615 | return 0; | |
616 | ||
617 | error: | |
49114fd4 | 618 | if (a->arg != a->direct_alloc_arg) |
c4b681fd | 619 | free (a->arg); |
49114fd4 | 620 | if (d->dir != d->direct_alloc_dir) |
c4b681fd LC |
621 | free (d->dir); |
622 | errno = EINVAL; | |
623 | return -1; | |
624 | ||
625 | out_of_memory: | |
49114fd4 | 626 | if (a->arg != a->direct_alloc_arg) |
c4b681fd | 627 | free (a->arg); |
49114fd4 | 628 | if (d->dir != d->direct_alloc_dir) |
c4b681fd | 629 | free (d->dir); |
c4b681fd LC |
630 | errno = ENOMEM; |
631 | return -1; | |
632 | } | |
633 | ||
634 | #undef PRINTF_PARSE | |
635 | #undef DIRECTIVES | |
636 | #undef DIRECTIVE | |
637 | #undef CHAR_T_ONLY_ASCII | |
638 | #undef CHAR_T |