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
5 it under the terms of the GNU 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 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
17 #include <sys/cdefs.h>
18 __RCSID("$NetBSD: printf-parse.c,v 1.2 2016/05/17 14:00:09 christos Exp $");
19
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 /* Specification. */
26 #if WIDE_CHAR_VERSION
27 # include "wprintf-parse.h"
28 #else
29 # include "printf-parse.h"
30 #endif
31
32 /* Get size_t, NULL. */
33 #include <stddef.h>
34
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
42
43 /* malloc(), realloc(), free(). */
44 #include <stdlib.h>
45
46 /* Checked size_t computations. */
47 #include "xsize.h"
48
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
60
61 #ifdef STATIC
62 STATIC
63 #endif
64 int
PRINTF_PARSE(const CHAR_T * format,DIRECTIVES * d,arguments * a)65 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
66 {
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;
73
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;
80
81 a->count = 0;
82 a_allocated = 0;
83 a->arg = NULL;
84
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; \
92 \
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; \
107 } \
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; \
115 }
116
117 while (*cp != '\0')
118 {
119 CHAR_T c = *cp++;
120 if (c == '%')
121 {
122 size_t arg_index = ARG_NONE;
123 DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
124
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;
135
136 /* Test for positional argument. */
137 if (*cp >= '0' && *cp <= '9')
138 {
139 const CHAR_T *np;
140
141 for (np = cp; *np >= '0' && *np <= '9'; np++)
142 ;
143 if (*np == '$')
144 {
145 size_t n = 0;
146
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;
157 }
158 }
159
160 /* Read the flags. */
161 for (;;)
162 {
163 if (*cp == '\'')
164 {
165 dp->flags |= FLAG_GROUP;
166 cp++;
167 }
168 else if (*cp == '-')
169 {
170 dp->flags |= FLAG_LEFT;
171 cp++;
172 }
173 else if (*cp == '+')
174 {
175 dp->flags |= FLAG_SHOWSIGN;
176 cp++;
177 }
178 else if (*cp == ' ')
179 {
180 dp->flags |= FLAG_SPACE;
181 cp++;
182 }
183 else if (*cp == '#')
184 {
185 dp->flags |= FLAG_ALT;
186 cp++;
187 }
188 else if (*cp == '0')
189 {
190 dp->flags |= FLAG_ZERO;
191 cp++;
192 }
193 else
194 break;
195 }
196
197 /* Parse the field width. */
198 if (*cp == '*')
199 {
200 dp->width_start = cp;
201 cp++;
202 dp->width_end = cp;
203 if (max_width_length < 1)
204 max_width_length = 1;
205
206 /* Test for positional argument. */
207 if (*cp >= '0' && *cp <= '9')
208 {
209 const CHAR_T *np;
210
211 for (np = cp; *np >= '0' && *np <= '9'; np++)
212 ;
213 if (*np == '$')
214 {
215 size_t n = 0;
216
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;
227 }
228 }
229 if (dp->width_arg_index == ARG_NONE)
230 {
231 dp->width_arg_index = arg_posn++;
232 if (dp->width_arg_index == ARG_NONE)
233 /* arg_posn wrapped around. */
234 goto error;
235 }
236 REGISTER_ARG (dp->width_arg_index, TYPE_INT);
237 }
238 else if (*cp >= '0' && *cp <= '9')
239 {
240 size_t width_length;
241
242 dp->width_start = cp;
243 for (; *cp >= '0' && *cp <= '9'; cp++)
244 ;
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;
249 }
250
251 /* Parse the precision. */
252 if (*cp == '.')
253 {
254 cp++;
255 if (*cp == '*')
256 {
257 dp->precision_start = cp - 1;
258 cp++;
259 dp->precision_end = cp;
260 if (max_precision_length < 2)
261 max_precision_length = 2;
262
263 /* Test for positional argument. */
264 if (*cp >= '0' && *cp <= '9')
265 {
266 const CHAR_T *np;
267
268 for (np = cp; *np >= '0' && *np <= '9'; np++)
269 ;
270 if (*np == '$')
271 {
272 size_t n = 0;
273
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;
285 }
286 }
287 if (dp->precision_arg_index == ARG_NONE)
288 {
289 dp->precision_arg_index = arg_posn++;
290 if (dp->precision_arg_index == ARG_NONE)
291 /* arg_posn wrapped around. */
292 goto error;
293 }
294 REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
295 }
296 else
297 {
298 size_t precision_length;
299
300 dp->precision_start = cp - 1;
301 for (; *cp >= '0' && *cp <= '9'; cp++)
302 ;
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;
307 }
308 }
309
310 {
311 arg_type type;
312
313 /* Parse argument type/size specifiers. */
314 {
315 int flags = 0;
316
317 for (;;)
318 {
319 if (*cp == 'h')
320 {
321 flags |= (1 << (flags & 1));
322 cp++;
323 }
324 else if (*cp == 'L')
325 {
326 flags |= 4;
327 cp++;
328 }
329 else if (*cp == 'l')
330 {
331 flags += 8;
332 cp++;
333 }
334 #ifdef HAVE_INTMAX_T
335 else if (*cp == 'j')
336 {
337 if (sizeof (intmax_t) > sizeof (long))
338 {
339 /* intmax_t = long long */
340 flags += 16;
341 }
342 else if (sizeof (intmax_t) > sizeof (int))
343 {
344 /* intmax_t = long */
345 flags += 8;
346 }
347 cp++;
348 }
349 #endif
350 else if (*cp == 'z' || *cp == 'Z')
351 {
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))
356 {
357 /* size_t = long long */
358 flags += 16;
359 }
360 else if (sizeof (size_t) > sizeof (int))
361 {
362 /* size_t = long */
363 flags += 8;
364 }
365 cp++;
366 }
367 else if (*cp == 't')
368 {
369 if (sizeof (ptrdiff_t) > sizeof (long))
370 {
371 /* ptrdiff_t = long long */
372 flags += 16;
373 }
374 else if (sizeof (ptrdiff_t) > sizeof (int))
375 {
376 /* ptrdiff_t = long */
377 flags += 8;
378 }
379 cp++;
380 }
381 else
382 break;
383 }
384
385 /* Read the conversion character. */
386 c = *cp++;
387 switch (c)
388 {
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;
484 }
485 }
486
487 if (type != TYPE_NONE)
488 {
489 dp->arg_index = arg_index;
490 if (dp->arg_index == ARG_NONE)
491 {
492 dp->arg_index = arg_posn++;
493 if (dp->arg_index == ARG_NONE)
494 /* arg_posn wrapped around. */
495 goto error;
496 }
497 REGISTER_ARG (dp->arg_index, type);
498 }
499 dp->conversion = c;
500 dp->dir_end = cp;
501 }
502
503 d->count++;
504 if (d->count >= d_allocated)
505 {
506 size_t memory_size;
507 DIRECTIVE *memory;
508
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;
519 }
520 }
521 }
522 d->dir[d->count].dir_start = cp;
523
524 d->max_width_length = max_width_length;
525 d->max_precision_length = max_precision_length;
526 return 0;
527
528 error:
529 if (a->arg)
530 free (a->arg);
531 if (d->dir)
532 free (d->dir);
533 return -1;
534 }
535
536 #undef DIRECTIVES
537 #undef DIRECTIVE
538 #undef CHAR_T
539 #undef PRINTF_PARSE
540