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