1186690Sobrien/* 2186690Sobrien * Copyright (c) Ian F. Darwin 1986-1995. 3186690Sobrien * Software written by Ian F. Darwin and others; 4186690Sobrien * maintained 1995-present by Christos Zoulas and others. 5186690Sobrien * 6186690Sobrien * Redistribution and use in source and binary forms, with or without 7186690Sobrien * modification, are permitted provided that the following conditions 8186690Sobrien * are met: 9186690Sobrien * 1. Redistributions of source code must retain the above copyright 10186690Sobrien * notice immediately at the beginning of the file, without modification, 11186690Sobrien * this list of conditions, and the following disclaimer. 12186690Sobrien * 2. Redistributions in binary form must reproduce the above copyright 13186690Sobrien * notice, this list of conditions and the following disclaimer in the 14186690Sobrien * documentation and/or other materials provided with the distribution. 15186690Sobrien * 16186690Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17186690Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18186690Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19186690Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20186690Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21186690Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22186690Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23186690Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24186690Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25186690Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26186690Sobrien * SUCH DAMAGE. 27186690Sobrien */ 28186690Sobrien/*########################################################################### 29186690Sobrien # # 30186690Sobrien # vasprintf # 31186690Sobrien # # 32186690Sobrien # Copyright (c) 2002-2005 David TAILLANDIER # 33186690Sobrien # # 34186690Sobrien ###########################################################################*/ 35186690Sobrien 36186690Sobrien/* 37186690Sobrien 38186690SobrienThis software is distributed under the "modified BSD licence". 39186690Sobrien 40186690SobrienThis software is also released with GNU license (GPL) in another file (same 41186690Sobriensource-code, only license differ). 42186690Sobrien 43186690Sobrien 44186690Sobrien 45186690SobrienRedistribution and use in source and binary forms, with or without 46186690Sobrienmodification, are permitted provided that the following conditions are met: 47186690Sobrien 48186690SobrienRedistributions of source code must retain the above copyright notice, this 49186690Sobrienlist of conditions and the following disclaimer. Redistributions in binary 50186690Sobrienform must reproduce the above copyright notice, this list of conditions and 51186690Sobrienthe following disclaimer in the documentation and/or other materials 52186690Sobrienprovided with the distribution. The name of the author may not be used to 53186690Sobrienendorse or promote products derived from this software without specific 54186690Sobrienprior written permission. 55186690Sobrien 56186690SobrienTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 57186690SobrienWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 58186690SobrienMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 59186690SobrienEVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 60186690SobrienSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 61186690SobrienPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 62186690SobrienOR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 63186690SobrienWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 64186690SobrienOTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 65186690SobrienADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 66186690Sobrien 67186690Sobrien==================== 68186690Sobrien 69186690SobrienHacked from xnprintf version of 26th February 2005 to provide only 70186690Sobrienvasprintf by Reuben Thomas <rrt@sc3d.org>. 71186690Sobrien 72186690Sobrien==================== 73186690Sobrien 74186690Sobrien 75186690Sobrien'printf' function family use the following format string: 76186690Sobrien 77186690Sobrien%[flag][width][.prec][modifier]type 78186690Sobrien 79186690Sobrien%% is the escape sequence to print a '%' 80186690Sobrien% followed by an unknown format will print the characters without 81186690Sobrientrying to do any interpretation 82186690Sobrien 83186690Sobrienflag: none + - # (blank) 84186690Sobrienwidth: n 0n * 85186690Sobrienprec: none .0 .n .* 86267843Sdelphijmodifier: F N L h l ll z t ('F' and 'N' are ms-dos/16-bit specific) 87186690Sobrientype: d i o u x X f e g E G c s p n 88186690Sobrien 89186690Sobrien 90186690SobrienThe function needs to allocate memory to store the full text before to 91328875Seadleractually writing it. i.e if you want to fnprintf() 1000 characters, the 92186690Sobrienfunctions will allocate 1000 bytes. 93186690SobrienThis behaviour can be modified: you have to customise the code to flush the 94186690Sobrieninternal buffer (writing to screen or file) when it reach a given size. Then 95186690Sobrienthe buffer can have a shorter length. But what? If you really need to write 96186690SobrienHUGE string, don't use printf! 97186690SobrienDuring the process, some other memory is allocated (1024 bytes minimum) 98186690Sobriento handle the output of partial sprintf() calls. If you have only 10000 bytes 99186690Sobrienfree in memory, you *may* not be able to nprintf() a 8000 bytes-long text. 100186690Sobrien 101186690Sobriennote: if a buffer overflow occurs, exit() is called. This situation should 102186690Sobriennever appear ... but if you want to be *really* sure, you have to modify the 103186690Sobriencode to handle those situations (only one place to modify). 104186690SobrienA buffer overflow can only occur if your sprintf() do strange things or when 105186690Sobrienyou use strange formats. 106186690Sobrien 107186690Sobrien*/ 108191736Sobrien#include "file.h" 109186690Sobrien 110191736Sobrien#ifndef lint 111328875SeadlerFILE_RCSID("@(#)$File: vasprintf.c,v 1.14 2017/08/13 00:21:47 christos Exp $") 112191736Sobrien#endif /* lint */ 113191736Sobrien 114186690Sobrien#include <assert.h> 115186690Sobrien#include <string.h> 116186690Sobrien#include <stdlib.h> 117186690Sobrien#include <stdarg.h> 118186690Sobrien#include <ctype.h> 119186690Sobrien#ifdef HAVE_LIMITS_H 120186690Sobrien#include <limits.h> 121186690Sobrien#endif 122267843Sdelphij#ifdef HAVE_STDDEF_H 123267843Sdelphij#include <stddef.h> 124267843Sdelphij#endif 125186690Sobrien 126186690Sobrien#define ALLOC_CHUNK 2048 127186690Sobrien#define ALLOC_SECURITY_MARGIN 1024 /* big value because some platforms have very big 'G' exponent */ 128186690Sobrien#if ALLOC_CHUNK < ALLOC_SECURITY_MARGIN 129186690Sobrien# error !!! ALLOC_CHUNK < ALLOC_SECURITY_MARGIN !!! 130186690Sobrien#endif 131186690Sobrien/* note: to have some interest, ALLOC_CHUNK should be much greater than ALLOC_SECURITY_MARGIN */ 132186690Sobrien 133186690Sobrien/* 134186690Sobrien * To save a lot of push/pop, every variable are stored into this 135186690Sobrien * structure, which is passed among nearly every sub-functions. 136186690Sobrien */ 137186690Sobrientypedef struct { 138186690Sobrien const char * src_string; /* current position into intput string */ 139186690Sobrien char * buffer_base; /* output buffer */ 140186690Sobrien char * dest_string; /* current position into output string */ 141186690Sobrien size_t buffer_len; /* length of output buffer */ 142186690Sobrien size_t real_len; /* real current length of output text */ 143186690Sobrien size_t pseudo_len; /* total length of output text if it were not limited in size */ 144186690Sobrien size_t maxlen; 145186690Sobrien va_list vargs; /* pointer to current position into vargs */ 146186690Sobrien char * sprintf_string; 147186690Sobrien FILE * fprintf_file; 148186690Sobrien} xprintf_struct; 149186690Sobrien 150186690Sobrien/* 151186690Sobrien * Realloc buffer if needed 152186690Sobrien * Return value: 0 = ok 153186690Sobrien * EOF = not enought memory 154186690Sobrien */ 155186690Sobrienstatic int realloc_buff(xprintf_struct *s, size_t len) 156186690Sobrien{ 157186690Sobrien char * ptr; 158186690Sobrien 159186690Sobrien if (len + ALLOC_SECURITY_MARGIN + s->real_len > s->buffer_len) { 160186690Sobrien len += s->real_len + ALLOC_CHUNK; 161186690Sobrien ptr = (char *)realloc((void *)(s->buffer_base), len); 162186690Sobrien if (ptr == NULL) { 163186690Sobrien s->buffer_base = NULL; 164186690Sobrien return EOF; 165186690Sobrien } 166186690Sobrien 167186690Sobrien s->dest_string = ptr + (size_t)(s->dest_string - s->buffer_base); 168186690Sobrien s->buffer_base = ptr; 169186690Sobrien s->buffer_len = len; 170186690Sobrien 171186690Sobrien (s->buffer_base)[s->buffer_len - 1] = 1; /* overflow marker */ 172186690Sobrien } 173186690Sobrien 174186690Sobrien return 0; 175186690Sobrien} 176186690Sobrien 177186690Sobrien/* 178186690Sobrien * Prints 'usual' characters up to next '%' 179186690Sobrien * or up to end of text 180186690Sobrien */ 181186690Sobrienstatic int usual_char(xprintf_struct * s) 182186690Sobrien{ 183186690Sobrien size_t len; 184186690Sobrien 185186690Sobrien len = strcspn(s->src_string, "%"); /* reachs the next '%' or end of input string */ 186186690Sobrien /* note: 'len' is never 0 because the presence of '%' */ 187186690Sobrien /* or end-of-line is checked in the calling function */ 188186690Sobrien 189186690Sobrien if (realloc_buff(s,len) == EOF) 190186690Sobrien return EOF; 191186690Sobrien 192186690Sobrien memcpy(s->dest_string, s->src_string, len); 193186690Sobrien s->src_string += len; 194186690Sobrien s->dest_string += len; 195186690Sobrien s->real_len += len; 196186690Sobrien s->pseudo_len += len; 197186690Sobrien 198186690Sobrien return 0; 199186690Sobrien} 200186690Sobrien 201186690Sobrien/* 202186690Sobrien * Return value: 0 = ok 203186690Sobrien * EOF = error 204186690Sobrien */ 205186690Sobrienstatic int print_it(xprintf_struct *s, size_t approx_len, 206186690Sobrien const char *format_string, ...) 207186690Sobrien{ 208186690Sobrien va_list varg; 209186690Sobrien int vsprintf_len; 210186690Sobrien size_t len; 211186690Sobrien 212186690Sobrien if (realloc_buff(s,approx_len) == EOF) 213186690Sobrien return EOF; 214186690Sobrien 215186690Sobrien va_start(varg, format_string); 216186690Sobrien vsprintf_len = vsprintf(s->dest_string, format_string, varg); 217186690Sobrien va_end(varg); 218186690Sobrien 219186690Sobrien /* Check for overflow */ 220186690Sobrien assert((s->buffer_base)[s->buffer_len - 1] == 1); 221186690Sobrien 222186690Sobrien if (vsprintf_len == EOF) /* must be done *after* overflow-check */ 223186690Sobrien return EOF; 224186690Sobrien 225186690Sobrien s->pseudo_len += vsprintf_len; 226186690Sobrien len = strlen(s->dest_string); 227186690Sobrien s->real_len += len; 228186690Sobrien s->dest_string += len; 229186690Sobrien 230186690Sobrien return 0; 231186690Sobrien} 232186690Sobrien 233186690Sobrien/* 234186690Sobrien * Prints a string (%s) 235186690Sobrien * We need special handling because: 236186690Sobrien * a: the length of the string is unknown 237186690Sobrien * b: when .prec is used, we must not access any extra byte of the 238186690Sobrien * string (of course, if the original sprintf() does... what the 239186690Sobrien * hell, not my problem) 240186690Sobrien * 241186690Sobrien * Return value: 0 = ok 242186690Sobrien * EOF = error 243186690Sobrien */ 244186690Sobrienstatic int type_s(xprintf_struct *s, int width, int prec, 245186690Sobrien const char *format_string, const char *arg_string) 246186690Sobrien{ 247186690Sobrien size_t string_len; 248186690Sobrien 249186690Sobrien if (arg_string == NULL) 250186690Sobrien return print_it(s, (size_t)6, "(null)", 0); 251186690Sobrien 252186690Sobrien /* hand-made strlen() whitch stops when 'prec' is reached. */ 253186690Sobrien /* if 'prec' is -1 then it is never reached. */ 254186690Sobrien string_len = 0; 255186690Sobrien while (arg_string[string_len] != 0 && (size_t)prec != string_len) 256186690Sobrien string_len++; 257186690Sobrien 258186690Sobrien if (width != -1 && string_len < (size_t)width) 259186690Sobrien string_len = (size_t)width; 260186690Sobrien 261186690Sobrien return print_it(s, string_len, format_string, arg_string); 262186690Sobrien} 263186690Sobrien 264186690Sobrien/* 265186690Sobrien * Read a serie of digits. Stop when non-digit is found. 266186690Sobrien * Return value: the value read (between 0 and 32767). 267186690Sobrien * Note: no checks are made against overflow. If the string contain a big 268186690Sobrien * number, then the return value won't be what we want (but, in this case, 269186690Sobrien * the programmer don't know whatr he wants, then no problem). 270186690Sobrien */ 271186690Sobrienstatic int getint(const char **string) 272186690Sobrien{ 273186690Sobrien int i = 0; 274186690Sobrien 275186690Sobrien while (isdigit((unsigned char)**string) != 0) { 276186690Sobrien i = i * 10 + (**string - '0'); 277186690Sobrien (*string)++; 278186690Sobrien } 279186690Sobrien 280186690Sobrien if (i < 0 || i > 32767) 281186690Sobrien i = 32767; /* if we have i==-10 this is not because the number is */ 282186690Sobrien /* negative; this is because the number is big */ 283186690Sobrien return i; 284186690Sobrien} 285186690Sobrien 286186690Sobrien/* 287186690Sobrien * Read a part of the format string. A part is 'usual characters' (ie "blabla") 288186690Sobrien * or '%%' escape sequence (to print a single '%') or any combination of 289186690Sobrien * format specifier (ie "%i" or "%10.2d"). 290186690Sobrien * After the current part is managed, the function returns to caller with 291186690Sobrien * everything ready to manage the following part. 292186690Sobrien * The caller must ensure than the string is not empty, i.e. the first byte 293186690Sobrien * is not zero. 294186690Sobrien * 295186690Sobrien * Return value: 0 = ok 296186690Sobrien * EOF = error 297186690Sobrien */ 298186690Sobrienstatic int dispatch(xprintf_struct *s) 299186690Sobrien{ 300186690Sobrien const char *initial_ptr; 301186690Sobrien char format_string[24]; /* max length may be something like "% +-#032768.32768Ld" */ 302186690Sobrien char *format_ptr; 303186690Sobrien int flag_plus, flag_minus, flag_space, flag_sharp, flag_zero; 304186690Sobrien int width, prec, modifier, approx_width; 305186690Sobrien char type; 306186690Sobrien /* most of those variables are here to rewrite the format string */ 307186690Sobrien 308186690Sobrien#define SRCTXT (s->src_string) 309186690Sobrien#define DESTTXT (s->dest_string) 310186690Sobrien 311186690Sobrien /* incoherent format string. Characters after the '%' will be printed with the next call */ 312186690Sobrien#define INCOHERENT() do {SRCTXT=initial_ptr; return 0;} while (0) /* do/while to avoid */ 313186690Sobrien#define INCOHERENT_TEST() do {if(*SRCTXT==0) INCOHERENT();} while (0) /* a null statement */ 314186690Sobrien 315186690Sobrien /* 'normal' text */ 316186690Sobrien if (*SRCTXT != '%') 317186690Sobrien return usual_char(s); 318186690Sobrien 319186690Sobrien /* we then have a '%' */ 320186690Sobrien SRCTXT++; 321186690Sobrien /* don't check for end-of-string ; this is done later */ 322186690Sobrien 323186690Sobrien /* '%%' escape sequence */ 324186690Sobrien if (*SRCTXT == '%') { 325186690Sobrien if (realloc_buff(s, (size_t)1) == EOF) /* because we can have "%%%%%%%%..." */ 326186690Sobrien return EOF; 327186690Sobrien *DESTTXT = '%'; 328186690Sobrien DESTTXT++; 329186690Sobrien SRCTXT++; 330186690Sobrien (s->real_len)++; 331186690Sobrien (s->pseudo_len)++; 332186690Sobrien return 0; 333186690Sobrien } 334186690Sobrien 335186690Sobrien /* '%' managing */ 336186690Sobrien initial_ptr = SRCTXT; /* save current pointer in case of incorrect */ 337186690Sobrien /* 'decoding'. Points just after the '%' so the '%' */ 338186690Sobrien /* won't be printed in any case, as required. */ 339186690Sobrien 340186690Sobrien /* flag */ 341186690Sobrien flag_plus = flag_minus = flag_space = flag_sharp = flag_zero = 0; 342186690Sobrien 343186690Sobrien for (;; SRCTXT++) { 344186690Sobrien if (*SRCTXT == ' ') 345186690Sobrien flag_space = 1; 346186690Sobrien else if (*SRCTXT == '+') 347186690Sobrien flag_plus = 1; 348186690Sobrien else if (*SRCTXT == '-') 349186690Sobrien flag_minus = 1; 350186690Sobrien else if (*SRCTXT == '#') 351186690Sobrien flag_sharp = 1; 352186690Sobrien else if (*SRCTXT == '0') 353186690Sobrien flag_zero = 1; 354186690Sobrien else 355186690Sobrien break; 356186690Sobrien } 357186690Sobrien 358186690Sobrien INCOHERENT_TEST(); /* here is the first test for end of string */ 359186690Sobrien 360186690Sobrien /* width */ 361186690Sobrien if (*SRCTXT == '*') { /* width given by next argument */ 362186690Sobrien SRCTXT++; 363186690Sobrien width = va_arg(s->vargs, int); 364186690Sobrien if ((size_t)width > 0x3fffU) /* 'size_t' to check against negative values too */ 365186690Sobrien width = 0x3fff; 366186690Sobrien } else if (isdigit((unsigned char)*SRCTXT)) /* width given as ASCII number */ 367186690Sobrien width = getint(&SRCTXT); 368186690Sobrien else 369186690Sobrien width = -1; /* no width specified */ 370186690Sobrien 371186690Sobrien INCOHERENT_TEST(); 372186690Sobrien 373186690Sobrien /* .prec */ 374186690Sobrien if (*SRCTXT == '.') { 375186690Sobrien SRCTXT++; 376186690Sobrien if (*SRCTXT == '*') { /* .prec given by next argument */ 377186690Sobrien SRCTXT++; 378186690Sobrien prec = va_arg(s->vargs, int); 379186690Sobrien if ((size_t)prec >= 0x3fffU) /* 'size_t' to check against negative values too */ 380186690Sobrien prec = 0x3fff; 381186690Sobrien } else { /* .prec given as ASCII number */ 382186690Sobrien if (isdigit((unsigned char)*SRCTXT) == 0) 383186690Sobrien INCOHERENT(); 384186690Sobrien prec = getint(&SRCTXT); 385186690Sobrien } 386186690Sobrien INCOHERENT_TEST(); 387186690Sobrien } else 388186690Sobrien prec = -1; /* no .prec specified */ 389186690Sobrien 390186690Sobrien /* modifier */ 391267843Sdelphij switch (*SRCTXT) { 392267843Sdelphij case 'L': 393267843Sdelphij case 'h': 394267843Sdelphij case 'l': 395267843Sdelphij case 'z': 396267843Sdelphij case 't': 397186690Sobrien modifier = *SRCTXT; 398186690Sobrien SRCTXT++; 399186690Sobrien if (modifier=='l' && *SRCTXT=='l') { 400186690Sobrien SRCTXT++; 401186690Sobrien modifier = 'L'; /* 'll' == 'L' long long == long double */ 402186690Sobrien } /* only for compatibility ; not portable */ 403186690Sobrien INCOHERENT_TEST(); 404267843Sdelphij break; 405267843Sdelphij default: 406186690Sobrien modifier = -1; /* no modifier specified */ 407267843Sdelphij break; 408267843Sdelphij } 409186690Sobrien 410186690Sobrien /* type */ 411186690Sobrien type = *SRCTXT; 412186690Sobrien if (strchr("diouxXfegEGcspn",type) == NULL) 413186690Sobrien INCOHERENT(); /* unknown type */ 414186690Sobrien SRCTXT++; 415186690Sobrien 416186690Sobrien /* rewrite format-string */ 417186690Sobrien format_string[0] = '%'; 418186690Sobrien format_ptr = &(format_string[1]); 419186690Sobrien 420186690Sobrien if (flag_plus) { 421186690Sobrien *format_ptr = '+'; 422186690Sobrien format_ptr++; 423186690Sobrien } 424186690Sobrien if (flag_minus) { 425186690Sobrien *format_ptr = '-'; 426186690Sobrien format_ptr++; 427186690Sobrien } 428186690Sobrien if (flag_space) { 429186690Sobrien *format_ptr = ' '; 430186690Sobrien format_ptr++; 431186690Sobrien } 432186690Sobrien if (flag_sharp) { 433186690Sobrien *format_ptr = '#'; 434186690Sobrien format_ptr++; 435186690Sobrien } 436186690Sobrien if (flag_zero) { 437186690Sobrien *format_ptr = '0'; 438186690Sobrien format_ptr++; 439186690Sobrien } /* '0' *must* be the last one */ 440186690Sobrien 441186690Sobrien if (width != -1) { 442186690Sobrien sprintf(format_ptr, "%i", width); 443186690Sobrien format_ptr += strlen(format_ptr); 444186690Sobrien } 445186690Sobrien 446186690Sobrien if (prec != -1) { 447186690Sobrien *format_ptr = '.'; 448186690Sobrien format_ptr++; 449186690Sobrien sprintf(format_ptr, "%i", prec); 450186690Sobrien format_ptr += strlen(format_ptr); 451186690Sobrien } 452186690Sobrien 453186690Sobrien if (modifier != -1) { 454186690Sobrien if (modifier == 'L' && strchr("diouxX",type) != NULL) { 455186690Sobrien *format_ptr = 'l'; 456186690Sobrien format_ptr++; 457186690Sobrien *format_ptr = 'l'; 458186690Sobrien format_ptr++; 459186690Sobrien } else { 460186690Sobrien *format_ptr = modifier; 461186690Sobrien format_ptr++; 462186690Sobrien } 463186690Sobrien } 464186690Sobrien 465186690Sobrien *format_ptr = type; 466186690Sobrien format_ptr++; 467186690Sobrien *format_ptr = 0; 468186690Sobrien 469186690Sobrien /* vague approximation of minimal length if width or prec are specified */ 470186690Sobrien approx_width = width + prec; 471186690Sobrien if (approx_width < 0) /* because width == -1 and/or prec == -1 */ 472186690Sobrien approx_width = 0; 473186690Sobrien 474186690Sobrien switch (type) { 475186690Sobrien /* int */ 476186690Sobrien case 'd': 477186690Sobrien case 'i': 478186690Sobrien case 'o': 479186690Sobrien case 'u': 480186690Sobrien case 'x': 481186690Sobrien case 'X': 482186690Sobrien switch (modifier) { 483186690Sobrien case -1 : 484186690Sobrien return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int)); 485186690Sobrien case 'L': 486186690Sobrien return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long long int)); 487186690Sobrien case 'l': 488186690Sobrien return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long int)); 489186690Sobrien case 'h': 490186690Sobrien return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int)); 491267843Sdelphij case 'z': 492267843Sdelphij return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, size_t)); 493267843Sdelphij case 't': 494267843Sdelphij return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, ptrdiff_t)); 495186690Sobrien /* 'int' instead of 'short int' because default promotion is 'int' */ 496186690Sobrien default: 497186690Sobrien INCOHERENT(); 498186690Sobrien } 499186690Sobrien 500186690Sobrien /* char */ 501186690Sobrien case 'c': 502186690Sobrien if (modifier != -1) 503186690Sobrien INCOHERENT(); 504186690Sobrien return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int)); 505186690Sobrien /* 'int' instead of 'char' because default promotion is 'int' */ 506186690Sobrien 507186690Sobrien /* math */ 508186690Sobrien case 'e': 509186690Sobrien case 'f': 510186690Sobrien case 'g': 511186690Sobrien case 'E': 512186690Sobrien case 'G': 513186690Sobrien switch (modifier) { 514186690Sobrien case -1 : /* because of default promotion, no modifier means 'l' */ 515186690Sobrien case 'l': 516186690Sobrien return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, double)); 517186690Sobrien case 'L': 518186690Sobrien return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long double)); 519186690Sobrien default: 520186690Sobrien INCOHERENT(); 521186690Sobrien } 522186690Sobrien 523186690Sobrien /* string */ 524186690Sobrien case 's': 525186690Sobrien return type_s(s, width, prec, format_string, va_arg(s->vargs, const char*)); 526186690Sobrien 527186690Sobrien /* pointer */ 528186690Sobrien case 'p': 529186690Sobrien if (modifier == -1) 530186690Sobrien return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, void *)); 531186690Sobrien INCOHERENT(); 532186690Sobrien 533186690Sobrien /* store */ 534186690Sobrien case 'n': 535186690Sobrien if (modifier == -1) { 536186690Sobrien int * p; 537186690Sobrien p = va_arg(s->vargs, int *); 538186690Sobrien if (p != NULL) { 539186690Sobrien *p = s->pseudo_len; 540186690Sobrien return 0; 541186690Sobrien } 542186690Sobrien return EOF; 543186690Sobrien } 544186690Sobrien INCOHERENT(); 545186690Sobrien 546186690Sobrien } /* switch */ 547186690Sobrien 548186690Sobrien INCOHERENT(); /* unknown type */ 549186690Sobrien 550186690Sobrien#undef INCOHERENT 551186690Sobrien#undef INCOHERENT_TEST 552186690Sobrien#undef SRCTXT 553186690Sobrien#undef DESTTXT 554186690Sobrien} 555186690Sobrien 556186690Sobrien/* 557186690Sobrien * Return value: number of *virtually* written characters 558186690Sobrien * EOF = error 559186690Sobrien */ 560186690Sobrienstatic int core(xprintf_struct *s) 561186690Sobrien{ 562267843Sdelphij size_t save_len; 563186690Sobrien char *dummy_base; 564186690Sobrien 565186690Sobrien /* basic checks */ 566186690Sobrien if ((int)(s->maxlen) <= 0) /* 'int' to check against some conversion */ 567186690Sobrien return EOF; /* error for example if value is (int)-10 */ 568186690Sobrien s->maxlen--; /* because initial maxlen counts final 0 */ 569186690Sobrien /* note: now 'maxlen' _can_ be zero */ 570186690Sobrien 571186690Sobrien if (s->src_string == NULL) 572186690Sobrien s->src_string = "(null)"; 573186690Sobrien 574186690Sobrien /* struct init and memory allocation */ 575186690Sobrien s->buffer_base = NULL; 576186690Sobrien s->buffer_len = 0; 577186690Sobrien s->real_len = 0; 578186690Sobrien s->pseudo_len = 0; 579186690Sobrien if (realloc_buff(s, (size_t)0) == EOF) 580186690Sobrien return EOF; 581186690Sobrien s->dest_string = s->buffer_base; 582186690Sobrien 583186690Sobrien /* process source string */ 584186690Sobrien for (;;) { 585186690Sobrien /* up to end of source string */ 586186690Sobrien if (*(s->src_string) == 0) { 587267843Sdelphij *(s->dest_string) = '\0'; /* final NUL */ 588186690Sobrien break; 589186690Sobrien } 590186690Sobrien 591186690Sobrien if (dispatch(s) == EOF) 592186690Sobrien goto free_EOF; 593186690Sobrien 594186690Sobrien /* up to end of dest string */ 595186690Sobrien if (s->real_len >= s->maxlen) { 596267843Sdelphij (s->buffer_base)[s->maxlen] = '\0'; /* final NUL */ 597186690Sobrien break; 598186690Sobrien } 599186690Sobrien } 600186690Sobrien 601186690Sobrien /* for (v)asnprintf */ 602186690Sobrien dummy_base = s->buffer_base; 603186690Sobrien 604186690Sobrien dummy_base = s->buffer_base + s->real_len; 605186690Sobrien save_len = s->real_len; 606186690Sobrien 607186690Sobrien /* process the remaining of source string to compute 'pseudo_len'. We 608186690Sobrien * overwrite again and again, starting at 'dummy_base' because we don't 609186690Sobrien * need the text, only char count. */ 610186690Sobrien while(*(s->src_string) != 0) { /* up to end of source string */ 611186690Sobrien s->real_len = 0; 612186690Sobrien s->dest_string = dummy_base; 613186690Sobrien if (dispatch(s) == EOF) 614186690Sobrien goto free_EOF; 615186690Sobrien } 616186690Sobrien 617186690Sobrien s->buffer_base = (char *)realloc((void *)(s->buffer_base), save_len + 1); 618186690Sobrien if (s->buffer_base == NULL) 619186690Sobrien return EOF; /* should rarely happen because we shrink the buffer */ 620186690Sobrien return s->pseudo_len; 621186690Sobrien 622186690Sobrien free_EOF: 623234250Sobrien free(s->buffer_base); 624186690Sobrien return EOF; 625186690Sobrien} 626186690Sobrien 627186690Sobrienint vasprintf(char **ptr, const char *format_string, va_list vargs) 628186690Sobrien{ 629186690Sobrien xprintf_struct s; 630186690Sobrien int retval; 631186690Sobrien 632186690Sobrien s.src_string = format_string; 633186690Sobrien#ifdef va_copy 634186690Sobrien va_copy (s.vargs, vargs); 635186690Sobrien#else 636276415Sdelphij# ifdef __va_copy 637186690Sobrien __va_copy (s.vargs, vargs); 638276415Sdelphij# else 639276415Sdelphij# ifdef WIN32 640276415Sdelphij s.vargs = vargs; 641276415Sdelphij# else 642267843Sdelphij memcpy (&s.vargs, &vargs, sizeof (s.va_args)); 643276415Sdelphij# endif /* WIN32 */ 644276415Sdelphij# endif /* __va_copy */ 645186690Sobrien#endif /* va_copy */ 646186690Sobrien s.maxlen = (size_t)INT_MAX; 647186690Sobrien 648186690Sobrien retval = core(&s); 649186690Sobrien va_end(s.vargs); 650186690Sobrien if (retval == EOF) { 651186690Sobrien *ptr = NULL; 652186690Sobrien return EOF; 653186690Sobrien } 654186690Sobrien 655186690Sobrien *ptr = s.buffer_base; 656186690Sobrien return retval; 657186690Sobrien} 658