1 /* vsprintf with automatic memory allocation.
2 Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
3
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.
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 GNU
12 Library General Public License for more details.
13
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. */
18
19 #ifndef _WIN32
20 /* Tell glibc's <stdio.h> to provide a prototype for snprintf().
21 This must come before <config.h> because <config.h> may include
22 <features.h>, and once <features.h> has been included, it's too late. */
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
26 #endif
27
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include "gst-printf.h"
33
34 /* Specification. */
35 #include "vasnprintf.h"
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 #include "printf-parse.h"
44 #include "printf-extension.h"
45
46 #ifdef HAVE_WCHAR_T
47 # ifdef HAVE_WCSLEN
48 # define local_wcslen wcslen
49 # else
50 /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
51 a dependency towards this library, here is a local substitute.
52 Define this substitute only once, even if this file is included
53 twice in the same compilation unit. */
54 # ifndef local_wcslen_defined
55 # define local_wcslen_defined 1
56 static size_t
local_wcslen(const wchar_t * s)57 local_wcslen (const wchar_t * s)
58 {
59 const wchar_t *ptr;
60
61 for (ptr = s; *ptr != (wchar_t) 0; ptr++);
62 return ptr - s;
63 }
64 # endif
65 # endif
66 #endif
67
68 /* For those losing systems which don't have 'alloca' we have to add
69 some additional code emulating it. */
70 #if defined (alloca) || defined (GLIB_HAVE_ALLOCA_H)
71 # define freea(p) /* nothing */
72 #else
73 # define alloca(n) malloc (n)
74 # define freea(p) free (p)
75 #endif
76
77 #ifndef HAVE_LONG_LONG_FORMAT
78 static inline int
print_long_long(char * buf,int len,int width,int precision,unsigned long flags,char conversion,unsigned long long number)79 print_long_long (char *buf,
80 int len,
81 int width,
82 int precision,
83 unsigned long flags, char conversion, unsigned long long number)
84 {
85 int negative = FALSE;
86 char buffer[128];
87 char *bufferend;
88 char *pointer;
89 int base;
90 static const char *upper = "0123456789ABCDEFX";
91 static const char *lower = "0123456789abcdefx";
92 const char *digits;
93 int i;
94 char *p;
95 int count;
96
97 #define EMIT(c) \
98 if (p - buf == len - 1) \
99 { \
100 *p++ = '\0'; \
101 return len; \
102 } \
103 else \
104 *p++ = c;
105
106 p = buf;
107
108 switch (conversion) {
109 case 'o':
110 base = 8;
111 digits = lower;
112 negative = FALSE;
113 break;
114 case 'x':
115 base = 16;
116 digits = lower;
117 negative = FALSE;
118 break;
119 case 'X':
120 base = 16;
121 digits = upper;
122 negative = FALSE;
123 break;
124 case 'u':
125 base = 10;
126 digits = lower;
127 negative = FALSE;
128 break;
129 default:
130 base = 10;
131 digits = lower;
132 negative = (long long) number < 0;
133 if (negative)
134 number = -((long long) number);
135 break;
136 }
137
138 /* Build number */
139 pointer = bufferend = &buffer[sizeof (buffer) - 1];
140 *pointer-- = '\0';
141 for (i = 1; i < (int) sizeof (buffer); i++) {
142 *pointer-- = digits[number % base];
143 number /= base;
144 if (number == 0)
145 break;
146 }
147
148 /* Adjust width */
149 width -= (bufferend - pointer) - 1;
150
151 /* Adjust precision */
152 if (precision != -1) {
153 precision -= (bufferend - pointer) - 1;
154 if (precision < 0)
155 precision = 0;
156 flags |= FLAG_ZERO;
157 }
158
159 /* Adjust width further */
160 if (negative || (flags & FLAG_SHOWSIGN) || (flags & FLAG_SPACE))
161 width--;
162 if (flags & FLAG_ALT) {
163 switch (base) {
164 case 16:
165 width -= 2;
166 break;
167 case 8:
168 width--;
169 break;
170 default:
171 break;
172 }
173 }
174
175 /* Output prefixes spaces if needed */
176 if (!((flags & FLAG_LEFT) || ((flags & FLAG_ZERO) && (precision == -1)))) {
177 count = (precision == -1) ? 0 : precision;
178 while (width-- > count)
179 *p++ = ' ';
180 }
181
182 /* width has been adjusted for signs and alternatives */
183 if (negative) {
184 EMIT ('-');
185 } else if (flags & FLAG_SHOWSIGN) {
186 EMIT ('+');
187 } else if (flags & FLAG_SPACE) {
188 EMIT (' ');
189 }
190
191 if (flags & FLAG_ALT) {
192 switch (base) {
193 case 8:
194 EMIT ('0');
195 break;
196 case 16:
197 EMIT ('0');
198 EMIT (digits[16]);
199 break;
200 default:
201 break;
202 } /* switch base */
203 }
204
205 /* Output prefixed zero padding if needed */
206 if (flags & FLAG_ZERO) {
207 if (precision == -1)
208 precision = width;
209 while (precision-- > 0) {
210 EMIT ('0');
211 width--;
212 }
213 }
214
215 /* Output the number itself */
216 while (*(++pointer)) {
217 EMIT (*pointer);
218 }
219
220 /* Output trailing spaces if needed */
221 if (flags & FLAG_LEFT) {
222 while (width-- > 0)
223 EMIT (' ');
224 }
225
226 EMIT ('\0');
227
228 return p - buf - 1;
229 }
230 #endif
231
232 static void
printf_postprocess_args(char_directives * directives,arguments * arguments)233 printf_postprocess_args (char_directives * directives, arguments * arguments)
234 {
235 int i;
236
237 for (i = 0; i < directives->count; ++i) {
238 char_directive *dp;
239 argument *a;
240
241 dp = &directives->dir[i];
242
243 /* %% has no arguments, for example */
244 if (dp->arg_index < 0)
245 continue;
246
247 a = &arguments->arg[dp->arg_index];
248
249 if (a->type == TYPE_POINTER_EXT) {
250 char fmt[4];
251
252 fmt[0] = 'p';
253 fmt[1] = POINTER_EXT_SIGNIFIER_CHAR;
254 fmt[2] = dp->ptr_ext_char;
255 fmt[3] = '\0';
256
257 a->ext_string =
258 __gst_printf_pointer_extension_serialize (fmt, a->a.a_pointer);
259 }
260 }
261 }
262
263 char *
vasnprintf(char * resultbuf,size_t * lengthp,const char * format,va_list args)264 vasnprintf (char *resultbuf, size_t * lengthp, const char *format, va_list args)
265 {
266 char_directives d;
267 arguments a;
268
269 if (printf_parse (format, &d, &a) < 0) {
270 errno = EINVAL;
271 return NULL;
272 }
273 #define CLEANUP() \
274 free (d.dir); \
275 if (a.arg) { \
276 while (a.count--) { \
277 if (a.arg[a.count].ext_string) \
278 free (a.arg[a.count].ext_string); \
279 } \
280 free (a.arg); \
281 }
282
283 if (printf_fetchargs (args, &a) < 0) {
284 CLEANUP ();
285 errno = EINVAL;
286 return NULL;
287 }
288
289 /* collect TYPE_POINTER_EXT argument strings */
290 printf_postprocess_args (&d, &a);
291
292 {
293 char *buf =
294 (char *) alloca (7 + d.max_width_length + d.max_precision_length + 6);
295 const char *cp;
296 unsigned int i;
297 char_directive *dp;
298 /* Output string accumulator. */
299 char *result;
300 size_t allocated;
301 size_t length;
302
303 if (resultbuf != NULL) {
304 result = resultbuf;
305 allocated = *lengthp;
306 } else {
307 result = NULL;
308 allocated = 0;
309 }
310 length = 0;
311 /* Invariants:
312 result is either == resultbuf or == NULL or malloc-allocated.
313 If length > 0, then result != NULL. */
314
315 #define ENSURE_ALLOCATION(needed) \
316 if ((needed) > allocated) \
317 { \
318 char *memory; \
319 \
320 allocated = (allocated > 0 ? 2 * allocated : 12); \
321 if ((needed) > allocated) \
322 allocated = (needed); \
323 if (result == resultbuf || result == NULL) \
324 memory = (char *) malloc (allocated); \
325 else \
326 memory = (char *) realloc (result, allocated); \
327 \
328 if (memory == NULL) \
329 { \
330 if (!(result == resultbuf || result == NULL)) \
331 free (result); \
332 freea (buf); \
333 CLEANUP (); \
334 errno = ENOMEM; \
335 return NULL; \
336 } \
337 if (result == resultbuf && length > 0) \
338 memcpy (memory, result, length); \
339 result = memory; \
340 }
341
342 for (cp = format, i = 0, dp = &d.dir[0];; cp = dp->dir_end, i++, dp++) {
343 if (cp != dp->dir_start) {
344 size_t n = dp->dir_start - cp;
345
346 ENSURE_ALLOCATION (length + n);
347 memcpy (result + length, cp, n);
348 length += n;
349 }
350 if (i == d.count)
351 break;
352
353 /* Execute a single directive. */
354 if (dp->conversion == '%') {
355 if (!(dp->arg_index < 0))
356 abort ();
357 ENSURE_ALLOCATION (length + 1);
358 result[length] = '%';
359 length += 1;
360 } else {
361 if (!(dp->arg_index >= 0))
362 abort ();
363
364 if (dp->conversion == 'n') {
365 switch (a.arg[dp->arg_index].type) {
366 case TYPE_COUNT_SCHAR_POINTER:
367 *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
368 break;
369 case TYPE_COUNT_SHORT_POINTER:
370 *a.arg[dp->arg_index].a.a_count_short_pointer = length;
371 break;
372 case TYPE_COUNT_INT_POINTER:
373 *a.arg[dp->arg_index].a.a_count_int_pointer = length;
374 break;
375 case TYPE_COUNT_LONGINT_POINTER:
376 *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
377 break;
378 #ifdef HAVE_LONG_LONG
379 case TYPE_COUNT_LONGLONGINT_POINTER:
380 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
381 break;
382 #endif
383 default:
384 abort ();
385 }
386 } else {
387 arg_type type = a.arg[dp->arg_index].type;
388 char *p;
389 unsigned int prefix_count;
390 int prefixes[2];
391 #ifndef HAVE_SNPRINTF
392 unsigned int tmp_length;
393 char tmpbuf[700];
394 char *tmp;
395
396 /* Allocate a temporary buffer of sufficient size for calling
397 sprintf. */
398 {
399 unsigned int width;
400 unsigned int precision;
401
402 width = 0;
403 if (dp->width_start != dp->width_end) {
404 if (dp->width_arg_index >= 0) {
405 int arg;
406
407 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
408 abort ();
409 arg = a.arg[dp->width_arg_index].a.a_int;
410 width = (arg < 0 ? -arg : arg);
411 } else {
412 const char *digitp = dp->width_start;
413
414 do
415 width = width * 10 + (*digitp++ - '0');
416 while (digitp != dp->width_end);
417 }
418 }
419
420 precision = 6;
421 if (dp->precision_start != dp->precision_end) {
422 if (dp->precision_arg_index >= 0) {
423 int arg;
424
425 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
426 abort ();
427 arg = a.arg[dp->precision_arg_index].a.a_int;
428 precision = (arg < 0 ? 0 : arg);
429 } else {
430 const char *digitp = dp->precision_start + 1;
431
432 precision = 0;
433 while (digitp != dp->precision_end)
434 precision = precision * 10 + (*digitp++ - '0');
435 }
436 }
437
438 switch (dp->conversion) {
439 case 'd':
440 case 'i':
441 case 'u':
442 # ifdef HAVE_LONG_LONG
443 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
444 tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.30103 /* binary -> decimal */
445 * 2 /* estimate for FLAG_GROUP */
446 )
447 + 1 /* turn floor into ceil */
448 + 1; /* account for leading sign */
449 else
450 # endif
451 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
452 tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.30103 /* binary -> decimal */
453 * 2 /* estimate for FLAG_GROUP */
454 )
455 + 1 /* turn floor into ceil */
456 + 1; /* account for leading sign */
457 else
458 tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.30103 /* binary -> decimal */
459 * 2 /* estimate for FLAG_GROUP */
460 )
461 + 1 /* turn floor into ceil */
462 + 1; /* account for leading sign */
463 break;
464
465 case 'o':
466 # ifdef HAVE_LONG_LONG
467 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
468 tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.333334 /* binary -> octal */
469 )
470 + 1 /* turn floor into ceil */
471 + 1; /* account for leading sign */
472 else
473 # endif
474 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
475 tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.333334 /* binary -> octal */
476 )
477 + 1 /* turn floor into ceil */
478 + 1; /* account for leading sign */
479 else
480 tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.333334 /* binary -> octal */
481 )
482 + 1 /* turn floor into ceil */
483 + 1; /* account for leading sign */
484 break;
485
486 case 'x':
487 case 'X':
488 # ifdef HAVE_LONG_LONG
489 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
490 tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
491 )
492 + 1 /* turn floor into ceil */
493 + 2; /* account for leading sign or alternate form */
494 else
495 # endif
496 # ifdef HAVE_INT64_AND_I64
497 if (type == TYPE_INT64 || type == TYPE_UINT64)
498 tmp_length = (unsigned int) (sizeof (unsigned __int64) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
499 )
500 + 1 /* turn floor into ceil */
501 + 2; /* account for leading sign or alternate form */
502 else
503 # endif
504 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
505 tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
506 )
507 + 1 /* turn floor into ceil */
508 + 2; /* account for leading sign or alternate form */
509 else
510 tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
511 )
512 + 1 /* turn floor into ceil */
513 + 2; /* account for leading sign or alternate form */
514 break;
515
516 case 'f':
517 case 'F':
518 # ifdef HAVE_LONG_DOUBLE
519 if (type == TYPE_LONGDOUBLE)
520 tmp_length = (unsigned int) (LDBL_MAX_EXP * 0.30103 /* binary -> decimal */
521 * 2 /* estimate for FLAG_GROUP */
522 )
523 + 1 /* turn floor into ceil */
524 + precision + 10; /* sign, decimal point etc. */
525 else
526 # endif
527 tmp_length = (unsigned int) (DBL_MAX_EXP * 0.30103 /* binary -> decimal */
528 * 2 /* estimate for FLAG_GROUP */
529 )
530 + 1 /* turn floor into ceil */
531 + precision + 10; /* sign, decimal point etc. */
532 break;
533
534 case 'e':
535 case 'E':
536 case 'g':
537 case 'G':
538 case 'a':
539 case 'A':
540 tmp_length = precision + 12; /* sign, decimal point, exponent etc. */
541 break;
542
543 case 'c':
544 # ifdef HAVE_WINT_T
545 if (type == TYPE_WIDE_CHAR)
546 tmp_length = MB_CUR_MAX;
547 else
548 # endif
549 tmp_length = 1;
550 break;
551
552 case 's':
553 # ifdef HAVE_WCHAR_T
554 if (type == TYPE_WIDE_STRING)
555 tmp_length = (a.arg[dp->arg_index].a.a_wide_string == NULL ? 6 /* wcslen(L"(null)") */
556 : local_wcslen (a.arg[dp->arg_index].a.a_wide_string))
557 * MB_CUR_MAX;
558 else
559 # endif
560 tmp_length = a.arg[dp->arg_index].a.a_string == NULL ? 6 /* strlen("(null)") */
561 : strlen (a.arg[dp->arg_index].a.a_string);
562 break;
563
564 case 'p':
565 tmp_length = (unsigned int) (sizeof (void *) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
566 )
567 + 1 /* turn floor into ceil */
568 + 2; /* account for leading 0x */
569
570 /* make sure we always have enough space for a plain %p, so + */
571 if (dp->flags & FLAG_PTR_EXT && a.arg[dp->arg_index].ext_string)
572 tmp_length += strlen (a.arg[dp->arg_index].ext_string);
573 break;
574
575 default:
576 abort ();
577 }
578
579 if (tmp_length < width)
580 tmp_length = width;
581
582 tmp_length++; /* account for trailing NUL */
583 }
584
585 if (tmp_length <= sizeof (tmpbuf))
586 tmp = tmpbuf;
587 else {
588 tmp = (char *) malloc (tmp_length);
589 if (tmp == NULL) {
590 /* Out of memory. */
591 if (!(result == resultbuf || result == NULL))
592 free (result);
593 freea (buf);
594 CLEANUP ();
595 errno = ENOMEM;
596 return NULL;
597 }
598 }
599 #endif
600
601 /* Construct the format string for calling snprintf or
602 sprintf. */
603 p = buf;
604 *p++ = '%';
605 if (dp->flags & FLAG_GROUP)
606 *p++ = '\'';
607 if (dp->flags & FLAG_LEFT)
608 *p++ = '-';
609 if (dp->flags & FLAG_SHOWSIGN)
610 *p++ = '+';
611 if (dp->flags & FLAG_SPACE)
612 *p++ = ' ';
613 if (dp->flags & FLAG_ALT)
614 *p++ = '#';
615 if (dp->flags & FLAG_ZERO)
616 *p++ = '0';
617 if (dp->width_start != dp->width_end) {
618 size_t n = dp->width_end - dp->width_start;
619 memcpy (p, dp->width_start, n);
620 p += n;
621 }
622 if (dp->precision_start != dp->precision_end) {
623 size_t n = dp->precision_end - dp->precision_start;
624 memcpy (p, dp->precision_start, n);
625 p += n;
626 }
627
628 switch (type) {
629 #ifdef HAVE_INT64_AND_I64
630 case TYPE_INT64:
631 case TYPE_UINT64:
632 *p++ = 'I';
633 *p++ = '6';
634 *p++ = '4';
635 break;
636 #endif
637 #ifdef HAVE_LONG_LONG
638 case TYPE_LONGLONGINT:
639 case TYPE_ULONGLONGINT:
640 #ifdef HAVE_INT64_AND_I64 /* The system (sn)printf uses %I64. Also assume
641 * that long long == __int64.
642 */
643 *p++ = 'I';
644 *p++ = '6';
645 *p++ = '4';
646 break;
647 #else
648 *p++ = 'l';
649 /*FALLTHROUGH*/
650 #endif
651 #endif
652 case TYPE_LONGINT:
653 case TYPE_ULONGINT:
654 #ifdef HAVE_WINT_T
655 case TYPE_WIDE_CHAR:
656 #endif
657 #ifdef HAVE_WCHAR_T
658 case TYPE_WIDE_STRING:
659 #endif
660 *p++ = 'l';
661 break;
662 #ifdef HAVE_LONG_DOUBLE
663 case TYPE_LONGDOUBLE:
664 *p++ = 'L';
665 break;
666 #endif
667 default:
668 break;
669 }
670 *p = dp->conversion;
671 #ifdef HAVE_SNPRINTF
672 p[1] = '%';
673 p[2] = 'n';
674 p[3] = '\0';
675 #else
676 p[1] = '\0';
677 #endif
678
679 /* Construct the arguments for calling snprintf or sprintf. */
680 prefix_count = 0;
681 if (dp->width_arg_index >= 0) {
682 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
683 abort ();
684 prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
685 }
686 if (dp->precision_arg_index >= 0) {
687 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
688 abort ();
689 prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
690 }
691 #ifdef HAVE_SNPRINTF
692 /* Prepare checking whether snprintf returns the count
693 via %n. */
694 ENSURE_ALLOCATION (length + 1);
695 result[length] = '\0';
696 #endif
697
698 for (;;) {
699 size_t maxlen;
700 int count;
701 #ifdef HAVE_SNPRINTF
702 int retcount;
703 #endif
704
705 maxlen = allocated - length;
706 count = -1;
707
708 #ifdef HAVE_SNPRINTF
709 retcount = 0;
710
711 #define SNPRINTF_BUF(arg) \
712 switch (prefix_count) \
713 { \
714 case 0: \
715 retcount = snprintf (result + length, maxlen, buf, \
716 arg, &count); \
717 break; \
718 case 1: \
719 retcount = snprintf (result + length, maxlen, buf, \
720 prefixes[0], arg, &count); \
721 break; \
722 case 2: \
723 retcount = snprintf (result + length, maxlen, buf, \
724 prefixes[0], prefixes[1], arg, \
725 &count); \
726 break; \
727 default: \
728 abort (); \
729 }
730 #else
731 #define SNPRINTF_BUF(arg) \
732 switch (prefix_count) \
733 { \
734 case 0: \
735 count = sprintf (tmp, buf, arg); \
736 break; \
737 case 1: \
738 count = sprintf (tmp, buf, prefixes[0], arg); \
739 break; \
740 case 2: \
741 count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
742 arg); \
743 break; \
744 default: \
745 abort (); \
746 }
747 #endif
748
749 switch (type) {
750 case TYPE_SCHAR:
751 {
752 int arg = a.arg[dp->arg_index].a.a_schar;
753 SNPRINTF_BUF (arg);
754 }
755 break;
756 case TYPE_UCHAR:
757 {
758 unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
759 SNPRINTF_BUF (arg);
760 }
761 break;
762 case TYPE_SHORT:
763 {
764 int arg = a.arg[dp->arg_index].a.a_short;
765 SNPRINTF_BUF (arg);
766 }
767 break;
768 case TYPE_USHORT:
769 {
770 unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
771 SNPRINTF_BUF (arg);
772 }
773 break;
774 case TYPE_INT:
775 {
776 int arg = a.arg[dp->arg_index].a.a_int;
777 SNPRINTF_BUF (arg);
778 }
779 break;
780 case TYPE_UINT:
781 {
782 unsigned int arg = a.arg[dp->arg_index].a.a_uint;
783 SNPRINTF_BUF (arg);
784 }
785 break;
786 case TYPE_LONGINT:
787 {
788 long int arg = a.arg[dp->arg_index].a.a_longint;
789 SNPRINTF_BUF (arg);
790 }
791 break;
792 case TYPE_ULONGINT:
793 {
794 unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
795 SNPRINTF_BUF (arg);
796 }
797 break;
798 #ifdef HAVE_INT64_AND_I64
799 case TYPE_INT64:
800 {
801 __int64 arg = a.arg[dp->arg_index].a.a_int64;
802 SNPRINTF_BUF (arg);
803 }
804 break;
805 case TYPE_UINT64:
806 {
807 unsigned __int64 arg = a.arg[dp->arg_index].a.a_uint64;
808 SNPRINTF_BUF (arg);
809 }
810 break;
811 #endif
812 #ifdef HAVE_LONG_LONG
813 #ifndef HAVE_LONG_LONG_FORMAT
814 case TYPE_LONGLONGINT:
815 case TYPE_ULONGLONGINT:
816 {
817 unsigned long long int arg =
818 a.arg[dp->arg_index].a.a_ulonglongint;
819 int width;
820 int precision;
821
822 width = 0;
823 if (dp->width_start != dp->width_end) {
824 if (dp->width_arg_index >= 0) {
825 int arg;
826
827 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
828 abort ();
829 arg = a.arg[dp->width_arg_index].a.a_int;
830 width = (arg < 0 ? -arg : arg);
831 } else {
832 const char *digitp = dp->width_start;
833
834 do
835 width = width * 10 + (*digitp++ - '0');
836 while (digitp != dp->width_end);
837 }
838 }
839
840 precision = -1;
841 if (dp->precision_start != dp->precision_end) {
842 if (dp->precision_arg_index >= 0) {
843 int arg;
844
845 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
846 abort ();
847 arg = a.arg[dp->precision_arg_index].a.a_int;
848 precision = (arg < 0 ? 0 : arg);
849 } else {
850 const char *digitp = dp->precision_start + 1;
851
852 precision = 0;
853 do
854 precision = precision * 10 + (*digitp++ - '0');
855 while (digitp != dp->precision_end);
856 }
857 }
858 #ifdef HAVE_SNPRINTF
859 count = print_long_long (result + length, maxlen,
860 width, precision, dp->flags, dp->conversion, arg);
861 #else
862 count = print_long_long (tmp, tmp_length,
863 width, precision, dp->flags, dp->conversion, arg);
864 #endif
865 }
866 break;
867 #else
868 case TYPE_LONGLONGINT:
869 {
870 long long int arg = a.arg[dp->arg_index].a.a_longlongint;
871 SNPRINTF_BUF (arg);
872 }
873 break;
874 case TYPE_ULONGLONGINT:
875 {
876 unsigned long long int arg =
877 a.arg[dp->arg_index].a.a_ulonglongint;
878 SNPRINTF_BUF (arg);
879 }
880 break;
881 #endif
882 #endif
883 case TYPE_DOUBLE:
884 {
885 double arg = a.arg[dp->arg_index].a.a_double;
886 SNPRINTF_BUF (arg);
887 }
888 break;
889 #ifdef HAVE_LONG_DOUBLE
890 case TYPE_LONGDOUBLE:
891 {
892 long double arg = a.arg[dp->arg_index].a.a_longdouble;
893 SNPRINTF_BUF (arg);
894 }
895 break;
896 #endif
897 case TYPE_CHAR:
898 {
899 int arg = a.arg[dp->arg_index].a.a_char;
900 SNPRINTF_BUF (arg);
901 }
902 break;
903 #ifdef HAVE_WINT_T
904 case TYPE_WIDE_CHAR:
905 {
906 wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
907 SNPRINTF_BUF (arg);
908 }
909 break;
910 #endif
911 case TYPE_STRING:
912 {
913 const char *arg = a.arg[dp->arg_index].a.a_string == NULL
914 ? "(null)" : a.arg[dp->arg_index].a.a_string;
915 SNPRINTF_BUF (arg);
916 }
917 break;
918 #ifdef HAVE_WCHAR_T
919 case TYPE_WIDE_STRING:
920 {
921 const wchar_t *arg =
922 a.arg[dp->arg_index].a.a_wide_string ==
923 NULL ? L"(null)" : a.arg[dp->arg_index].a.a_wide_string;
924 SNPRINTF_BUF (arg);
925 }
926 break;
927 #endif
928 case TYPE_POINTER:
929 {
930 void *arg = a.arg[dp->arg_index].a.a_pointer;
931 SNPRINTF_BUF (arg);
932 }
933 break;
934 case TYPE_POINTER_EXT:
935 {
936 void *arg = a.arg[dp->arg_index].a.a_pointer;
937
938 if (a.arg[dp->arg_index].ext_string != NULL) {
939 arg = a.arg[dp->arg_index].ext_string;
940 *p = 's';
941 }
942
943 SNPRINTF_BUF (arg);
944 }
945 break;
946 default:
947 abort ();
948 }
949
950 #ifdef HAVE_SNPRINTF
951 /* Portability: Not all implementations of snprintf()
952 are ISO C 99 compliant. Determine the number of
953 bytes that snprintf() has produced or would have
954 produced. */
955 if (count >= 0) {
956 /* Verify that snprintf() has NUL-terminated its
957 result. */
958 if (count < maxlen && result[length + count] != '\0')
959 abort ();
960 /* Portability hack. */
961 if (retcount > count)
962 count = retcount;
963 } else {
964 /* snprintf() doesn't understand the '%n'
965 directive. */
966 if (p[1] != '\0') {
967 /* Don't use the '%n' directive; instead, look
968 at the snprintf() return value. */
969 p[1] = '\0';
970 continue;
971 }
972 count = retcount;
973 }
974 #endif
975
976 /* Attempt to handle failure. */
977 if (count < 0) {
978 if (!(result == resultbuf || result == NULL))
979 free (result);
980 freea (buf);
981 CLEANUP ();
982 errno = EINVAL;
983 return NULL;
984 }
985 #ifndef HAVE_SNPRINTF
986 if (count >= tmp_length)
987 /* tmp_length was incorrectly calculated - fix the
988 code above! */
989 abort ();
990 #endif
991
992 /* Make room for the result. */
993 if (count >= maxlen) {
994 /* Need at least count bytes. But allocate
995 proportionally, to avoid looping eternally if
996 snprintf() reports a too small count. */
997 size_t n = length + count;
998
999 if (n < 2 * allocated)
1000 n = 2 * allocated;
1001
1002 ENSURE_ALLOCATION (n);
1003 #ifdef HAVE_SNPRINTF
1004 continue;
1005 #endif
1006 }
1007 #ifdef HAVE_SNPRINTF
1008 /* The snprintf() result did fit. */
1009 #else
1010 /* Append the sprintf() result. */
1011 memcpy (result + length, tmp, count);
1012 if (tmp != tmpbuf)
1013 free (tmp);
1014 #endif
1015
1016 length += count;
1017 break;
1018 }
1019 }
1020 }
1021 }
1022
1023 /* Add the final NUL. */
1024 ENSURE_ALLOCATION (length + 1);
1025 result[length] = '\0';
1026
1027 if (result != resultbuf && length + 1 < allocated) {
1028 /* Shrink the allocated memory if possible. */
1029 char *memory;
1030
1031 memory = (char *) realloc (result, length + 1);
1032 if (memory != NULL)
1033 result = memory;
1034 }
1035
1036 freea (buf);
1037 CLEANUP ();
1038 *lengthp = length;
1039 return result;
1040 }
1041 }
1042