155682Smarkm/* 2120945Snectar * Copyright (c) 1995-2003 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#ifdef HAVE_CONFIG_H 3555682Smarkm#include <config.h> 36178825SdfrRCSID("$Id: snprintf.c 21005 2007-06-08 01:54:35Z lha $"); 3755682Smarkm#endif 38178825Sdfr#if defined(TEST_SNPRINTF) 39178825Sdfr#include "snprintf-test.h" 40178825Sdfr#endif /* TEST_SNPRINTF */ 4155682Smarkm#include <stdio.h> 4255682Smarkm#include <stdarg.h> 4355682Smarkm#include <stdlib.h> 4455682Smarkm#include <string.h> 4555682Smarkm#include <ctype.h> 46178825Sdfr#include "roken.h" 47178825Sdfr#include <assert.h> 4855682Smarkm 4955682Smarkmenum format_flags { 5055682Smarkm minus_flag = 1, 5155682Smarkm plus_flag = 2, 5255682Smarkm space_flag = 4, 5355682Smarkm alternate_flag = 8, 5455682Smarkm zero_flag = 16 5555682Smarkm}; 5655682Smarkm 5755682Smarkm/* 5855682Smarkm * Common state 5955682Smarkm */ 6055682Smarkm 6190926Snectarstruct snprintf_state { 62178825Sdfr unsigned char *str; 63178825Sdfr unsigned char *s; 64178825Sdfr unsigned char *theend; 65178825Sdfr size_t sz; 66178825Sdfr size_t max_sz; 67178825Sdfr void (*append_char)(struct snprintf_state *, unsigned char); 68178825Sdfr /* XXX - methods */ 6955682Smarkm}; 7055682Smarkm 7190926Snectar#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) 7255682Smarkmstatic int 7390926Snectarsn_reserve (struct snprintf_state *state, size_t n) 7455682Smarkm{ 75178825Sdfr return state->s + n > state->theend; 7655682Smarkm} 7755682Smarkm 7890926Snectarstatic void 7990926Snectarsn_append_char (struct snprintf_state *state, unsigned char c) 8055682Smarkm{ 81178825Sdfr if (!sn_reserve (state, 1)) 82178825Sdfr *state->s++ = c; 8355682Smarkm} 8455682Smarkm#endif 8555682Smarkm 8655682Smarkmstatic int 8790926Snectaras_reserve (struct snprintf_state *state, size_t n) 8855682Smarkm{ 89178825Sdfr if (state->s + n > state->theend) { 90178825Sdfr int off = state->s - state->str; 91178825Sdfr unsigned char *tmp; 9255682Smarkm 93178825Sdfr if (state->max_sz && state->sz >= state->max_sz) 94178825Sdfr return 1; 9555682Smarkm 96178825Sdfr state->sz = max(state->sz * 2, state->sz + n); 97178825Sdfr if (state->max_sz) 98178825Sdfr state->sz = min(state->sz, state->max_sz); 99178825Sdfr tmp = realloc (state->str, state->sz); 100178825Sdfr if (tmp == NULL) 101178825Sdfr return 1; 102178825Sdfr state->str = tmp; 103178825Sdfr state->s = state->str + off; 104178825Sdfr state->theend = state->str + state->sz - 1; 105178825Sdfr } 106178825Sdfr return 0; 10755682Smarkm} 10855682Smarkm 10990926Snectarstatic void 11090926Snectaras_append_char (struct snprintf_state *state, unsigned char c) 11155682Smarkm{ 112178825Sdfr if(!as_reserve (state, 1)) 113178825Sdfr *state->s++ = c; 11455682Smarkm} 11555682Smarkm 11690926Snectar/* longest integer types */ 11790926Snectar 11890926Snectar#ifdef HAVE_LONG_LONG 11990926Snectartypedef unsigned long long u_longest; 12090926Snectartypedef long long longest; 12190926Snectar#else 12290926Snectartypedef unsigned long u_longest; 12390926Snectartypedef long longest; 12490926Snectar#endif 12590926Snectar 12690926Snectar 127178825Sdfr 12855682Smarkmstatic int 129178825Sdfrpad(struct snprintf_state *state, int width, char c) 130178825Sdfr{ 131178825Sdfr int len = 0; 132178825Sdfr while(width-- > 0){ 133178825Sdfr (*state->append_char)(state, c); 134178825Sdfr ++len; 135178825Sdfr } 136178825Sdfr return len; 137178825Sdfr} 138178825Sdfr 139178825Sdfr/* return true if we should use alternatve hex form */ 140178825Sdfrstatic int 14190926Snectaruse_alternative (int flags, u_longest num, unsigned base) 14290926Snectar{ 143178825Sdfr return (flags & alternate_flag) && base == 16 && num != 0; 14490926Snectar} 14590926Snectar 14690926Snectarstatic int 14790926Snectarappend_number(struct snprintf_state *state, 148102644Snectar u_longest num, unsigned base, const char *rep, 14955682Smarkm int width, int prec, int flags, int minusp) 15055682Smarkm{ 151178825Sdfr int len = 0; 152178825Sdfr u_longest n = num; 153178825Sdfr char nstr[64]; /* enough for <192 bit octal integers */ 154178825Sdfr int nstart, nlen; 155178825Sdfr char signchar; 15655682Smarkm 157178825Sdfr /* given precision, ignore zero flag */ 158178825Sdfr if(prec != -1) 159178825Sdfr flags &= ~zero_flag; 160178825Sdfr else 161178825Sdfr prec = 1; 162178825Sdfr 163178825Sdfr /* format number as string */ 164178825Sdfr nstart = sizeof(nstr); 165178825Sdfr nlen = 0; 166178825Sdfr nstr[--nstart] = '\0'; 167178825Sdfr do { 168178825Sdfr assert(nstart > 0); 169178825Sdfr nstr[--nstart] = rep[n % base]; 170178825Sdfr ++nlen; 171178825Sdfr n /= base; 172178825Sdfr } while(n); 173178825Sdfr 174178825Sdfr /* zero value with zero precision should produce no digits */ 175178825Sdfr if(prec == 0 && num == 0) { 176178825Sdfr nlen--; 177178825Sdfr nstart++; 17855682Smarkm } 179178825Sdfr 180178825Sdfr /* figure out what char to use for sign */ 181178825Sdfr if(minusp) 182178825Sdfr signchar = '-'; 183178825Sdfr else if((flags & plus_flag)) 184178825Sdfr signchar = '+'; 185178825Sdfr else if((flags & space_flag)) 186178825Sdfr signchar = ' '; 187178825Sdfr else 188178825Sdfr signchar = '\0'; 189178825Sdfr 190178825Sdfr if((flags & alternate_flag) && base == 8) { 191178825Sdfr /* if necessary, increase the precision to 192178825Sdfr make first digit a zero */ 193178825Sdfr 194178825Sdfr /* XXX C99 claims (regarding # and %o) that "if the value and 195178825Sdfr precision are both 0, a single 0 is printed", but there is 196178825Sdfr no such wording for %x. This would mean that %#.o would 197178825Sdfr output "0", but %#.x "". This does not make sense, and is 198178825Sdfr also not what other printf implementations are doing. */ 199178825Sdfr 200178825Sdfr if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0') 201178825Sdfr prec = nlen + 1; 20255682Smarkm } 203178825Sdfr 204178825Sdfr /* possible formats: 205178825Sdfr pad | sign | alt | zero | digits 206178825Sdfr sign | alt | zero | digits | pad minus_flag 207178825Sdfr sign | alt | zero | digits zero_flag */ 208178825Sdfr 209178825Sdfr /* if not right justifying or padding with zeros, we need to 210178825Sdfr compute the length of the rest of the string, and then pad with 211178825Sdfr spaces */ 212178825Sdfr if(!(flags & (minus_flag | zero_flag))) { 213178825Sdfr if(prec > nlen) 214178825Sdfr width -= prec; 215178825Sdfr else 216178825Sdfr width -= nlen; 217178825Sdfr 218178825Sdfr if(use_alternative(flags, num, base)) 219178825Sdfr width -= 2; 220178825Sdfr 221178825Sdfr if(signchar != '\0') 222178825Sdfr width--; 223178825Sdfr 224178825Sdfr /* pad to width */ 225178825Sdfr len += pad(state, width, ' '); 22655682Smarkm } 227178825Sdfr if(signchar != '\0') { 228178825Sdfr (*state->append_char)(state, signchar); 229178825Sdfr ++len; 230178825Sdfr } 231178825Sdfr if(use_alternative(flags, num, base)) { 232178825Sdfr (*state->append_char)(state, '0'); 233178825Sdfr (*state->append_char)(state, rep[10] + 23); /* XXX */ 234178825Sdfr len += 2; 235178825Sdfr } 236178825Sdfr if(flags & zero_flag) { 237178825Sdfr /* pad to width with zeros */ 238178825Sdfr if(prec - nlen > width - len - nlen) 239178825Sdfr len += pad(state, prec - nlen, '0'); 240178825Sdfr else 241178825Sdfr len += pad(state, width - len - nlen, '0'); 242178825Sdfr } else 243178825Sdfr /* pad to prec with zeros */ 244178825Sdfr len += pad(state, prec - nlen, '0'); 245178825Sdfr 246178825Sdfr while(nstr[nstart] != '\0') { 247178825Sdfr (*state->append_char)(state, nstr[nstart++]); 248178825Sdfr ++len; 249178825Sdfr } 250178825Sdfr 251178825Sdfr if(flags & minus_flag) 252178825Sdfr len += pad(state, width - len, ' '); 253178825Sdfr 254178825Sdfr return len; 25555682Smarkm} 25655682Smarkm 25790926Snectar/* 25890926Snectar * return length 25990926Snectar */ 26090926Snectar 26155682Smarkmstatic int 26290926Snectarappend_string (struct snprintf_state *state, 26390926Snectar const unsigned char *arg, 26455682Smarkm int width, 26555682Smarkm int prec, 26655682Smarkm int flags) 26755682Smarkm{ 26890926Snectar int len = 0; 26990926Snectar 27072445Sassar if(arg == NULL) 27190926Snectar arg = (const unsigned char*)"(null)"; 27272445Sassar 27372445Sassar if(prec != -1) 27472445Sassar width -= prec; 27572445Sassar else 27690926Snectar width -= strlen((const char *)arg); 27772445Sassar if(!(flags & minus_flag)) 278178825Sdfr len += pad(state, width, ' '); 279178825Sdfr 28072445Sassar if (prec != -1) { 28190926Snectar while (*arg && prec--) { 28290926Snectar (*state->append_char) (state, *arg++); 28390926Snectar ++len; 28490926Snectar } 28572445Sassar } else { 28690926Snectar while (*arg) { 28790926Snectar (*state->append_char) (state, *arg++); 28890926Snectar ++len; 28990926Snectar } 29072445Sassar } 29172445Sassar if(flags & minus_flag) 292178825Sdfr len += pad(state, width, ' '); 29390926Snectar return len; 29455682Smarkm} 29555682Smarkm 29655682Smarkmstatic int 29790926Snectarappend_char(struct snprintf_state *state, 29855682Smarkm unsigned char arg, 29955682Smarkm int width, 30055682Smarkm int flags) 30155682Smarkm{ 302178825Sdfr int len = 0; 30390926Snectar 304178825Sdfr while(!(flags & minus_flag) && --width > 0) { 305178825Sdfr (*state->append_char) (state, ' ') ; 306178825Sdfr ++len; 307178825Sdfr } 308178825Sdfr (*state->append_char) (state, arg); 30990926Snectar ++len; 310178825Sdfr while((flags & minus_flag) && --width > 0) { 311178825Sdfr (*state->append_char) (state, ' '); 312178825Sdfr ++len; 313178825Sdfr } 314178825Sdfr return 0; 31555682Smarkm} 31655682Smarkm 31755682Smarkm/* 31855682Smarkm * This can't be made into a function... 31955682Smarkm */ 32055682Smarkm 32190926Snectar#ifdef HAVE_LONG_LONG 32290926Snectar 32355682Smarkm#define PARSE_INT_FORMAT(res, arg, unsig) \ 32490926Snectarif (long_long_flag) \ 32590926Snectar res = (unsig long long)va_arg(arg, unsig long long); \ 32690926Snectarelse if (long_flag) \ 32790926Snectar res = (unsig long)va_arg(arg, unsig long); \ 328178825Sdfrelse if (size_t_flag) \ 329178825Sdfr res = (unsig long)va_arg(arg, size_t); \ 33090926Snectarelse if (short_flag) \ 33190926Snectar res = (unsig short)va_arg(arg, unsig int); \ 33290926Snectarelse \ 33390926Snectar res = (unsig int)va_arg(arg, unsig int) 33490926Snectar 33590926Snectar#else 33690926Snectar 33790926Snectar#define PARSE_INT_FORMAT(res, arg, unsig) \ 33855682Smarkmif (long_flag) \ 33955682Smarkm res = (unsig long)va_arg(arg, unsig long); \ 340178825Sdfrelse if (size_t_flag) \ 341178825Sdfr res = (unsig long)va_arg(arg, size_t); \ 34255682Smarkmelse if (short_flag) \ 34357422Smarkm res = (unsig short)va_arg(arg, unsig int); \ 34455682Smarkmelse \ 34555682Smarkm res = (unsig int)va_arg(arg, unsig int) 34655682Smarkm 34790926Snectar#endif 34890926Snectar 34955682Smarkm/* 35090926Snectar * zyxprintf - return length, as snprintf 35155682Smarkm */ 35255682Smarkm 35355682Smarkmstatic int 35490926Snectarxyzprintf (struct snprintf_state *state, const char *char_format, va_list ap) 35555682Smarkm{ 356178825Sdfr const unsigned char *format = (const unsigned char *)char_format; 357178825Sdfr unsigned char c; 358178825Sdfr int len = 0; 35955682Smarkm 360178825Sdfr while((c = *format++)) { 361178825Sdfr if (c == '%') { 362178825Sdfr int flags = 0; 363178825Sdfr int width = 0; 364178825Sdfr int prec = -1; 365178825Sdfr int size_t_flag = 0; 366178825Sdfr int long_long_flag = 0; 367178825Sdfr int long_flag = 0; 368178825Sdfr int short_flag = 0; 36955682Smarkm 370178825Sdfr /* flags */ 371178825Sdfr while((c = *format++)){ 372178825Sdfr if(c == '-') 373178825Sdfr flags |= minus_flag; 374178825Sdfr else if(c == '+') 375178825Sdfr flags |= plus_flag; 376178825Sdfr else if(c == ' ') 377178825Sdfr flags |= space_flag; 378178825Sdfr else if(c == '#') 379178825Sdfr flags |= alternate_flag; 380178825Sdfr else if(c == '0') 381178825Sdfr flags |= zero_flag; 382178825Sdfr else if(c == '\'') 383178825Sdfr ; /* just ignore */ 384178825Sdfr else 385178825Sdfr break; 386178825Sdfr } 38755682Smarkm 388178825Sdfr if((flags & space_flag) && (flags & plus_flag)) 389178825Sdfr flags ^= space_flag; 39055682Smarkm 391178825Sdfr if((flags & minus_flag) && (flags & zero_flag)) 392178825Sdfr flags ^= zero_flag; 39355682Smarkm 394178825Sdfr /* width */ 395178825Sdfr if (isdigit(c)) 396178825Sdfr do { 397178825Sdfr width = width * 10 + c - '0'; 398178825Sdfr c = *format++; 399178825Sdfr } while(isdigit(c)); 400178825Sdfr else if(c == '*') { 401178825Sdfr width = va_arg(ap, int); 402178825Sdfr c = *format++; 403178825Sdfr } 40455682Smarkm 405178825Sdfr /* precision */ 406178825Sdfr if (c == '.') { 407178825Sdfr prec = 0; 408178825Sdfr c = *format++; 409178825Sdfr if (isdigit(c)) 410178825Sdfr do { 411178825Sdfr prec = prec * 10 + c - '0'; 412178825Sdfr c = *format++; 413178825Sdfr } while(isdigit(c)); 414178825Sdfr else if (c == '*') { 415178825Sdfr prec = va_arg(ap, int); 416178825Sdfr c = *format++; 417178825Sdfr } 418178825Sdfr } 41955682Smarkm 420178825Sdfr /* size */ 42155682Smarkm 422178825Sdfr if (c == 'h') { 423178825Sdfr short_flag = 1; 424178825Sdfr c = *format++; 425178825Sdfr } else if (c == 'z') { 426178825Sdfr size_t_flag = 1; 427178825Sdfr c = *format++; 428178825Sdfr } else if (c == 'l') { 429178825Sdfr long_flag = 1; 430178825Sdfr c = *format++; 431178825Sdfr if (c == 'l') { 432178825Sdfr long_long_flag = 1; 433178825Sdfr c = *format++; 434178825Sdfr } 435178825Sdfr } 43655682Smarkm 437178825Sdfr if(c != 'd' && c != 'i') 438178825Sdfr flags &= ~(plus_flag | space_flag); 43955682Smarkm 440178825Sdfr switch (c) { 441178825Sdfr case 'c' : 442178825Sdfr append_char(state, va_arg(ap, int), width, flags); 443178825Sdfr ++len; 444178825Sdfr break; 445178825Sdfr case 's' : 446178825Sdfr len += append_string(state, 447178825Sdfr va_arg(ap, unsigned char*), 448178825Sdfr width, 449178825Sdfr prec, 450178825Sdfr flags); 451178825Sdfr break; 452178825Sdfr case 'd' : 453178825Sdfr case 'i' : { 454178825Sdfr longest arg; 455178825Sdfr u_longest num; 456178825Sdfr int minusp = 0; 45755682Smarkm 458178825Sdfr PARSE_INT_FORMAT(arg, ap, signed); 45955682Smarkm 460178825Sdfr if (arg < 0) { 461178825Sdfr minusp = 1; 462178825Sdfr num = -arg; 463178825Sdfr } else 464178825Sdfr num = arg; 46555682Smarkm 466178825Sdfr len += append_number (state, num, 10, "0123456789", 467178825Sdfr width, prec, flags, minusp); 468178825Sdfr break; 469178825Sdfr } 470178825Sdfr case 'u' : { 471178825Sdfr u_longest arg; 47255682Smarkm 473178825Sdfr PARSE_INT_FORMAT(arg, ap, unsigned); 47455682Smarkm 475178825Sdfr len += append_number (state, arg, 10, "0123456789", 476178825Sdfr width, prec, flags, 0); 477178825Sdfr break; 478178825Sdfr } 479178825Sdfr case 'o' : { 480178825Sdfr u_longest arg; 48155682Smarkm 482178825Sdfr PARSE_INT_FORMAT(arg, ap, unsigned); 48355682Smarkm 484178825Sdfr len += append_number (state, arg, 010, "01234567", 485178825Sdfr width, prec, flags, 0); 486178825Sdfr break; 487178825Sdfr } 488178825Sdfr case 'x' : { 489178825Sdfr u_longest arg; 49055682Smarkm 491178825Sdfr PARSE_INT_FORMAT(arg, ap, unsigned); 49255682Smarkm 493178825Sdfr len += append_number (state, arg, 0x10, "0123456789abcdef", 494178825Sdfr width, prec, flags, 0); 495178825Sdfr break; 496178825Sdfr } 497178825Sdfr case 'X' :{ 498178825Sdfr u_longest arg; 49955682Smarkm 500178825Sdfr PARSE_INT_FORMAT(arg, ap, unsigned); 50155682Smarkm 502178825Sdfr len += append_number (state, arg, 0x10, "0123456789ABCDEF", 503178825Sdfr width, prec, flags, 0); 504178825Sdfr break; 505178825Sdfr } 506178825Sdfr case 'p' : { 507178825Sdfr unsigned long arg = (unsigned long)va_arg(ap, void*); 508178825Sdfr 509178825Sdfr len += append_number (state, arg, 0x10, "0123456789ABCDEF", 510178825Sdfr width, prec, flags, 0); 511178825Sdfr break; 512178825Sdfr } 513178825Sdfr case 'n' : { 514178825Sdfr int *arg = va_arg(ap, int*); 515178825Sdfr *arg = state->s - state->str; 516178825Sdfr break; 517178825Sdfr } 518178825Sdfr case '\0' : 519178825Sdfr --format; 520178825Sdfr /* FALLTHROUGH */ 521178825Sdfr case '%' : 522178825Sdfr (*state->append_char)(state, c); 523178825Sdfr ++len; 524178825Sdfr break; 525178825Sdfr default : 526178825Sdfr (*state->append_char)(state, '%'); 527178825Sdfr (*state->append_char)(state, c); 528178825Sdfr len += 2; 529178825Sdfr break; 530178825Sdfr } 531178825Sdfr } else { 532178825Sdfr (*state->append_char) (state, c); 533178825Sdfr ++len; 534178825Sdfr } 53590926Snectar } 536178825Sdfr return len; 53755682Smarkm} 53855682Smarkm 53990926Snectar#if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF) 540178825Sdfrint ROKEN_LIB_FUNCTION 54155682Smarkmsnprintf (char *str, size_t sz, const char *format, ...) 54255682Smarkm{ 543178825Sdfr va_list args; 544178825Sdfr int ret; 54555682Smarkm 546178825Sdfr va_start(args, format); 547178825Sdfr ret = vsnprintf (str, sz, format, args); 548178825Sdfr va_end(args); 54955682Smarkm 55055682Smarkm#ifdef PARANOIA 551178825Sdfr { 552178825Sdfr int ret2; 553178825Sdfr char *tmp; 55455682Smarkm 555178825Sdfr tmp = malloc (sz); 556178825Sdfr if (tmp == NULL) 557178825Sdfr abort (); 55855682Smarkm 559178825Sdfr va_start(args, format); 560178825Sdfr ret2 = vsprintf (tmp, format, args); 561178825Sdfr va_end(args); 562178825Sdfr if (ret != ret2 || strcmp(str, tmp)) 563178825Sdfr abort (); 564178825Sdfr free (tmp); 565178825Sdfr } 56655682Smarkm#endif 56755682Smarkm 568178825Sdfr return ret; 56955682Smarkm} 57055682Smarkm#endif 57155682Smarkm 57290926Snectar#if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF) 573178825Sdfrint ROKEN_LIB_FUNCTION 57455682Smarkmasprintf (char **ret, const char *format, ...) 57555682Smarkm{ 576178825Sdfr va_list args; 577178825Sdfr int val; 57855682Smarkm 579178825Sdfr va_start(args, format); 580178825Sdfr val = vasprintf (ret, format, args); 581178825Sdfr va_end(args); 58255682Smarkm 58355682Smarkm#ifdef PARANOIA 584178825Sdfr { 585178825Sdfr int ret2; 586178825Sdfr char *tmp; 587178825Sdfr tmp = malloc (val + 1); 588178825Sdfr if (tmp == NULL) 589178825Sdfr abort (); 59055682Smarkm 591178825Sdfr va_start(args, format); 592178825Sdfr ret2 = vsprintf (tmp, format, args); 593178825Sdfr va_end(args); 594178825Sdfr if (val != ret2 || strcmp(*ret, tmp)) 595178825Sdfr abort (); 596178825Sdfr free (tmp); 597178825Sdfr } 59855682Smarkm#endif 59955682Smarkm 600178825Sdfr return val; 60155682Smarkm} 60255682Smarkm#endif 60355682Smarkm 60490926Snectar#if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF) 605178825Sdfrint ROKEN_LIB_FUNCTION 60655682Smarkmasnprintf (char **ret, size_t max_sz, const char *format, ...) 60755682Smarkm{ 608178825Sdfr va_list args; 609178825Sdfr int val; 61055682Smarkm 611178825Sdfr va_start(args, format); 612178825Sdfr val = vasnprintf (ret, max_sz, format, args); 61355682Smarkm 61455682Smarkm#ifdef PARANOIA 615178825Sdfr { 616178825Sdfr int ret2; 617178825Sdfr char *tmp; 618178825Sdfr tmp = malloc (val + 1); 619178825Sdfr if (tmp == NULL) 620178825Sdfr abort (); 62155682Smarkm 622178825Sdfr ret2 = vsprintf (tmp, format, args); 623178825Sdfr if (val != ret2 || strcmp(*ret, tmp)) 624178825Sdfr abort (); 625178825Sdfr free (tmp); 626178825Sdfr } 62755682Smarkm#endif 62855682Smarkm 629178825Sdfr va_end(args); 630178825Sdfr return val; 63155682Smarkm} 63255682Smarkm#endif 63355682Smarkm 63490926Snectar#if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF) 635178825Sdfrint ROKEN_LIB_FUNCTION 63655682Smarkmvasprintf (char **ret, const char *format, va_list args) 63755682Smarkm{ 638178825Sdfr return vasnprintf (ret, 0, format, args); 63955682Smarkm} 64055682Smarkm#endif 64155682Smarkm 64255682Smarkm 64390926Snectar#if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF) 644178825Sdfrint ROKEN_LIB_FUNCTION 64555682Smarkmvasnprintf (char **ret, size_t max_sz, const char *format, va_list args) 64655682Smarkm{ 647178825Sdfr int st; 648178825Sdfr struct snprintf_state state; 64955682Smarkm 650178825Sdfr state.max_sz = max_sz; 651178825Sdfr state.sz = 1; 652178825Sdfr state.str = malloc(state.sz); 653178825Sdfr if (state.str == NULL) { 654178825Sdfr *ret = NULL; 655178825Sdfr return -1; 656178825Sdfr } 657178825Sdfr state.s = state.str; 658178825Sdfr state.theend = state.s + state.sz - 1; 659178825Sdfr state.append_char = as_append_char; 66055682Smarkm 661178825Sdfr st = xyzprintf (&state, format, args); 662178825Sdfr if (st > state.sz) { 663178825Sdfr free (state.str); 664178825Sdfr *ret = NULL; 665178825Sdfr return -1; 666178825Sdfr } else { 667178825Sdfr char *tmp; 66855682Smarkm 669178825Sdfr *state.s = '\0'; 670178825Sdfr tmp = realloc (state.str, st+1); 671178825Sdfr if (tmp == NULL) { 672178825Sdfr free (state.str); 673178825Sdfr *ret = NULL; 674178825Sdfr return -1; 675178825Sdfr } 676178825Sdfr *ret = tmp; 677178825Sdfr return st; 67855682Smarkm } 67955682Smarkm} 68055682Smarkm#endif 68155682Smarkm 68290926Snectar#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) 683178825Sdfrint ROKEN_LIB_FUNCTION 68455682Smarkmvsnprintf (char *str, size_t sz, const char *format, va_list args) 68555682Smarkm{ 686178825Sdfr struct snprintf_state state; 687178825Sdfr int ret; 688178825Sdfr unsigned char *ustr = (unsigned char *)str; 68955682Smarkm 690178825Sdfr state.max_sz = 0; 691178825Sdfr state.sz = sz; 692178825Sdfr state.str = ustr; 693178825Sdfr state.s = ustr; 694178825Sdfr state.theend = ustr + sz - (sz > 0); 695178825Sdfr state.append_char = sn_append_char; 69655682Smarkm 697178825Sdfr ret = xyzprintf (&state, format, args); 698178825Sdfr if (state.s != NULL && sz != 0) 699178825Sdfr *state.s = '\0'; 700178825Sdfr return ret; 70155682Smarkm} 70255682Smarkm#endif 703