diff options
Diffstat (limited to 'gl/vasnprintf.c')
-rw-r--r-- | gl/vasnprintf.c | 889 |
1 files changed, 889 insertions, 0 deletions
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c new file mode 100644 index 00000000..0fe2aada --- /dev/null +++ b/gl/vasnprintf.c | |||
@@ -0,0 +1,889 @@ | |||
1 | /* vsprintf with automatic memory allocation. | ||
2 | Copyright (C) 1999, 2002-2006 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 | |||
18 | /* Tell glibc's <stdio.h> to provide a prototype for snprintf(). | ||
19 | This must come before <config.h> because <config.h> may include | ||
20 | <features.h>, and once <features.h> has been included, it's too late. */ | ||
21 | #ifndef _GNU_SOURCE | ||
22 | # define _GNU_SOURCE 1 | ||
23 | #endif | ||
24 | |||
25 | #include <config.h> | ||
26 | #ifndef IN_LIBINTL | ||
27 | # include <alloca.h> | ||
28 | #endif | ||
29 | |||
30 | /* Specification. */ | ||
31 | #if WIDE_CHAR_VERSION | ||
32 | # include "vasnwprintf.h" | ||
33 | #else | ||
34 | # include "vasnprintf.h" | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> /* snprintf(), sprintf() */ | ||
38 | #include <stdlib.h> /* abort(), malloc(), realloc(), free() */ | ||
39 | #include <string.h> /* memcpy(), strlen() */ | ||
40 | #include <errno.h> /* errno */ | ||
41 | #include <limits.h> /* CHAR_BIT */ | ||
42 | #include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ | ||
43 | #if WIDE_CHAR_VERSION | ||
44 | # include "wprintf-parse.h" | ||
45 | #else | ||
46 | # include "printf-parse.h" | ||
47 | #endif | ||
48 | |||
49 | /* Checked size_t computations. */ | ||
50 | #include "xsize.h" | ||
51 | |||
52 | #ifdef HAVE_WCHAR_T | ||
53 | # ifdef HAVE_WCSLEN | ||
54 | # define local_wcslen wcslen | ||
55 | # else | ||
56 | /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid | ||
57 | a dependency towards this library, here is a local substitute. | ||
58 | Define this substitute only once, even if this file is included | ||
59 | twice in the same compilation unit. */ | ||
60 | # ifndef local_wcslen_defined | ||
61 | # define local_wcslen_defined 1 | ||
62 | static size_t | ||
63 | local_wcslen (const wchar_t *s) | ||
64 | { | ||
65 | const wchar_t *ptr; | ||
66 | |||
67 | for (ptr = s; *ptr != (wchar_t) 0; ptr++) | ||
68 | ; | ||
69 | return ptr - s; | ||
70 | } | ||
71 | # endif | ||
72 | # endif | ||
73 | #endif | ||
74 | |||
75 | #if WIDE_CHAR_VERSION | ||
76 | # define VASNPRINTF vasnwprintf | ||
77 | # define CHAR_T wchar_t | ||
78 | # define DIRECTIVE wchar_t_directive | ||
79 | # define DIRECTIVES wchar_t_directives | ||
80 | # define PRINTF_PARSE wprintf_parse | ||
81 | # define USE_SNPRINTF 1 | ||
82 | # if HAVE_DECL__SNWPRINTF | ||
83 | /* On Windows, the function swprintf() has a different signature than | ||
84 | on Unix; we use the _snwprintf() function instead. */ | ||
85 | # define SNPRINTF _snwprintf | ||
86 | # else | ||
87 | /* Unix. */ | ||
88 | # define SNPRINTF swprintf | ||
89 | # endif | ||
90 | #else | ||
91 | # define VASNPRINTF vasnprintf | ||
92 | # define CHAR_T char | ||
93 | # define DIRECTIVE char_directive | ||
94 | # define DIRECTIVES char_directives | ||
95 | # define PRINTF_PARSE printf_parse | ||
96 | # define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) | ||
97 | # if HAVE_DECL__SNPRINTF | ||
98 | /* Windows. */ | ||
99 | # define SNPRINTF _snprintf | ||
100 | # else | ||
101 | /* Unix. */ | ||
102 | # define SNPRINTF snprintf | ||
103 | # endif | ||
104 | #endif | ||
105 | |||
106 | CHAR_T * | ||
107 | VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) | ||
108 | { | ||
109 | DIRECTIVES d; | ||
110 | arguments a; | ||
111 | |||
112 | if (PRINTF_PARSE (format, &d, &a) < 0) | ||
113 | { | ||
114 | errno = EINVAL; | ||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | #define CLEANUP() \ | ||
119 | free (d.dir); \ | ||
120 | if (a.arg) \ | ||
121 | free (a.arg); | ||
122 | |||
123 | if (printf_fetchargs (args, &a) < 0) | ||
124 | { | ||
125 | CLEANUP (); | ||
126 | errno = EINVAL; | ||
127 | return NULL; | ||
128 | } | ||
129 | |||
130 | { | ||
131 | size_t buf_neededlength; | ||
132 | CHAR_T *buf; | ||
133 | CHAR_T *buf_malloced; | ||
134 | const CHAR_T *cp; | ||
135 | size_t i; | ||
136 | DIRECTIVE *dp; | ||
137 | /* Output string accumulator. */ | ||
138 | CHAR_T *result; | ||
139 | size_t allocated; | ||
140 | size_t length; | ||
141 | |||
142 | /* Allocate a small buffer that will hold a directive passed to | ||
143 | sprintf or snprintf. */ | ||
144 | buf_neededlength = | ||
145 | xsum4 (7, d.max_width_length, d.max_precision_length, 6); | ||
146 | #if HAVE_ALLOCA | ||
147 | if (buf_neededlength < 4000 / sizeof (CHAR_T)) | ||
148 | { | ||
149 | buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T)); | ||
150 | buf_malloced = NULL; | ||
151 | } | ||
152 | else | ||
153 | #endif | ||
154 | { | ||
155 | size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T)); | ||
156 | if (size_overflow_p (buf_memsize)) | ||
157 | goto out_of_memory_1; | ||
158 | buf = (CHAR_T *) malloc (buf_memsize); | ||
159 | if (buf == NULL) | ||
160 | goto out_of_memory_1; | ||
161 | buf_malloced = buf; | ||
162 | } | ||
163 | |||
164 | if (resultbuf != NULL) | ||
165 | { | ||
166 | result = resultbuf; | ||
167 | allocated = *lengthp; | ||
168 | } | ||
169 | else | ||
170 | { | ||
171 | result = NULL; | ||
172 | allocated = 0; | ||
173 | } | ||
174 | length = 0; | ||
175 | /* Invariants: | ||
176 | result is either == resultbuf or == NULL or malloc-allocated. | ||
177 | If length > 0, then result != NULL. */ | ||
178 | |||
179 | /* Ensures that allocated >= needed. Aborts through a jump to | ||
180 | out_of_memory if needed is SIZE_MAX or otherwise too big. */ | ||
181 | #define ENSURE_ALLOCATION(needed) \ | ||
182 | if ((needed) > allocated) \ | ||
183 | { \ | ||
184 | size_t memory_size; \ | ||
185 | CHAR_T *memory; \ | ||
186 | \ | ||
187 | allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \ | ||
188 | if ((needed) > allocated) \ | ||
189 | allocated = (needed); \ | ||
190 | memory_size = xtimes (allocated, sizeof (CHAR_T)); \ | ||
191 | if (size_overflow_p (memory_size)) \ | ||
192 | goto out_of_memory; \ | ||
193 | if (result == resultbuf || result == NULL) \ | ||
194 | memory = (CHAR_T *) malloc (memory_size); \ | ||
195 | else \ | ||
196 | memory = (CHAR_T *) realloc (result, memory_size); \ | ||
197 | if (memory == NULL) \ | ||
198 | goto out_of_memory; \ | ||
199 | if (result == resultbuf && length > 0) \ | ||
200 | memcpy (memory, result, length * sizeof (CHAR_T)); \ | ||
201 | result = memory; \ | ||
202 | } | ||
203 | |||
204 | for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) | ||
205 | { | ||
206 | if (cp != dp->dir_start) | ||
207 | { | ||
208 | size_t n = dp->dir_start - cp; | ||
209 | size_t augmented_length = xsum (length, n); | ||
210 | |||
211 | ENSURE_ALLOCATION (augmented_length); | ||
212 | memcpy (result + length, cp, n * sizeof (CHAR_T)); | ||
213 | length = augmented_length; | ||
214 | } | ||
215 | if (i == d.count) | ||
216 | break; | ||
217 | |||
218 | /* Execute a single directive. */ | ||
219 | if (dp->conversion == '%') | ||
220 | { | ||
221 | size_t augmented_length; | ||
222 | |||
223 | if (!(dp->arg_index == ARG_NONE)) | ||
224 | abort (); | ||
225 | augmented_length = xsum (length, 1); | ||
226 | ENSURE_ALLOCATION (augmented_length); | ||
227 | result[length] = '%'; | ||
228 | length = augmented_length; | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | if (!(dp->arg_index != ARG_NONE)) | ||
233 | abort (); | ||
234 | |||
235 | if (dp->conversion == 'n') | ||
236 | { | ||
237 | switch (a.arg[dp->arg_index].type) | ||
238 | { | ||
239 | case TYPE_COUNT_SCHAR_POINTER: | ||
240 | *a.arg[dp->arg_index].a.a_count_schar_pointer = length; | ||
241 | break; | ||
242 | case TYPE_COUNT_SHORT_POINTER: | ||
243 | *a.arg[dp->arg_index].a.a_count_short_pointer = length; | ||
244 | break; | ||
245 | case TYPE_COUNT_INT_POINTER: | ||
246 | *a.arg[dp->arg_index].a.a_count_int_pointer = length; | ||
247 | break; | ||
248 | case TYPE_COUNT_LONGINT_POINTER: | ||
249 | *a.arg[dp->arg_index].a.a_count_longint_pointer = length; | ||
250 | break; | ||
251 | #ifdef HAVE_LONG_LONG_INT | ||
252 | case TYPE_COUNT_LONGLONGINT_POINTER: | ||
253 | *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; | ||
254 | break; | ||
255 | #endif | ||
256 | default: | ||
257 | abort (); | ||
258 | } | ||
259 | } | ||
260 | else | ||
261 | { | ||
262 | arg_type type = a.arg[dp->arg_index].type; | ||
263 | CHAR_T *p; | ||
264 | unsigned int prefix_count; | ||
265 | int prefixes[2]; | ||
266 | #if !USE_SNPRINTF | ||
267 | size_t tmp_length; | ||
268 | CHAR_T tmpbuf[700]; | ||
269 | CHAR_T *tmp; | ||
270 | |||
271 | /* Allocate a temporary buffer of sufficient size for calling | ||
272 | sprintf. */ | ||
273 | { | ||
274 | size_t width; | ||
275 | size_t precision; | ||
276 | |||
277 | width = 0; | ||
278 | if (dp->width_start != dp->width_end) | ||
279 | { | ||
280 | if (dp->width_arg_index != ARG_NONE) | ||
281 | { | ||
282 | int arg; | ||
283 | |||
284 | if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) | ||
285 | abort (); | ||
286 | arg = a.arg[dp->width_arg_index].a.a_int; | ||
287 | width = (arg < 0 ? (unsigned int) (-arg) : arg); | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | const CHAR_T *digitp = dp->width_start; | ||
292 | |||
293 | do | ||
294 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | ||
295 | while (digitp != dp->width_end); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | precision = 6; | ||
300 | if (dp->precision_start != dp->precision_end) | ||
301 | { | ||
302 | if (dp->precision_arg_index != ARG_NONE) | ||
303 | { | ||
304 | int arg; | ||
305 | |||
306 | if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) | ||
307 | abort (); | ||
308 | arg = a.arg[dp->precision_arg_index].a.a_int; | ||
309 | precision = (arg < 0 ? 0 : arg); | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | const CHAR_T *digitp = dp->precision_start + 1; | ||
314 | |||
315 | precision = 0; | ||
316 | while (digitp != dp->precision_end) | ||
317 | precision = xsum (xtimes (precision, 10), *digitp++ - '0'); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | switch (dp->conversion) | ||
322 | { | ||
323 | |||
324 | case 'd': case 'i': case 'u': | ||
325 | # ifdef HAVE_LONG_LONG_INT | ||
326 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
327 | tmp_length = | ||
328 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
329 | * 0.30103 /* binary -> decimal */ | ||
330 | ) | ||
331 | + 1; /* turn floor into ceil */ | ||
332 | else | ||
333 | # endif | ||
334 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
335 | tmp_length = | ||
336 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
337 | * 0.30103 /* binary -> decimal */ | ||
338 | ) | ||
339 | + 1; /* turn floor into ceil */ | ||
340 | else | ||
341 | tmp_length = | ||
342 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
343 | * 0.30103 /* binary -> decimal */ | ||
344 | ) | ||
345 | + 1; /* turn floor into ceil */ | ||
346 | if (tmp_length < precision) | ||
347 | tmp_length = precision; | ||
348 | /* Multiply by 2, as an estimate for FLAG_GROUP. */ | ||
349 | tmp_length = xsum (tmp_length, tmp_length); | ||
350 | /* Add 1, to account for a leading sign. */ | ||
351 | tmp_length = xsum (tmp_length, 1); | ||
352 | break; | ||
353 | |||
354 | case 'o': | ||
355 | # ifdef HAVE_LONG_LONG_INT | ||
356 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
357 | tmp_length = | ||
358 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
359 | * 0.333334 /* binary -> octal */ | ||
360 | ) | ||
361 | + 1; /* turn floor into ceil */ | ||
362 | else | ||
363 | # endif | ||
364 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
365 | tmp_length = | ||
366 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
367 | * 0.333334 /* binary -> octal */ | ||
368 | ) | ||
369 | + 1; /* turn floor into ceil */ | ||
370 | else | ||
371 | tmp_length = | ||
372 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
373 | * 0.333334 /* binary -> octal */ | ||
374 | ) | ||
375 | + 1; /* turn floor into ceil */ | ||
376 | if (tmp_length < precision) | ||
377 | tmp_length = precision; | ||
378 | /* Add 1, to account for a leading sign. */ | ||
379 | tmp_length = xsum (tmp_length, 1); | ||
380 | break; | ||
381 | |||
382 | case 'x': case 'X': | ||
383 | # ifdef HAVE_LONG_LONG_INT | ||
384 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
385 | tmp_length = | ||
386 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
387 | * 0.25 /* binary -> hexadecimal */ | ||
388 | ) | ||
389 | + 1; /* turn floor into ceil */ | ||
390 | else | ||
391 | # endif | ||
392 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
393 | tmp_length = | ||
394 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
395 | * 0.25 /* binary -> hexadecimal */ | ||
396 | ) | ||
397 | + 1; /* turn floor into ceil */ | ||
398 | else | ||
399 | tmp_length = | ||
400 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
401 | * 0.25 /* binary -> hexadecimal */ | ||
402 | ) | ||
403 | + 1; /* turn floor into ceil */ | ||
404 | if (tmp_length < precision) | ||
405 | tmp_length = precision; | ||
406 | /* Add 2, to account for a leading sign or alternate form. */ | ||
407 | tmp_length = xsum (tmp_length, 2); | ||
408 | break; | ||
409 | |||
410 | case 'f': case 'F': | ||
411 | # ifdef HAVE_LONG_DOUBLE | ||
412 | if (type == TYPE_LONGDOUBLE) | ||
413 | tmp_length = | ||
414 | (unsigned int) (LDBL_MAX_EXP | ||
415 | * 0.30103 /* binary -> decimal */ | ||
416 | * 2 /* estimate for FLAG_GROUP */ | ||
417 | ) | ||
418 | + 1 /* turn floor into ceil */ | ||
419 | + 10; /* sign, decimal point etc. */ | ||
420 | else | ||
421 | # endif | ||
422 | tmp_length = | ||
423 | (unsigned int) (DBL_MAX_EXP | ||
424 | * 0.30103 /* binary -> decimal */ | ||
425 | * 2 /* estimate for FLAG_GROUP */ | ||
426 | ) | ||
427 | + 1 /* turn floor into ceil */ | ||
428 | + 10; /* sign, decimal point etc. */ | ||
429 | tmp_length = xsum (tmp_length, precision); | ||
430 | break; | ||
431 | |||
432 | case 'e': case 'E': case 'g': case 'G': | ||
433 | case 'a': case 'A': | ||
434 | tmp_length = | ||
435 | 12; /* sign, decimal point, exponent etc. */ | ||
436 | tmp_length = xsum (tmp_length, precision); | ||
437 | break; | ||
438 | |||
439 | case 'c': | ||
440 | # if defined HAVE_WINT_T && !WIDE_CHAR_VERSION | ||
441 | if (type == TYPE_WIDE_CHAR) | ||
442 | tmp_length = MB_CUR_MAX; | ||
443 | else | ||
444 | # endif | ||
445 | tmp_length = 1; | ||
446 | break; | ||
447 | |||
448 | case 's': | ||
449 | # ifdef HAVE_WCHAR_T | ||
450 | if (type == TYPE_WIDE_STRING) | ||
451 | { | ||
452 | tmp_length = | ||
453 | local_wcslen (a.arg[dp->arg_index].a.a_wide_string); | ||
454 | |||
455 | # if !WIDE_CHAR_VERSION | ||
456 | tmp_length = xtimes (tmp_length, MB_CUR_MAX); | ||
457 | # endif | ||
458 | } | ||
459 | else | ||
460 | # endif | ||
461 | tmp_length = strlen (a.arg[dp->arg_index].a.a_string); | ||
462 | break; | ||
463 | |||
464 | case 'p': | ||
465 | tmp_length = | ||
466 | (unsigned int) (sizeof (void *) * CHAR_BIT | ||
467 | * 0.25 /* binary -> hexadecimal */ | ||
468 | ) | ||
469 | + 1 /* turn floor into ceil */ | ||
470 | + 2; /* account for leading 0x */ | ||
471 | break; | ||
472 | |||
473 | default: | ||
474 | abort (); | ||
475 | } | ||
476 | |||
477 | if (tmp_length < width) | ||
478 | tmp_length = width; | ||
479 | |||
480 | tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ | ||
481 | } | ||
482 | |||
483 | if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) | ||
484 | tmp = tmpbuf; | ||
485 | else | ||
486 | { | ||
487 | size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T)); | ||
488 | |||
489 | if (size_overflow_p (tmp_memsize)) | ||
490 | /* Overflow, would lead to out of memory. */ | ||
491 | goto out_of_memory; | ||
492 | tmp = (CHAR_T *) malloc (tmp_memsize); | ||
493 | if (tmp == NULL) | ||
494 | /* Out of memory. */ | ||
495 | goto out_of_memory; | ||
496 | } | ||
497 | #endif | ||
498 | |||
499 | /* Construct the format string for calling snprintf or | ||
500 | sprintf. */ | ||
501 | p = buf; | ||
502 | *p++ = '%'; | ||
503 | if (dp->flags & FLAG_GROUP) | ||
504 | *p++ = '\''; | ||
505 | if (dp->flags & FLAG_LEFT) | ||
506 | *p++ = '-'; | ||
507 | if (dp->flags & FLAG_SHOWSIGN) | ||
508 | *p++ = '+'; | ||
509 | if (dp->flags & FLAG_SPACE) | ||
510 | *p++ = ' '; | ||
511 | if (dp->flags & FLAG_ALT) | ||
512 | *p++ = '#'; | ||
513 | if (dp->flags & FLAG_ZERO) | ||
514 | *p++ = '0'; | ||
515 | if (dp->width_start != dp->width_end) | ||
516 | { | ||
517 | size_t n = dp->width_end - dp->width_start; | ||
518 | memcpy (p, dp->width_start, n * sizeof (CHAR_T)); | ||
519 | p += n; | ||
520 | } | ||
521 | if (dp->precision_start != dp->precision_end) | ||
522 | { | ||
523 | size_t n = dp->precision_end - dp->precision_start; | ||
524 | memcpy (p, dp->precision_start, n * sizeof (CHAR_T)); | ||
525 | p += n; | ||
526 | } | ||
527 | |||
528 | switch (type) | ||
529 | { | ||
530 | #ifdef HAVE_LONG_LONG_INT | ||
531 | case TYPE_LONGLONGINT: | ||
532 | case TYPE_ULONGLONGINT: | ||
533 | *p++ = 'l'; | ||
534 | /*FALLTHROUGH*/ | ||
535 | #endif | ||
536 | case TYPE_LONGINT: | ||
537 | case TYPE_ULONGINT: | ||
538 | #ifdef HAVE_WINT_T | ||
539 | case TYPE_WIDE_CHAR: | ||
540 | #endif | ||
541 | #ifdef HAVE_WCHAR_T | ||
542 | case TYPE_WIDE_STRING: | ||
543 | #endif | ||
544 | *p++ = 'l'; | ||
545 | break; | ||
546 | #ifdef HAVE_LONG_DOUBLE | ||
547 | case TYPE_LONGDOUBLE: | ||
548 | *p++ = 'L'; | ||
549 | break; | ||
550 | #endif | ||
551 | default: | ||
552 | break; | ||
553 | } | ||
554 | *p = dp->conversion; | ||
555 | #if USE_SNPRINTF | ||
556 | p[1] = '%'; | ||
557 | p[2] = 'n'; | ||
558 | p[3] = '\0'; | ||
559 | #else | ||
560 | p[1] = '\0'; | ||
561 | #endif | ||
562 | |||
563 | /* Construct the arguments for calling snprintf or sprintf. */ | ||
564 | prefix_count = 0; | ||
565 | if (dp->width_arg_index != ARG_NONE) | ||
566 | { | ||
567 | if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) | ||
568 | abort (); | ||
569 | prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; | ||
570 | } | ||
571 | if (dp->precision_arg_index != ARG_NONE) | ||
572 | { | ||
573 | if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) | ||
574 | abort (); | ||
575 | prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; | ||
576 | } | ||
577 | |||
578 | #if USE_SNPRINTF | ||
579 | /* Prepare checking whether snprintf returns the count | ||
580 | via %n. */ | ||
581 | ENSURE_ALLOCATION (xsum (length, 1)); | ||
582 | result[length] = '\0'; | ||
583 | #endif | ||
584 | |||
585 | for (;;) | ||
586 | { | ||
587 | size_t maxlen; | ||
588 | int count; | ||
589 | int retcount; | ||
590 | |||
591 | maxlen = allocated - length; | ||
592 | count = -1; | ||
593 | retcount = 0; | ||
594 | |||
595 | #if USE_SNPRINTF | ||
596 | # define SNPRINTF_BUF(arg) \ | ||
597 | switch (prefix_count) \ | ||
598 | { \ | ||
599 | case 0: \ | ||
600 | retcount = SNPRINTF (result + length, maxlen, buf, \ | ||
601 | arg, &count); \ | ||
602 | break; \ | ||
603 | case 1: \ | ||
604 | retcount = SNPRINTF (result + length, maxlen, buf, \ | ||
605 | prefixes[0], arg, &count); \ | ||
606 | break; \ | ||
607 | case 2: \ | ||
608 | retcount = SNPRINTF (result + length, maxlen, buf, \ | ||
609 | prefixes[0], prefixes[1], arg, \ | ||
610 | &count); \ | ||
611 | break; \ | ||
612 | default: \ | ||
613 | abort (); \ | ||
614 | } | ||
615 | #else | ||
616 | # define SNPRINTF_BUF(arg) \ | ||
617 | switch (prefix_count) \ | ||
618 | { \ | ||
619 | case 0: \ | ||
620 | count = sprintf (tmp, buf, arg); \ | ||
621 | break; \ | ||
622 | case 1: \ | ||
623 | count = sprintf (tmp, buf, prefixes[0], arg); \ | ||
624 | break; \ | ||
625 | case 2: \ | ||
626 | count = sprintf (tmp, buf, prefixes[0], prefixes[1],\ | ||
627 | arg); \ | ||
628 | break; \ | ||
629 | default: \ | ||
630 | abort (); \ | ||
631 | } | ||
632 | #endif | ||
633 | |||
634 | switch (type) | ||
635 | { | ||
636 | case TYPE_SCHAR: | ||
637 | { | ||
638 | int arg = a.arg[dp->arg_index].a.a_schar; | ||
639 | SNPRINTF_BUF (arg); | ||
640 | } | ||
641 | break; | ||
642 | case TYPE_UCHAR: | ||
643 | { | ||
644 | unsigned int arg = a.arg[dp->arg_index].a.a_uchar; | ||
645 | SNPRINTF_BUF (arg); | ||
646 | } | ||
647 | break; | ||
648 | case TYPE_SHORT: | ||
649 | { | ||
650 | int arg = a.arg[dp->arg_index].a.a_short; | ||
651 | SNPRINTF_BUF (arg); | ||
652 | } | ||
653 | break; | ||
654 | case TYPE_USHORT: | ||
655 | { | ||
656 | unsigned int arg = a.arg[dp->arg_index].a.a_ushort; | ||
657 | SNPRINTF_BUF (arg); | ||
658 | } | ||
659 | break; | ||
660 | case TYPE_INT: | ||
661 | { | ||
662 | int arg = a.arg[dp->arg_index].a.a_int; | ||
663 | SNPRINTF_BUF (arg); | ||
664 | } | ||
665 | break; | ||
666 | case TYPE_UINT: | ||
667 | { | ||
668 | unsigned int arg = a.arg[dp->arg_index].a.a_uint; | ||
669 | SNPRINTF_BUF (arg); | ||
670 | } | ||
671 | break; | ||
672 | case TYPE_LONGINT: | ||
673 | { | ||
674 | long int arg = a.arg[dp->arg_index].a.a_longint; | ||
675 | SNPRINTF_BUF (arg); | ||
676 | } | ||
677 | break; | ||
678 | case TYPE_ULONGINT: | ||
679 | { | ||
680 | unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint; | ||
681 | SNPRINTF_BUF (arg); | ||
682 | } | ||
683 | break; | ||
684 | #ifdef HAVE_LONG_LONG_INT | ||
685 | case TYPE_LONGLONGINT: | ||
686 | { | ||
687 | long long int arg = a.arg[dp->arg_index].a.a_longlongint; | ||
688 | SNPRINTF_BUF (arg); | ||
689 | } | ||
690 | break; | ||
691 | case TYPE_ULONGLONGINT: | ||
692 | { | ||
693 | unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint; | ||
694 | SNPRINTF_BUF (arg); | ||
695 | } | ||
696 | break; | ||
697 | #endif | ||
698 | case TYPE_DOUBLE: | ||
699 | { | ||
700 | double arg = a.arg[dp->arg_index].a.a_double; | ||
701 | SNPRINTF_BUF (arg); | ||
702 | } | ||
703 | break; | ||
704 | #ifdef HAVE_LONG_DOUBLE | ||
705 | case TYPE_LONGDOUBLE: | ||
706 | { | ||
707 | long double arg = a.arg[dp->arg_index].a.a_longdouble; | ||
708 | SNPRINTF_BUF (arg); | ||
709 | } | ||
710 | break; | ||
711 | #endif | ||
712 | case TYPE_CHAR: | ||
713 | { | ||
714 | int arg = a.arg[dp->arg_index].a.a_char; | ||
715 | SNPRINTF_BUF (arg); | ||
716 | } | ||
717 | break; | ||
718 | #ifdef HAVE_WINT_T | ||
719 | case TYPE_WIDE_CHAR: | ||
720 | { | ||
721 | wint_t arg = a.arg[dp->arg_index].a.a_wide_char; | ||
722 | SNPRINTF_BUF (arg); | ||
723 | } | ||
724 | break; | ||
725 | #endif | ||
726 | case TYPE_STRING: | ||
727 | { | ||
728 | const char *arg = a.arg[dp->arg_index].a.a_string; | ||
729 | SNPRINTF_BUF (arg); | ||
730 | } | ||
731 | break; | ||
732 | #ifdef HAVE_WCHAR_T | ||
733 | case TYPE_WIDE_STRING: | ||
734 | { | ||
735 | const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; | ||
736 | SNPRINTF_BUF (arg); | ||
737 | } | ||
738 | break; | ||
739 | #endif | ||
740 | case TYPE_POINTER: | ||
741 | { | ||
742 | void *arg = a.arg[dp->arg_index].a.a_pointer; | ||
743 | SNPRINTF_BUF (arg); | ||
744 | } | ||
745 | break; | ||
746 | default: | ||
747 | abort (); | ||
748 | } | ||
749 | |||
750 | #if USE_SNPRINTF | ||
751 | /* Portability: Not all implementations of snprintf() | ||
752 | are ISO C 99 compliant. Determine the number of | ||
753 | bytes that snprintf() has produced or would have | ||
754 | produced. */ | ||
755 | if (count >= 0) | ||
756 | { | ||
757 | /* Verify that snprintf() has NUL-terminated its | ||
758 | result. */ | ||
759 | if (count < maxlen && result[length + count] != '\0') | ||
760 | abort (); | ||
761 | /* Portability hack. */ | ||
762 | if (retcount > count) | ||
763 | count = retcount; | ||
764 | } | ||
765 | else | ||
766 | { | ||
767 | /* snprintf() doesn't understand the '%n' | ||
768 | directive. */ | ||
769 | if (p[1] != '\0') | ||
770 | { | ||
771 | /* Don't use the '%n' directive; instead, look | ||
772 | at the snprintf() return value. */ | ||
773 | p[1] = '\0'; | ||
774 | continue; | ||
775 | } | ||
776 | else | ||
777 | { | ||
778 | /* Look at the snprintf() return value. */ | ||
779 | if (retcount < 0) | ||
780 | { | ||
781 | /* HP-UX 10.20 snprintf() is doubly deficient: | ||
782 | It doesn't understand the '%n' directive, | ||
783 | *and* it returns -1 (rather than the length | ||
784 | that would have been required) when the | ||
785 | buffer is too small. */ | ||
786 | size_t bigger_need = | ||
787 | xsum (xtimes (allocated, 2), 12); | ||
788 | ENSURE_ALLOCATION (bigger_need); | ||
789 | continue; | ||
790 | } | ||
791 | else | ||
792 | count = retcount; | ||
793 | } | ||
794 | } | ||
795 | #endif | ||
796 | |||
797 | /* Attempt to handle failure. */ | ||
798 | if (count < 0) | ||
799 | { | ||
800 | if (!(result == resultbuf || result == NULL)) | ||
801 | free (result); | ||
802 | if (buf_malloced != NULL) | ||
803 | free (buf_malloced); | ||
804 | CLEANUP (); | ||
805 | errno = EINVAL; | ||
806 | return NULL; | ||
807 | } | ||
808 | |||
809 | #if !USE_SNPRINTF | ||
810 | if (count >= tmp_length) | ||
811 | /* tmp_length was incorrectly calculated - fix the | ||
812 | code above! */ | ||
813 | abort (); | ||
814 | #endif | ||
815 | |||
816 | /* Make room for the result. */ | ||
817 | if (count >= maxlen) | ||
818 | { | ||
819 | /* Need at least count bytes. But allocate | ||
820 | proportionally, to avoid looping eternally if | ||
821 | snprintf() reports a too small count. */ | ||
822 | size_t n = | ||
823 | xmax (xsum (length, count), xtimes (allocated, 2)); | ||
824 | |||
825 | ENSURE_ALLOCATION (n); | ||
826 | #if USE_SNPRINTF | ||
827 | continue; | ||
828 | #endif | ||
829 | } | ||
830 | |||
831 | #if USE_SNPRINTF | ||
832 | /* The snprintf() result did fit. */ | ||
833 | #else | ||
834 | /* Append the sprintf() result. */ | ||
835 | memcpy (result + length, tmp, count * sizeof (CHAR_T)); | ||
836 | if (tmp != tmpbuf) | ||
837 | free (tmp); | ||
838 | #endif | ||
839 | |||
840 | length += count; | ||
841 | break; | ||
842 | } | ||
843 | } | ||
844 | } | ||
845 | } | ||
846 | |||
847 | /* Add the final NUL. */ | ||
848 | ENSURE_ALLOCATION (xsum (length, 1)); | ||
849 | result[length] = '\0'; | ||
850 | |||
851 | if (result != resultbuf && length + 1 < allocated) | ||
852 | { | ||
853 | /* Shrink the allocated memory if possible. */ | ||
854 | CHAR_T *memory; | ||
855 | |||
856 | memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T)); | ||
857 | if (memory != NULL) | ||
858 | result = memory; | ||
859 | } | ||
860 | |||
861 | if (buf_malloced != NULL) | ||
862 | free (buf_malloced); | ||
863 | CLEANUP (); | ||
864 | *lengthp = length; | ||
865 | /* Note that we can produce a big string of a length > INT_MAX. POSIX | ||
866 | says that snprintf() fails with errno = EOVERFLOW in this case, but | ||
867 | that's only because snprintf() returns an 'int'. This function does | ||
868 | not have this limitation. */ | ||
869 | return result; | ||
870 | |||
871 | out_of_memory: | ||
872 | if (!(result == resultbuf || result == NULL)) | ||
873 | free (result); | ||
874 | if (buf_malloced != NULL) | ||
875 | free (buf_malloced); | ||
876 | out_of_memory_1: | ||
877 | CLEANUP (); | ||
878 | errno = ENOMEM; | ||
879 | return NULL; | ||
880 | } | ||
881 | } | ||
882 | |||
883 | #undef SNPRINTF | ||
884 | #undef USE_SNPRINTF | ||
885 | #undef PRINTF_PARSE | ||
886 | #undef DIRECTIVES | ||
887 | #undef DIRECTIVE | ||
888 | #undef CHAR_T | ||
889 | #undef VASNPRINTF | ||