1 |
/* vsprintf with automatic memory allocation. |
2 |
Copyright (C) 1999, 2002-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 |
#ifdef HAVE_CONFIG_H |
26 |
# include <config.h> |
27 |
#endif |
28 |
#ifndef IN_LIBINTL |
29 |
# include <alloca.h> |
30 |
#endif |
31 |
|
32 |
/* Specification. */ |
33 |
#if WIDE_CHAR_VERSION |
34 |
# include "vasnwprintf.h" |
35 |
#else |
36 |
# include "vasnprintf.h" |
37 |
#endif |
38 |
|
39 |
#include <stdio.h> /* snprintf(), sprintf() */ |
40 |
#include <stdlib.h> /* abort(), malloc(), realloc(), free() */ |
41 |
#include <string.h> /* memcpy(), strlen() */ |
42 |
#include <errno.h> /* errno */ |
43 |
#include <limits.h> /* CHAR_BIT */ |
44 |
#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ |
45 |
#if WIDE_CHAR_VERSION |
46 |
# include "wprintf-parse.h" |
47 |
#else |
48 |
# include "printf-parse.h" |
49 |
#endif |
50 |
|
51 |
/* Checked size_t computations. */ |
52 |
#include "xsize.h" |
53 |
|
54 |
#ifdef HAVE_WCHAR_T |
55 |
# ifdef HAVE_WCSLEN |
56 |
# define local_wcslen wcslen |
57 |
# else |
58 |
/* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid |
59 |
a dependency towards this library, here is a local substitute. |
60 |
Define this substitute only once, even if this file is included |
61 |
twice in the same compilation unit. */ |
62 |
# ifndef local_wcslen_defined |
63 |
# define local_wcslen_defined 1 |
64 |
static size_t |
65 |
local_wcslen (const wchar_t *s) |
66 |
{ |
67 |
const wchar_t *ptr; |
68 |
|
69 |
for (ptr = s; *ptr != (wchar_t) 0; ptr++) |
70 |
; |
71 |
return ptr - s; |
72 |
} |
73 |
# endif |
74 |
# endif |
75 |
#endif |
76 |
|
77 |
#if WIDE_CHAR_VERSION |
78 |
# define VASNPRINTF vasnwprintf |
79 |
# define CHAR_T wchar_t |
80 |
# define DIRECTIVE wchar_t_directive |
81 |
# define DIRECTIVES wchar_t_directives |
82 |
# define PRINTF_PARSE wprintf_parse |
83 |
# define USE_SNPRINTF 1 |
84 |
# if HAVE_DECL__SNWPRINTF |
85 |
/* On Windows, the function swprintf() has a different signature than |
86 |
on Unix; we use the _snwprintf() function instead. */ |
87 |
# define SNPRINTF _snwprintf |
88 |
# else |
89 |
/* Unix. */ |
90 |
# define SNPRINTF swprintf |
91 |
# endif |
92 |
#else |
93 |
# define VASNPRINTF vasnprintf |
94 |
# define CHAR_T char |
95 |
# define DIRECTIVE char_directive |
96 |
# define DIRECTIVES char_directives |
97 |
# define PRINTF_PARSE printf_parse |
98 |
# define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) |
99 |
# if HAVE_DECL__SNPRINTF |
100 |
/* Windows. */ |
101 |
# define SNPRINTF _snprintf |
102 |
# else |
103 |
/* Unix. */ |
104 |
# define SNPRINTF snprintf |
105 |
# endif |
106 |
#endif |
107 |
|
108 |
CHAR_T * |
109 |
VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) |
110 |
{ |
111 |
DIRECTIVES d; |
112 |
arguments a; |
113 |
|
114 |
if (PRINTF_PARSE (format, &d, &a) < 0) |
115 |
{ |
116 |
errno = EINVAL; |
117 |
return NULL; |
118 |
} |
119 |
|
120 |
#define CLEANUP() \ |
121 |
free (d.dir); \ |
122 |
if (a.arg) \ |
123 |
free (a.arg); |
124 |
|
125 |
if (printf_fetchargs (args, &a) < 0) |
126 |
{ |
127 |
CLEANUP (); |
128 |
errno = EINVAL; |
129 |
return NULL; |
130 |
} |
131 |
|
132 |
{ |
133 |
size_t buf_neededlength; |
134 |
CHAR_T *buf; |
135 |
CHAR_T *buf_malloced; |
136 |
const CHAR_T *cp; |
137 |
size_t i; |
138 |
DIRECTIVE *dp; |
139 |
/* Output string accumulator. */ |
140 |
CHAR_T *result; |
141 |
size_t allocated; |
142 |
size_t length; |
143 |
|
144 |
/* Allocate a small buffer that will hold a directive passed to |
145 |
sprintf or snprintf. */ |
146 |
buf_neededlength = |
147 |
xsum4 (7, d.max_width_length, d.max_precision_length, 6); |
148 |
#if HAVE_ALLOCA |
149 |
if (buf_neededlength < 4000 / sizeof (CHAR_T)) |
150 |
{ |
151 |
buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T)); |
152 |
buf_malloced = NULL; |
153 |
} |
154 |
else |
155 |
#endif |
156 |
{ |
157 |
size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T)); |
158 |
if (size_overflow_p (buf_memsize)) |
159 |
goto out_of_memory_1; |
160 |
buf = (CHAR_T *) malloc (buf_memsize); |
161 |
if (buf == NULL) |
162 |
goto out_of_memory_1; |
163 |
buf_malloced = buf; |
164 |
} |
165 |
|
166 |
if (resultbuf != NULL) |
167 |
{ |
168 |
result = resultbuf; |
169 |
allocated = *lengthp; |
170 |
} |
171 |
else |
172 |
{ |
173 |
result = NULL; |
174 |
allocated = 0; |
175 |
} |
176 |
length = 0; |
177 |
/* Invariants: |
178 |
result is either == resultbuf or == NULL or malloc-allocated. |
179 |
If length > 0, then result != NULL. */ |
180 |
|
181 |
/* Ensures that allocated >= needed. Aborts through a jump to |
182 |
out_of_memory if needed is SIZE_MAX or otherwise too big. */ |
183 |
#define ENSURE_ALLOCATION(needed) \ |
184 |
if ((needed) > allocated) \ |
185 |
{ \ |
186 |
size_t memory_size; \ |
187 |
CHAR_T *memory; \ |
188 |
\ |
189 |
allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \ |
190 |
if ((needed) > allocated) \ |
191 |
allocated = (needed); \ |
192 |
memory_size = xtimes (allocated, sizeof (CHAR_T)); \ |
193 |
if (size_overflow_p (memory_size)) \ |
194 |
goto out_of_memory; \ |
195 |
if (result == resultbuf || result == NULL) \ |
196 |
memory = (CHAR_T *) malloc (memory_size); \ |
197 |
else \ |
198 |
memory = (CHAR_T *) realloc (result, memory_size); \ |
199 |
if (memory == NULL) \ |
200 |
goto out_of_memory; \ |
201 |
if (result == resultbuf && length > 0) \ |
202 |
memcpy (memory, result, length * sizeof (CHAR_T)); \ |
203 |
result = memory; \ |
204 |
} |
205 |
|
206 |
for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) |
207 |
{ |
208 |
if (cp != dp->dir_start) |
209 |
{ |
210 |
size_t n = dp->dir_start - cp; |
211 |
size_t augmented_length = xsum (length, n); |
212 |
|
213 |
ENSURE_ALLOCATION (augmented_length); |
214 |
memcpy (result + length, cp, n * sizeof (CHAR_T)); |
215 |
length = augmented_length; |
216 |
} |
217 |
if (i == d.count) |
218 |
break; |
219 |
|
220 |
/* Execute a single directive. */ |
221 |
if (dp->conversion == '%') |
222 |
{ |
223 |
size_t augmented_length; |
224 |
|
225 |
if (!(dp->arg_index == ARG_NONE)) |
226 |
abort (); |
227 |
augmented_length = xsum (length, 1); |
228 |
ENSURE_ALLOCATION (augmented_length); |
229 |
result[length] = '%'; |
230 |
length = augmented_length; |
231 |
} |
232 |
else |
233 |
{ |
234 |
if (!(dp->arg_index != ARG_NONE)) |
235 |
abort (); |
236 |
|
237 |
if (dp->conversion == 'n') |
238 |
{ |
239 |
switch (a.arg[dp->arg_index].type) |
240 |
{ |
241 |
case TYPE_COUNT_SCHAR_POINTER: |
242 |
*a.arg[dp->arg_index].a.a_count_schar_pointer = length; |
243 |
break; |
244 |
case TYPE_COUNT_SHORT_POINTER: |
245 |
*a.arg[dp->arg_index].a.a_count_short_pointer = length; |
246 |
break; |
247 |
case TYPE_COUNT_INT_POINTER: |
248 |
*a.arg[dp->arg_index].a.a_count_int_pointer = length; |
249 |
break; |
250 |
case TYPE_COUNT_LONGINT_POINTER: |
251 |
*a.arg[dp->arg_index].a.a_count_longint_pointer = length; |
252 |
break; |
253 |
#ifdef HAVE_LONG_LONG |
254 |
case TYPE_COUNT_LONGLONGINT_POINTER: |
255 |
*a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; |
256 |
break; |
257 |
#endif |
258 |
default: |
259 |
abort (); |
260 |
} |
261 |
} |
262 |
else |
263 |
{ |
264 |
arg_type type = a.arg[dp->arg_index].type; |
265 |
CHAR_T *p; |
266 |
unsigned int prefix_count; |
267 |
int prefixes[2]; |
268 |
#if !USE_SNPRINTF |
269 |
size_t tmp_length; |
270 |
CHAR_T tmpbuf[700]; |
271 |
CHAR_T *tmp; |
272 |
|
273 |
/* Allocate a temporary buffer of sufficient size for calling |
274 |
sprintf. */ |
275 |
{ |
276 |
size_t width; |
277 |
size_t precision; |
278 |
|
279 |
width = 0; |
280 |
if (dp->width_start != dp->width_end) |
281 |
{ |
282 |
if (dp->width_arg_index != ARG_NONE) |
283 |
{ |
284 |
int arg; |
285 |
|
286 |
if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) |
287 |
abort (); |
288 |
arg = a.arg[dp->width_arg_index].a.a_int; |
289 |
width = (arg < 0 ? (unsigned int) (-arg) : arg); |
290 |
} |
291 |
else |
292 |
{ |
293 |
const CHAR_T *digitp = dp->width_start; |
294 |
|
295 |
do |
296 |
width = xsum (xtimes (width, 10), *digitp++ - '0'); |
297 |
while (digitp != dp->width_end); |
298 |
} |
299 |
} |
300 |
|
301 |
precision = 6; |
302 |
if (dp->precision_start != dp->precision_end) |
303 |
{ |
304 |
if (dp->precision_arg_index != ARG_NONE) |
305 |
{ |
306 |
int arg; |
307 |
|
308 |
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) |
309 |
abort (); |
310 |
arg = a.arg[dp->precision_arg_index].a.a_int; |
311 |
precision = (arg < 0 ? 0 : arg); |
312 |
} |
313 |
else |
314 |
{ |
315 |
const CHAR_T *digitp = dp->precision_start + 1; |
316 |
|
317 |
precision = 0; |
318 |
while (digitp != dp->precision_end) |
319 |
precision = xsum (xtimes (precision, 10), *digitp++ - '0'); |
320 |
} |
321 |
} |
322 |
|
323 |
switch (dp->conversion) |
324 |
{ |
325 |
|
326 |
case 'd': case 'i': case 'u': |
327 |
# ifdef HAVE_LONG_LONG |
328 |
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) |
329 |
tmp_length = |
330 |
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT |
331 |
* 0.30103 /* binary -> decimal */ |
332 |
* 2 /* estimate for FLAG_GROUP */ |
333 |
) |
334 |
+ 1 /* turn floor into ceil */ |
335 |
+ 1; /* account for leading sign */ |
336 |
else |
337 |
# endif |
338 |
if (type == TYPE_LONGINT || type == TYPE_ULONGINT) |
339 |
tmp_length = |
340 |
(unsigned int) (sizeof (unsigned long) * CHAR_BIT |
341 |
* 0.30103 /* binary -> decimal */ |
342 |
* 2 /* estimate for FLAG_GROUP */ |
343 |
) |
344 |
+ 1 /* turn floor into ceil */ |
345 |
+ 1; /* account for leading sign */ |
346 |
else |
347 |
tmp_length = |
348 |
(unsigned int) (sizeof (unsigned int) * CHAR_BIT |
349 |
* 0.30103 /* binary -> decimal */ |
350 |
* 2 /* estimate for FLAG_GROUP */ |
351 |
) |
352 |
+ 1 /* turn floor into ceil */ |
353 |
+ 1; /* account for leading sign */ |
354 |
break; |
355 |
|
356 |
case 'o': |
357 |
# ifdef HAVE_LONG_LONG |
358 |
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) |
359 |
tmp_length = |
360 |
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT |
361 |
* 0.333334 /* binary -> octal */ |
362 |
) |
363 |
+ 1 /* turn floor into ceil */ |
364 |
+ 1; /* account for leading sign */ |
365 |
else |
366 |
# endif |
367 |
if (type == TYPE_LONGINT || type == TYPE_ULONGINT) |
368 |
tmp_length = |
369 |
(unsigned int) (sizeof (unsigned long) * CHAR_BIT |
370 |
* 0.333334 /* binary -> octal */ |
371 |
) |
372 |
+ 1 /* turn floor into ceil */ |
373 |
+ 1; /* account for leading sign */ |
374 |
else |
375 |
tmp_length = |
376 |
(unsigned int) (sizeof (unsigned int) * CHAR_BIT |
377 |
* 0.333334 /* binary -> octal */ |
378 |
) |
379 |
+ 1 /* turn floor into ceil */ |
380 |
+ 1; /* account for leading sign */ |
381 |
break; |
382 |
|
383 |
case 'x': case 'X': |
384 |
# ifdef HAVE_LONG_LONG |
385 |
if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) |
386 |
tmp_length = |
387 |
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT |
388 |
* 0.25 /* binary -> hexadecimal */ |
389 |
) |
390 |
+ 1 /* turn floor into ceil */ |
391 |
+ 2; /* account for leading sign or alternate form */ |
392 |
else |
393 |
# endif |
394 |
if (type == TYPE_LONGINT || type == TYPE_ULONGINT) |
395 |
tmp_length = |
396 |
(unsigned int) (sizeof (unsigned long) * CHAR_BIT |
397 |
* 0.25 /* binary -> hexadecimal */ |
398 |
) |
399 |
+ 1 /* turn floor into ceil */ |
400 |
+ 2; /* account for leading sign or alternate form */ |
401 |
else |
402 |
tmp_length = |
403 |
(unsigned int) (sizeof (unsigned int) * CHAR_BIT |
404 |
* 0.25 /* binary -> hexadecimal */ |
405 |
) |
406 |
+ 1 /* turn floor into ceil */ |
407 |
+ 2; /* account for leading sign or alternate form */ |
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 |
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 |
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 |
return result; |
866 |
|
867 |
out_of_memory: |
868 |
if (!(result == resultbuf || result == NULL)) |
869 |
free (result); |
870 |
if (buf_malloced != NULL) |
871 |
free (buf_malloced); |
872 |
out_of_memory_1: |
873 |
CLEANUP (); |
874 |
errno = ENOMEM; |
875 |
return NULL; |
876 |
} |
877 |
} |
878 |
|
879 |
#undef SNPRINTF |
880 |
#undef USE_SNPRINTF |
881 |
#undef PRINTF_PARSE |
882 |
#undef DIRECTIVES |
883 |
#undef DIRECTIVE |
884 |
#undef CHAR_T |
885 |
#undef VASNPRINTF |