| 1 |
/* vasnprintf with automatic memory allocation. |
|---|
| 2 |
Copyright (C) 1999, 2002-2005 Free Software Foundation, Inc. |
|---|
| 3 |
|
|---|
| 4 |
This program is free software; you can redistribute it and/or modify it |
|---|
| 5 |
under the terms of the GNU Library General Public License as published |
|---|
| 6 |
by the Free Software Foundation; either version 2, or (at your option) |
|---|
| 7 |
any later version. |
|---|
| 8 |
|
|---|
| 9 |
This program is distributed in the hope that it will be useful, |
|---|
| 10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 12 |
Library General Public License for more details. |
|---|
| 13 |
|
|---|
| 14 |
You should have received a copy of the GNU Library General Public |
|---|
| 15 |
License along with this program; if not, write to the Free Software |
|---|
| 16 |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
|---|
| 17 |
USA. */ |
|---|
| 18 |
|
|---|
| 19 |
/* Tell glibc's <stdio.h> to provide a prototype for snprintf(). |
|---|
| 20 |
This must come before <config.h> because <config.h> may include |
|---|
| 21 |
<features.h>, and once <features.h> has been included, it's too late. */ |
|---|
| 22 |
#ifndef _GNU_SOURCE |
|---|
| 23 |
# define _GNU_SOURCE 1 |
|---|
| 24 |
#endif |
|---|
| 25 |
|
|---|
| 26 |
#ifdef HAVE_CONFIG_H |
|---|
| 27 |
# include <config.h> |
|---|
| 28 |
#endif |
|---|
| 29 |
#ifndef IN_LIBINTL |
|---|
| 30 |
# include <alloca.h> |
|---|
| 31 |
#endif |
|---|
| 32 |
|
|---|
| 33 |
/* Specification. */ |
|---|
| 34 |
#if WIDE_CHAR_VERSION |
|---|
| 35 |
# include "vasnwprintf.h" |
|---|
| 36 |
#else |
|---|
| 37 |
# include "vasnprintf.h" |
|---|
| 38 |
#endif |
|---|
| 39 |
|
|---|
| 40 |
#include <stdio.h> /* snprintf() */ |
|---|
| 41 |
#include <stdlib.h> /* abort(), malloc(), realloc(), free() */ |
|---|
| 42 |
#include <string.h> /* memcpy(), strlen() */ |
|---|
| 43 |
#include <errno.h> /* errno */ |
|---|
| 44 |
#include <limits.h> /* CHAR_BIT, INT_MAX */ |
|---|
| 45 |
#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ |
|---|
| 46 |
#if WIDE_CHAR_VERSION |
|---|
| 47 |
# include "wprintf-parse.h" |
|---|
| 48 |
#else |
|---|
| 49 |
# include "printf-parse.h" |
|---|
| 50 |
#endif |
|---|
| 51 |
|
|---|
| 52 |
/* Checked size_t computations. */ |
|---|
| 53 |
#include "xsize.h" |
|---|
| 54 |
|
|---|
| 55 |
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ |
|---|
| 56 |
#ifndef EOVERFLOW |
|---|
| 57 |
# define EOVERFLOW E2BIG |
|---|
| 58 |
#endif |
|---|
| 59 |
|
|---|
| 60 |
#ifdef HAVE_WCHAR_T |
|---|
| 61 |
# ifdef HAVE_WCSLEN |
|---|
| 62 |
# define local_wcslen wcslen |
|---|
| 63 |
# else |
|---|
| 64 |
/* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid |
|---|
| 65 |
a dependency towards this library, here is a local substitute. |
|---|
| 66 |
Define this substitute only once, even if this file is included |
|---|
| 67 |
twice in the same compilation unit. */ |
|---|
| 68 |
# ifndef local_wcslen_defined |
|---|
| 69 |
# define local_wcslen_defined 1 |
|---|
| 70 |
static size_t |
|---|
| 71 |
local_wcslen (const wchar_t *s) |
|---|
| 72 |
{ |
|---|
| 73 |
const wchar_t *ptr; |
|---|
| 74 |
|
|---|
| 75 |
for (ptr = s; *ptr != (wchar_t) 0; ptr++) |
|---|
| 76 |
; |
|---|
| 77 |
return ptr - s; |
|---|
| 78 |
} |
|---|
| 79 |
# endif |
|---|
| 80 |
# endif |
|---|
| 81 |
#endif |
|---|
| 82 |
|
|---|
| 83 |
#if WIDE_CHAR_VERSION |
|---|
| 84 |
# define VASNPRINTF vasnwprintf |
|---|
| 85 |
# define CHAR_T wchar_t |
|---|
| 86 |
# define DIRECTIVE wchar_t_directive |
|---|
| 87 |
# define DIRECTIVES wchar_t_directives |
|---|
| 88 |
# define PRINTF_PARSE wprintf_parse |
|---|
| 89 |
# define USE_SNPRINTF 1 |
|---|
| 90 |
# if HAVE_DECL__SNWPRINTF |
|---|
| 91 |
/* On Windows, the function swprintf() has a different signature than |
|---|
| 92 |
on Unix; we use the _snwprintf() function instead. */ |
|---|
| 93 |
# define SNPRINTF _snwprintf |
|---|
| 94 |
# else |
|---|
| 95 |
/* Unix. */ |
|---|
| 96 |
# define SNPRINTF swprintf |
|---|
| 97 |
# endif |
|---|
| 98 |
#else |
|---|
| 99 |
# define VASNPRINTF vasnprintf |
|---|
| 100 |
# define CHAR_T char |
|---|
| 101 |
# define DIRECTIVE char_directive |
|---|
| 102 |
# define DIRECTIVES char_directives |
|---|
| 103 |
# define PRINTF_PARSE printf_parse |
|---|
| 104 |
# define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) |
|---|
| 105 |
# if HAVE_DECL__SNPRINTF |
|---|
| 106 |
/* Windows. */ |
|---|
| 107 |
# define SNPRINTF _snprintf |
|---|
| 108 |
# else |
|---|
| 109 |
/* Unix. */ |
|---|
| 110 |
# define SNPRINTF snprintf |
|---|
| 111 |
# endif |
|---|
| 112 |
#endif |
|---|
| 113 |
|
|---|
| 114 |
CHAR_T * |
|---|
| 115 |
VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) |
|---|
| 116 |
{ |
|---|
| 117 |
DIRECTIVES d; |
|---|
| 118 |
arguments a; |
|---|
| 119 |
|
|---|
| 120 |
if (PRINTF_PARSE (format, &d, &a) < 0) |
|---|
| 121 |
{ |
|---|
| 122 |
errno = EINVAL; |
|---|
| 123 |
return NULL; |
|---|
| 124 |
} |
|---|
| 125 |
|
|---|
| 126 |
#define CLEANUP() \ |
|---|
| 127 |
free (d.dir); \ |
|---|
| 128 |
if (a.arg) \ |
|---|
| 129 |
free (a.arg); |
|---|
| 130 |
|
|---|
| 131 |
if (printf_fetchargs (args, &a) < 0) |
|---|
| 132 |
{ |
|---|
| 133 |
CLEANUP (); |
|---|
| 134 |
errno = EINVAL; |
|---|
| 135 |
return NULL; |
|---|
| 136 |
} |
|---|
| 137 |
|
|---|
| 138 |
{ |
|---|
| 139 |
size_t buf_neededlength; |
|---|
| 140 |
CHAR_T *buf; |
|---|
| 141 |
CHAR_T *buf_malloced; |
|---|
| 142 |
const CHAR_T *cp; |
|---|
| 143 |
size_t i; |
|---|
| 144 |
DIRECTIVE *dp; |
|---|
| 145 |
/* Output string accumulator. */ |
|---|
| 146 |
CHAR_T *result; |
|---|
| 147 |
size_t allocated; |
|---|
| 148 |
size_t length; |
|---|
| 149 |
|
|---|
| 150 |
/* Allocate a small buffer that will hold a directive passed to |
|---|
| 151 |
snprintf. */ |
|---|
| 152 |
buf_neededlength = |
|---|
| 153 |
xsum4 (7, d.max_width_length, d.max_precision_length, 6); |
|---|
| 154 |
#if HAVE_ALLOCA |
|---|
| 155 |
if (buf_neededlength < 4000 / sizeof (CHAR_T)) |
|---|
| 156 |
{ |
|---|
| 157 |
buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T)); |
|---|
| 158 |
buf_malloced = NULL; |
|---|
| 159 |
} |
|---|
| 160 |
else |
|---|
| 161 |
#endif |
|---|
| 162 |
{ |
|---|
| 163 |
size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T)); |
|---|
| 164 |
if (size_overflow_p (buf_memsize)) |
|---|
| 165 |
goto out_of_memory_1; |
|---|
| 166 |
buf = (CHAR_T *) malloc (buf_memsize); |
|---|
| 167 |
if (buf == NULL) |
|---|
| 168 |
goto out_of_memory_1; |
|---|
| 169 |
buf_malloced = buf; |
|---|
| 170 |
} |
|---|
| 171 |
|
|---|
| 172 |
if (resultbuf != NULL) |
|---|
| 173 |
{ |
|---|
| 174 |
result = resultbuf; |
|---|
| 175 |
allocated = *lengthp; |
|---|
| 176 |
} |
|---|
| 177 |
else |
|---|
| 178 |
{ |
|---|
| 179 |
result = NULL; |
|---|
| 180 |
allocated = 0; |
|---|
| 181 |
} |
|---|
| 182 |
length = 0; |
|---|
| 183 |
/* Invariants: |
|---|
| 184 |
result is either == resultbuf or == NULL or malloc-allocated. |
|---|
| 185 |
If length > 0, then result != NULL. */ |
|---|
| 186 |
|
|---|
| 187 |
/* Ensures that allocated >= needed. Aborts through a jump to |
|---|
| 188 |
out_of_memory if needed is SIZE_MAX or otherwise too big. */ |
|---|
| 189 |
#define ENSURE_ALLOCATION(needed) \ |
|---|
| 190 |
if ((needed) > allocated) \ |
|---|
| 191 |
{ \ |
|---|
| 192 |
size_t memory_size; \ |
|---|
| 193 |
CHAR_T *memory; \ |
|---|
| 194 |
\ |
|---|
| 195 |
allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \ |
|---|
| 196 |
if ((needed) > allocated) \ |
|---|
| 197 |
allocated = (needed); \ |
|---|
| 198 |
memory_size = xtimes (allocated, sizeof (CHAR_T)); \ |
|---|
| 199 |
if (size_overflow_p (memory_size)) \ |
|---|
| 200 |
goto out_of_memory; \ |
|---|
| 201 |
if (result == resultbuf || result == NULL) \ |
|---|
| 202 |
memory = (CHAR_T *) malloc (memory_size); \ |
|---|
| 203 |
else \ |
|---|
| 204 |
memory = (CHAR_T *) realloc (result, memory_size); \ |
|---|
| 205 |
if (memory == NULL) \ |
|---|
| 206 |
goto out_of_memory; \ |
|---|
| 207 |
if (result == resultbuf && length > 0) \ |
|---|
| 208 |
memcpy (memory, result, length * sizeof (CHAR_T)); \ |
|---|
| 209 |
result = memory; \ |
|---|
| 210 |
} |
|---|
| 211 |
|
|---|
| 212 |
for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) |
|---|
| 213 |
{ |
|---|
| 214 |
if (cp != dp->dir_start) |
|---|
| 215 |
{ |
|---|
| 216 |
size_t n = dp->dir_start - cp; |
|---|
| 217 |
size_t augmented_length = xsum (length, n); |
|---|
| 218 |
|
|---|
| 219 |
ENSURE_ALLOCATION (augmented_length); |
|---|
| 220 |
memcpy (result + length, cp, n * sizeof (CHAR_T)); |
|---|
| 221 |
length = augmented_length; |
|---|
| 222 |
} |
|---|
| 223 |
if (i == d.count) |
|---|
| 224 |
break; |
|---|
| 225 |
|
|---|
| 226 |
/* Execute a single directive. */ |
|---|
| 227 |
if (dp->conversion == '%') |
|---|
| 228 |
{ |
|---|
| 229 |
size_t augmented_length; |
|---|
| 230 |
|
|---|
| 231 |
if (!(dp->arg_index == ARG_NONE)) |
|---|
| 232 |
abort (); |
|---|
| 233 |
augmented_length = xsum (length, 1); |
|---|
| 234 |
ENSURE_ALLOCATION (augmented_length); |
|---|
| 235 |
result[length] = '%'; |
|---|
| 236 |
length = augmented_length; |
|---|
| 237 |
} |
|---|
| 238 |
else |
|---|
| 239 |
{ |
|---|
| 240 |
if (!(dp->arg_index != ARG_NONE)) |
|---|
| 241 |
abort (); |
|---|
| 242 |
|
|---|
| 243 |
if (dp->conversion == 'n') |
|---|
| 244 |
{ |
|---|
| 245 |
switch (a.arg[dp->arg_index].type) |
|---|
| 246 |
{ |
|---|
| 247 |
case TYPE_COUNT_SCHAR_POINTER: |
|---|
| 248 |
*a.arg[dp->arg_index].a.a_count_schar_pointer = length; |
|---|
| 249 |
break; |
|---|
| 250 |
case TYPE_COUNT_SHORT_POINTER: |
|---|
| 251 |
*a.arg[dp->arg_index].a.a_count_short_pointer = length; |
|---|
| 252 |
break; |
|---|
| 253 |
case TYPE_COUNT_INT_POINTER: |
|---|
| 254 |
*a.arg[dp->arg_index].a.a_count_int_pointer = length; |
|---|
| 255 |
break; |
|---|
| 256 |
case TYPE_COUNT_LONGINT_POINTER: |
|---|
| 257 |
*a.arg[dp->arg_index].a.a_count_longint_pointer = length; |
|---|
| 258 |
break; |
|---|
| 259 |
#ifdef HAVE_LONG_LONG |
|---|
| 260 |
case TYPE_COUNT_LONGLONGINT_POINTER: |
|---|
| 261 |
*a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; |
|---|
| 262 |
break; |
|---|
| 263 |
#endif |
|---|
| 264 |
default: |
|---|
| 265 |
abort (); |
|---|
| 266 |
} |
|---|
| 267 |
} |
|---|
| 268 |
else |
|---|
| 269 |
{ |
|---|
| 270 |
arg_type type = a.arg[dp->arg_index].type; |
|---|
| 271 |
CHAR_T *p; |
|---|
| 272 |
unsigned int prefix_count; |
|---|
| 273 |
int prefixes[2]; |
|---|
| 274 |
|
|---|
| 275 |
/* Construct the format string for calling snprintf. */ |
|---|
| 276 |
p = buf; |
|---|
| 277 |
*p++ = '%'; |
|---|
| 278 |
if (dp->flags & FLAG_GROUP) |
|---|
| 279 |
*p++ = '\''; |
|---|
| 280 |
if (dp->flags & FLAG_LEFT) |
|---|
| 281 |
*p++ = '-'; |
|---|
| 282 |
if (dp->flags & FLAG_SHOWSIGN) |
|---|
| 283 |
*p++ = '+'; |
|---|
| 284 |
if (dp->flags & FLAG_SPACE) |
|---|
| 285 |
*p++ = ' '; |
|---|
| 286 |
if (dp->flags & FLAG_ALT) |
|---|
| 287 |
*p++ = '#'; |
|---|
| 288 |
if (dp->flags & FLAG_ZERO) |
|---|
| 289 |
*p++ = '0'; |
|---|
| 290 |
if (dp->width_start != dp->width_end) |
|---|
| 291 |
{ |
|---|
| 292 |
size_t n = dp->width_end - dp->width_start; |
|---|
| 293 |
memcpy (p, dp->width_start, n * sizeof (CHAR_T)); |
|---|
| 294 |
p += n; |
|---|
| 295 |
} |
|---|
| 296 |
if (dp->precision_start != dp->precision_end) |
|---|
| 297 |
{ |
|---|
| 298 |
size_t n = dp->precision_end - dp->precision_start; |
|---|
| 299 |
memcpy (p, dp->precision_start, n * sizeof (CHAR_T)); |
|---|
| 300 |
p += n; |
|---|
| 301 |
} |
|---|
| 302 |
|
|---|
| 303 |
switch (type) |
|---|
| 304 |
{ |
|---|
| 305 |
#ifdef HAVE_LONG_LONG |
|---|
| 306 |
case TYPE_LONGLONGINT: |
|---|
| 307 |
case TYPE_ULONGLONGINT: |
|---|
| 308 |
*p++ = 'l'; |
|---|
| 309 |
/*FALLTHROUGH*/ |
|---|
| 310 |
#endif |
|---|
| 311 |
case TYPE_LONGINT: |
|---|
| 312 |
case TYPE_ULONGINT: |
|---|
| 313 |
#ifdef HAVE_WINT_T |
|---|
| 314 |
case TYPE_WIDE_CHAR: |
|---|
| 315 |
#endif |
|---|
| 316 |
#ifdef HAVE_WCHAR_T |
|---|
| 317 |
case TYPE_WIDE_STRING: |
|---|
| 318 |
#endif |
|---|
| 319 |
*p++ = 'l'; |
|---|
| 320 |
break; |
|---|
| 321 |
#ifdef HAVE_LONG_DOUBLE |
|---|
| 322 |
case TYPE_LONGDOUBLE: |
|---|
| 323 |
*p++ = 'L'; |
|---|
| 324 |
break; |
|---|
| 325 |
#endif |
|---|
| 326 |
default: |
|---|
| 327 |
break; |
|---|
| 328 |
} |
|---|
| 329 |
*p = dp->conversion; |
|---|
| 330 |
#if USE_SNPRINTF |
|---|
| 331 |
p[1] = '%'; |
|---|
| 332 |
p[2] = 'n'; |
|---|
| 333 |
p[3] = '\0'; |
|---|
| 334 |
#else |
|---|
| 335 |
p[1] = '\0'; |
|---|
| 336 |
#endif |
|---|
| 337 |
|
|---|
| 338 |
/* Construct the arguments for calling snprintf. */ |
|---|
| 339 |
prefix_count = 0; |
|---|
| 340 |
if (dp->width_arg_index != ARG_NONE) |
|---|
| 341 |
{ |
|---|
| 342 |
if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) |
|---|
| 343 |
abort (); |
|---|
| 344 |
prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; |
|---|
| 345 |
} |
|---|
| 346 |
if (dp->precision_arg_index != ARG_NONE) |
|---|
| 347 |
{ |
|---|
| 348 |
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) |
|---|
| 349 |
abort (); |
|---|
| 350 |
prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; |
|---|
| 351 |
} |
|---|
| 352 |
|
|---|
| 353 |
#if USE_SNPRINTF |
|---|
| 354 |
/* Prepare checking whether snprintf returns the count |
|---|
| 355 |
via %n. */ |
|---|
| 356 |
ENSURE_ALLOCATION (xsum (length, 1)); |
|---|
| 357 |
result[length] = '\0'; |
|---|
| 358 |
#endif |
|---|
| 359 |
|
|---|
| 360 |
for (;;) |
|---|
| 361 |
{ |
|---|
| 362 |
size_t maxlen; |
|---|
| 363 |
int count; |
|---|
| 364 |
int retcount; |
|---|
| 365 |
|
|---|
| 366 |
maxlen = allocated - length; |
|---|
| 367 |
count = -1; |
|---|
| 368 |
retcount = 0; |
|---|
| 369 |
|
|---|
| 370 |
#if USE_SNPRINTF |
|---|
| 371 |
# define SNPRINTF_BUF(arg) \ |
|---|
| 372 |
switch (prefix_count) \ |
|---|
| 373 |
{ \ |
|---|
| 374 |
case 0: \ |
|---|
| 375 |
retcount = SNPRINTF (result + length, maxlen, buf, \ |
|---|
| 376 |
arg, &count); \ |
|---|
| 377 |
break; \ |
|---|
| 378 |
case 1: \ |
|---|
| 379 |
retcount = SNPRINTF (result + length, maxlen, buf, \ |
|---|
| 380 |
prefixes[0], arg, &count); \ |
|---|
| 381 |
break; \ |
|---|
| 382 |
case 2: \ |
|---|
| 383 |
retcount = SNPRINTF (result + length, maxlen, buf, \ |
|---|
| 384 |
prefixes[0], prefixes[1], arg, \ |
|---|
| 385 |
&count); \ |
|---|
| 386 |
break; \ |
|---|
| 387 |
default: \ |
|---|
| 388 |
abort (); \ |
|---|
| 389 |
} |
|---|
| 390 |
#endif |
|---|
| 391 |
|
|---|
| 392 |
switch (type) |
|---|
| 393 |
{ |
|---|
| 394 |
case TYPE_SCHAR: |
|---|
| 395 |
{ |
|---|
| 396 |
int arg = a.arg[dp->arg_index].a.a_schar; |
|---|
| 397 |
SNPRINTF_BUF (arg); |
|---|
| 398 |
} |
|---|
| 399 |
break; |
|---|
| 400 |
case TYPE_UCHAR: |
|---|
| 401 |
{ |
|---|
| 402 |
unsigned int arg = a.arg[dp->arg_index].a.a_uchar; |
|---|
| 403 |
SNPRINTF_BUF (arg); |
|---|
| 404 |
} |
|---|
| 405 |
break; |
|---|
| 406 |
case TYPE_SHORT: |
|---|
| 407 |
{ |
|---|
| 408 |
int arg = a.arg[dp->arg_index].a.a_short; |
|---|
| 409 |
SNPRINTF_BUF (arg); |
|---|
| 410 |
} |
|---|
| 411 |
break; |
|---|
| 412 |
case TYPE_USHORT: |
|---|
| 413 |
{ |
|---|
| 414 |
unsigned int arg = a.arg[dp->arg_index].a.a_ushort; |
|---|
| 415 |
SNPRINTF_BUF (arg); |
|---|
| 416 |
} |
|---|
| 417 |
break; |
|---|
| 418 |
case TYPE_INT: |
|---|
| 419 |
{ |
|---|
| 420 |
int arg = a.arg[dp->arg_index].a.a_int; |
|---|
| 421 |
SNPRINTF_BUF (arg); |
|---|
| 422 |
} |
|---|
| 423 |
break; |
|---|
| 424 |
case TYPE_UINT: |
|---|
| 425 |
{ |
|---|
| 426 |
unsigned int arg = a.arg[dp->arg_index].a.a_uint; |
|---|
| 427 |
SNPRINTF_BUF (arg); |
|---|
| 428 |
} |
|---|
| 429 |
break; |
|---|
| 430 |
case TYPE_LONGINT: |
|---|
| 431 |
{ |
|---|
| 432 |
long int arg = a.arg[dp->arg_index].a.a_longint; |
|---|
| 433 |
SNPRINTF_BUF (arg); |
|---|
| 434 |
} |
|---|
| 435 |
break; |
|---|
| 436 |
case TYPE_ULONGINT: |
|---|
| 437 |
{ |
|---|
| 438 |
unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint; |
|---|
| 439 |
SNPRINTF_BUF (arg); |
|---|
| 440 |
} |
|---|
| 441 |
break; |
|---|
| 442 |
#ifdef HAVE_LONG_LONG |
|---|
| 443 |
case TYPE_LONGLONGINT: |
|---|
| 444 |
{ |
|---|
| 445 |
long long int arg = a.arg[dp->arg_index].a.a_longlongint; |
|---|
| 446 |
SNPRINTF_BUF (arg); |
|---|
| 447 |
} |
|---|
| 448 |
break; |
|---|
| 449 |
case TYPE_ULONGLONGINT: |
|---|
| 450 |
{ |
|---|
| 451 |
unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint; |
|---|
| 452 |
SNPRINTF_BUF (arg); |
|---|
| 453 |
} |
|---|
| 454 |
break; |
|---|
| 455 |
#endif |
|---|
| 456 |
case TYPE_DOUBLE: |
|---|
| 457 |
{ |
|---|
| 458 |
double arg = a.arg[dp->arg_index].a.a_double; |
|---|
| 459 |
SNPRINTF_BUF (arg); |
|---|
| 460 |
} |
|---|
| 461 |
break; |
|---|
| 462 |
#ifdef HAVE_LONG_DOUBLE |
|---|
| 463 |
case TYPE_LONGDOUBLE: |
|---|
| 464 |
{ |
|---|
| 465 |
long double arg = a.arg[dp->arg_index].a.a_longdouble; |
|---|
| 466 |
SNPRINTF_BUF (arg); |
|---|
| 467 |
} |
|---|
| 468 |
break; |
|---|
| 469 |
#endif |
|---|
| 470 |
case TYPE_CHAR: |
|---|
| 471 |
{ |
|---|
| 472 |
int arg = a.arg[dp->arg_index].a.a_char; |
|---|
| 473 |
SNPRINTF_BUF (arg); |
|---|
| 474 |
} |
|---|
| 475 |
break; |
|---|
| 476 |
#ifdef HAVE_WINT_T |
|---|
| 477 |
case TYPE_WIDE_CHAR: |
|---|
| 478 |
{ |
|---|
| 479 |
wint_t arg = a.arg[dp->arg_index].a.a_wide_char; |
|---|
| 480 |
SNPRINTF_BUF (arg); |
|---|
| 481 |
} |
|---|
| 482 |
break; |
|---|
| 483 |
#endif |
|---|
| 484 |
case TYPE_STRING: |
|---|
| 485 |
{ |
|---|
| 486 |
const char *arg = a.arg[dp->arg_index].a.a_string; |
|---|
| 487 |
SNPRINTF_BUF (arg); |
|---|
| 488 |
} |
|---|
| 489 |
break; |
|---|
| 490 |
#ifdef HAVE_WCHAR_T |
|---|
| 491 |
case TYPE_WIDE_STRING: |
|---|
| 492 |
{ |
|---|
| 493 |
const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; |
|---|
| 494 |
SNPRINTF_BUF (arg); |
|---|
| 495 |
} |
|---|
| 496 |
break; |
|---|
| 497 |
#endif |
|---|
| 498 |
case TYPE_POINTER: |
|---|
| 499 |
{ |
|---|
| 500 |
void *arg = a.arg[dp->arg_index].a.a_pointer; |
|---|
| 501 |
SNPRINTF_BUF (arg); |
|---|
| 502 |
} |
|---|
| 503 |
break; |
|---|
| 504 |
default: |
|---|
| 505 |
abort (); |
|---|
| 506 |
} |
|---|
| 507 |
|
|---|
| 508 |
#if USE_SNPRINTF |
|---|
| 509 |
/* Portability: Not all implementations of snprintf() |
|---|
| 510 |
are ISO C 99 compliant. Determine the number of |
|---|
| 511 |
bytes that snprintf() has produced or would have |
|---|
| 512 |
produced. */ |
|---|
| 513 |
if (count >= 0) |
|---|
| 514 |
{ |
|---|
| 515 |
/* Verify that snprintf() has NUL-terminated its |
|---|
| 516 |
result. */ |
|---|
| 517 |
if (count < maxlen && result[length + count] != '\0') |
|---|
| 518 |
abort (); |
|---|
| 519 |
/* Portability hack. */ |
|---|
| 520 |
if (retcount > count) |
|---|
| 521 |
count = retcount; |
|---|
| 522 |
} |
|---|
| 523 |
else |
|---|
| 524 |
{ |
|---|
| 525 |
/* snprintf() doesn't understand the '%n' |
|---|
| 526 |
directive. */ |
|---|
| 527 |
if (p[1] != '\0') |
|---|
| 528 |
{ |
|---|
| 529 |
/* Don't use the '%n' directive; instead, look |
|---|
| 530 |
at the snprintf() return value. */ |
|---|
| 531 |
p[1] = '\0'; |
|---|
| 532 |
continue; |
|---|
| 533 |
} |
|---|
| 534 |
else |
|---|
| 535 |
{ |
|---|
| 536 |
/* Look at the snprintf() return value. */ |
|---|
| 537 |
if (retcount < 0) |
|---|
| 538 |
{ |
|---|
| 539 |
/* HP-UX 10.20 snprintf() is doubly deficient: |
|---|
| 540 |
It doesn't understand the '%n' directive, |
|---|
| 541 |
*and* it returns -1 (rather than the length |
|---|
| 542 |
that would have been required) when the |
|---|
| 543 |
buffer is too small. */ |
|---|
| 544 |
size_t bigger_need = |
|---|
| 545 |
xsum (xtimes (allocated, 2), 12); |
|---|
| 546 |
ENSURE_ALLOCATION (bigger_need); |
|---|
| 547 |
continue; |
|---|
| 548 |
} |
|---|
| 549 |
else |
|---|
| 550 |
count = retcount; |
|---|
| 551 |
} |
|---|
| 552 |
} |
|---|
| 553 |
#endif |
|---|
| 554 |
|
|---|
| 555 |
/* Attempt to handle failure. */ |
|---|
| 556 |
if (count < 0) |
|---|
| 557 |
{ |
|---|
| 558 |
if (!(result == resultbuf || result == NULL)) |
|---|
| 559 |
free (result); |
|---|
| 560 |
if (buf_malloced != NULL) |
|---|
| 561 |
free (buf_malloced); |
|---|
| 562 |
CLEANUP (); |
|---|
| 563 |
errno = EINVAL; |
|---|
| 564 |
return NULL; |
|---|
| 565 |
} |
|---|
| 566 |
|
|---|
| 567 |
#if !USE_SNPRINTF |
|---|
| 568 |
if (count >= tmp_length) |
|---|
| 569 |
/* tmp_length was incorrectly calculated - fix the |
|---|
| 570 |
code above! */ |
|---|
| 571 |
abort (); |
|---|
| 572 |
#endif |
|---|
| 573 |
|
|---|
| 574 |
/* Make room for the result. */ |
|---|
| 575 |
if (count >= maxlen) |
|---|
| 576 |
{ |
|---|
| 577 |
/* Need at least count bytes. But allocate |
|---|
| 578 |
proportionally, to avoid looping eternally if |
|---|
| 579 |
snprintf() reports a too small count. */ |
|---|
| 580 |
size_t n = |
|---|
| 581 |
xmax (xsum (length, count), xtimes (allocated, 2)); |
|---|
| 582 |
|
|---|
| 583 |
ENSURE_ALLOCATION (n); |
|---|
| 584 |
#if USE_SNPRINTF |
|---|
| 585 |
continue; |
|---|
| 586 |
#endif |
|---|
| 587 |
} |
|---|
| 588 |
|
|---|
| 589 |
length += count; |
|---|
| 590 |
break; |
|---|
| 591 |
} |
|---|
| 592 |
} |
|---|
| 593 |
} |
|---|
| 594 |
} |
|---|
| 595 |
|
|---|
| 596 |
/* Add the final NUL. */ |
|---|
| 597 |
ENSURE_ALLOCATION (xsum (length, 1)); |
|---|
| 598 |
result[length] = '\0'; |
|---|
| 599 |
|
|---|
| 600 |
if (result != resultbuf && length + 1 < allocated) |
|---|
| 601 |
{ |
|---|
| 602 |
/* Shrink the allocated memory if possible. */ |
|---|
| 603 |
CHAR_T *memory; |
|---|
| 604 |
|
|---|
| 605 |
memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T)); |
|---|
| 606 |
if (memory != NULL) |
|---|
| 607 |
result = memory; |
|---|
| 608 |
} |
|---|
| 609 |
|
|---|
| 610 |
if (buf_malloced != NULL) |
|---|
| 611 |
free (buf_malloced); |
|---|
| 612 |
CLEANUP (); |
|---|
| 613 |
*lengthp = length; |
|---|
| 614 |
if (length > INT_MAX) |
|---|
| 615 |
goto length_overflow; |
|---|
| 616 |
return result; |
|---|
| 617 |
|
|---|
| 618 |
length_overflow: |
|---|
| 619 |
/* We could produce such a big string, but its length doesn't fit into |
|---|
| 620 |
an 'int'. POSIX says that snprintf() fails with errno = EOVERFLOW in |
|---|
| 621 |
this case. */ |
|---|
| 622 |
if (result != resultbuf) |
|---|
| 623 |
free (result); |
|---|
| 624 |
errno = EOVERFLOW; |
|---|
| 625 |
return NULL; |
|---|
| 626 |
|
|---|
| 627 |
out_of_memory: |
|---|
| 628 |
if (!(result == resultbuf || result == NULL)) |
|---|
| 629 |
free (result); |
|---|
| 630 |
if (buf_malloced != NULL) |
|---|
| 631 |
free (buf_malloced); |
|---|
| 632 |
out_of_memory_1: |
|---|
| 633 |
CLEANUP (); |
|---|
| 634 |
errno = ENOMEM; |
|---|
| 635 |
return NULL; |
|---|
| 636 |
} |
|---|
| 637 |
} |
|---|
| 638 |
|
|---|
| 639 |
#undef SNPRINTF |
|---|
| 640 |
#undef USE_SNPRINTF |
|---|
| 641 |
#undef PRINTF_PARSE |
|---|
| 642 |
#undef DIRECTIVES |
|---|
| 643 |
#undef DIRECTIVE |
|---|
| 644 |
#undef CHAR_T |
|---|
| 645 |
#undef VASNPRINTF |
|---|