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