155682Smarkm/* 2233294Sstas * Copyright (c) 1995-2003 Kungliga Tekniska H��gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 5233294Sstas * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 9233294Sstas * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 12233294Sstas * 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. 16233294Sstas * 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. 20233294Sstas * 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#include <config.h> 3555682Smarkm#include <stdio.h> 3655682Smarkm#include <stdarg.h> 3755682Smarkm#include <stdlib.h> 3855682Smarkm#include <string.h> 3955682Smarkm#include <ctype.h> 40178825Sdfr#include "roken.h" 41178825Sdfr#include <assert.h> 4255682Smarkm 4355682Smarkmenum format_flags { 4455682Smarkm minus_flag = 1, 4555682Smarkm plus_flag = 2, 4655682Smarkm space_flag = 4, 4755682Smarkm alternate_flag = 8, 4855682Smarkm zero_flag = 16 4955682Smarkm}; 5055682Smarkm 5155682Smarkm/* 5255682Smarkm * Common state 5355682Smarkm */ 5455682Smarkm 5590926Snectarstruct snprintf_state { 56178825Sdfr unsigned char *str; 57178825Sdfr unsigned char *s; 58178825Sdfr unsigned char *theend; 59178825Sdfr size_t sz; 60178825Sdfr size_t max_sz; 61178825Sdfr void (*append_char)(struct snprintf_state *, unsigned char); 62178825Sdfr /* XXX - methods */ 6355682Smarkm}; 6455682Smarkm 6590926Snectar#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) 6655682Smarkmstatic int 6790926Snectarsn_reserve (struct snprintf_state *state, size_t n) 6855682Smarkm{ 69178825Sdfr return state->s + n > state->theend; 7055682Smarkm} 7155682Smarkm 7290926Snectarstatic void 7390926Snectarsn_append_char (struct snprintf_state *state, unsigned char c) 7455682Smarkm{ 75178825Sdfr if (!sn_reserve (state, 1)) 76178825Sdfr *state->s++ = c; 7755682Smarkm} 7855682Smarkm#endif 7955682Smarkm 8055682Smarkmstatic int 8190926Snectaras_reserve (struct snprintf_state *state, size_t n) 8255682Smarkm{ 83178825Sdfr if (state->s + n > state->theend) { 84178825Sdfr int off = state->s - state->str; 85178825Sdfr unsigned char *tmp; 8655682Smarkm 87178825Sdfr if (state->max_sz && state->sz >= state->max_sz) 88178825Sdfr return 1; 8955682Smarkm 90178825Sdfr state->sz = max(state->sz * 2, state->sz + n); 91178825Sdfr if (state->max_sz) 92178825Sdfr state->sz = min(state->sz, state->max_sz); 93178825Sdfr tmp = realloc (state->str, state->sz); 94178825Sdfr if (tmp == NULL) 95178825Sdfr return 1; 96178825Sdfr state->str = tmp; 97178825Sdfr state->s = state->str + off; 98178825Sdfr state->theend = state->str + state->sz - 1; 99178825Sdfr } 100178825Sdfr return 0; 10155682Smarkm} 10255682Smarkm 10390926Snectarstatic void 10490926Snectaras_append_char (struct snprintf_state *state, unsigned char c) 10555682Smarkm{ 106178825Sdfr if(!as_reserve (state, 1)) 107178825Sdfr *state->s++ = c; 10855682Smarkm} 10955682Smarkm 11090926Snectar/* longest integer types */ 11190926Snectar 11290926Snectar#ifdef HAVE_LONG_LONG 11390926Snectartypedef unsigned long long u_longest; 11490926Snectartypedef long long longest; 11590926Snectar#else 11690926Snectartypedef unsigned long u_longest; 11790926Snectartypedef long longest; 11890926Snectar#endif 11990926Snectar 12090926Snectar 121178825Sdfr 122233294Sstasstatic size_t 123178825Sdfrpad(struct snprintf_state *state, int width, char c) 124178825Sdfr{ 125233294Sstas size_t len = 0; 126178825Sdfr while(width-- > 0){ 127178825Sdfr (*state->append_char)(state, c); 128178825Sdfr ++len; 129178825Sdfr } 130178825Sdfr return len; 131178825Sdfr} 132178825Sdfr 133178825Sdfr/* return true if we should use alternatve hex form */ 134178825Sdfrstatic int 13590926Snectaruse_alternative (int flags, u_longest num, unsigned base) 13690926Snectar{ 137178825Sdfr return (flags & alternate_flag) && base == 16 && num != 0; 13890926Snectar} 13990926Snectar 14090926Snectarstatic int 14190926Snectarappend_number(struct snprintf_state *state, 142102644Snectar u_longest num, unsigned base, const char *rep, 14355682Smarkm int width, int prec, int flags, int minusp) 14455682Smarkm{ 145178825Sdfr int len = 0; 146178825Sdfr u_longest n = num; 147178825Sdfr char nstr[64]; /* enough for <192 bit octal integers */ 148178825Sdfr int nstart, nlen; 149178825Sdfr char signchar; 15055682Smarkm 151178825Sdfr /* given precision, ignore zero flag */ 152178825Sdfr if(prec != -1) 153178825Sdfr flags &= ~zero_flag; 154178825Sdfr else 155178825Sdfr prec = 1; 156178825Sdfr 157178825Sdfr /* format number as string */ 158178825Sdfr nstart = sizeof(nstr); 159178825Sdfr nlen = 0; 160178825Sdfr nstr[--nstart] = '\0'; 161178825Sdfr do { 162178825Sdfr assert(nstart > 0); 163178825Sdfr nstr[--nstart] = rep[n % base]; 164178825Sdfr ++nlen; 165178825Sdfr n /= base; 166178825Sdfr } while(n); 167178825Sdfr 168178825Sdfr /* zero value with zero precision should produce no digits */ 169178825Sdfr if(prec == 0 && num == 0) { 170178825Sdfr nlen--; 171178825Sdfr nstart++; 17255682Smarkm } 173178825Sdfr 174178825Sdfr /* figure out what char to use for sign */ 175178825Sdfr if(minusp) 176178825Sdfr signchar = '-'; 177178825Sdfr else if((flags & plus_flag)) 178178825Sdfr signchar = '+'; 179178825Sdfr else if((flags & space_flag)) 180178825Sdfr signchar = ' '; 181178825Sdfr else 182178825Sdfr signchar = '\0'; 183233294Sstas 184178825Sdfr if((flags & alternate_flag) && base == 8) { 185233294Sstas /* if necessary, increase the precision to 186178825Sdfr make first digit a zero */ 187178825Sdfr 188178825Sdfr /* XXX C99 claims (regarding # and %o) that "if the value and 189178825Sdfr precision are both 0, a single 0 is printed", but there is 190178825Sdfr no such wording for %x. This would mean that %#.o would 191178825Sdfr output "0", but %#.x "". This does not make sense, and is 192178825Sdfr also not what other printf implementations are doing. */ 193233294Sstas 194178825Sdfr if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0') 195178825Sdfr prec = nlen + 1; 19655682Smarkm } 197178825Sdfr 198178825Sdfr /* possible formats: 199178825Sdfr pad | sign | alt | zero | digits 200178825Sdfr sign | alt | zero | digits | pad minus_flag 201178825Sdfr sign | alt | zero | digits zero_flag */ 202178825Sdfr 203178825Sdfr /* if not right justifying or padding with zeros, we need to 204178825Sdfr compute the length of the rest of the string, and then pad with 205178825Sdfr spaces */ 206178825Sdfr if(!(flags & (minus_flag | zero_flag))) { 207178825Sdfr if(prec > nlen) 208178825Sdfr width -= prec; 209178825Sdfr else 210178825Sdfr width -= nlen; 211233294Sstas 212178825Sdfr if(use_alternative(flags, num, base)) 213178825Sdfr width -= 2; 214233294Sstas 215178825Sdfr if(signchar != '\0') 216178825Sdfr width--; 217233294Sstas 218178825Sdfr /* pad to width */ 219178825Sdfr len += pad(state, width, ' '); 22055682Smarkm } 221178825Sdfr if(signchar != '\0') { 222178825Sdfr (*state->append_char)(state, signchar); 223178825Sdfr ++len; 224178825Sdfr } 225178825Sdfr if(use_alternative(flags, num, base)) { 226178825Sdfr (*state->append_char)(state, '0'); 227178825Sdfr (*state->append_char)(state, rep[10] + 23); /* XXX */ 228178825Sdfr len += 2; 229178825Sdfr } 230178825Sdfr if(flags & zero_flag) { 231178825Sdfr /* pad to width with zeros */ 232178825Sdfr if(prec - nlen > width - len - nlen) 233178825Sdfr len += pad(state, prec - nlen, '0'); 234178825Sdfr else 235178825Sdfr len += pad(state, width - len - nlen, '0'); 236178825Sdfr } else 237178825Sdfr /* pad to prec with zeros */ 238178825Sdfr len += pad(state, prec - nlen, '0'); 239233294Sstas 240178825Sdfr while(nstr[nstart] != '\0') { 241178825Sdfr (*state->append_char)(state, nstr[nstart++]); 242178825Sdfr ++len; 243178825Sdfr } 244233294Sstas 245178825Sdfr if(flags & minus_flag) 246178825Sdfr len += pad(state, width - len, ' '); 247178825Sdfr 248178825Sdfr return len; 24955682Smarkm} 25055682Smarkm 25190926Snectar/* 25290926Snectar * return length 25390926Snectar */ 25490926Snectar 255233294Sstasstatic size_t 25690926Snectarappend_string (struct snprintf_state *state, 25790926Snectar const unsigned char *arg, 25855682Smarkm int width, 25955682Smarkm int prec, 26055682Smarkm int flags) 26155682Smarkm{ 262233294Sstas size_t len = 0; 26390926Snectar 26472445Sassar if(arg == NULL) 26590926Snectar arg = (const unsigned char*)"(null)"; 26672445Sassar 26772445Sassar if(prec != -1) 26872445Sassar width -= prec; 26972445Sassar else 27090926Snectar width -= strlen((const char *)arg); 27172445Sassar if(!(flags & minus_flag)) 272178825Sdfr len += pad(state, width, ' '); 273178825Sdfr 27472445Sassar if (prec != -1) { 27590926Snectar while (*arg && prec--) { 27690926Snectar (*state->append_char) (state, *arg++); 27790926Snectar ++len; 27890926Snectar } 27972445Sassar } else { 28090926Snectar while (*arg) { 28190926Snectar (*state->append_char) (state, *arg++); 28290926Snectar ++len; 28390926Snectar } 28472445Sassar } 28572445Sassar if(flags & minus_flag) 286178825Sdfr len += pad(state, width, ' '); 28790926Snectar return len; 28855682Smarkm} 28955682Smarkm 29055682Smarkmstatic int 29190926Snectarappend_char(struct snprintf_state *state, 29255682Smarkm unsigned char arg, 29355682Smarkm int width, 29455682Smarkm int flags) 29555682Smarkm{ 296178825Sdfr int len = 0; 29790926Snectar 298178825Sdfr while(!(flags & minus_flag) && --width > 0) { 299178825Sdfr (*state->append_char) (state, ' ') ; 300178825Sdfr ++len; 301178825Sdfr } 302178825Sdfr (*state->append_char) (state, arg); 30390926Snectar ++len; 304178825Sdfr while((flags & minus_flag) && --width > 0) { 305178825Sdfr (*state->append_char) (state, ' '); 306178825Sdfr ++len; 307178825Sdfr } 308178825Sdfr return 0; 30955682Smarkm} 31055682Smarkm 31155682Smarkm/* 31255682Smarkm * This can't be made into a function... 31355682Smarkm */ 31455682Smarkm 31590926Snectar#ifdef HAVE_LONG_LONG 31690926Snectar 31755682Smarkm#define PARSE_INT_FORMAT(res, arg, unsig) \ 31890926Snectarif (long_long_flag) \ 31990926Snectar res = (unsig long long)va_arg(arg, unsig long long); \ 32090926Snectarelse if (long_flag) \ 32190926Snectar res = (unsig long)va_arg(arg, unsig long); \ 322178825Sdfrelse if (size_t_flag) \ 323178825Sdfr res = (unsig long)va_arg(arg, size_t); \ 32490926Snectarelse if (short_flag) \ 32590926Snectar res = (unsig short)va_arg(arg, unsig int); \ 32690926Snectarelse \ 32790926Snectar res = (unsig int)va_arg(arg, unsig int) 32890926Snectar 32990926Snectar#else 33090926Snectar 33190926Snectar#define PARSE_INT_FORMAT(res, arg, unsig) \ 33255682Smarkmif (long_flag) \ 33355682Smarkm res = (unsig long)va_arg(arg, unsig long); \ 334178825Sdfrelse if (size_t_flag) \ 335178825Sdfr res = (unsig long)va_arg(arg, size_t); \ 33655682Smarkmelse if (short_flag) \ 33757422Smarkm res = (unsig short)va_arg(arg, unsig int); \ 33855682Smarkmelse \ 33955682Smarkm res = (unsig int)va_arg(arg, unsig int) 34055682Smarkm 34190926Snectar#endif 34290926Snectar 34355682Smarkm/* 34490926Snectar * zyxprintf - return length, as snprintf 34555682Smarkm */ 34655682Smarkm 347233294Sstasstatic size_t 34890926Snectarxyzprintf (struct snprintf_state *state, const char *char_format, va_list ap) 34955682Smarkm{ 350178825Sdfr const unsigned char *format = (const unsigned char *)char_format; 351178825Sdfr unsigned char c; 352233294Sstas size_t len = 0; 35355682Smarkm 354178825Sdfr while((c = *format++)) { 355178825Sdfr if (c == '%') { 356178825Sdfr int flags = 0; 357178825Sdfr int width = 0; 358178825Sdfr int prec = -1; 359178825Sdfr int size_t_flag = 0; 360178825Sdfr int long_long_flag = 0; 361178825Sdfr int long_flag = 0; 362178825Sdfr int short_flag = 0; 36355682Smarkm 364178825Sdfr /* flags */ 365178825Sdfr while((c = *format++)){ 366178825Sdfr if(c == '-') 367178825Sdfr flags |= minus_flag; 368178825Sdfr else if(c == '+') 369178825Sdfr flags |= plus_flag; 370178825Sdfr else if(c == ' ') 371178825Sdfr flags |= space_flag; 372178825Sdfr else if(c == '#') 373178825Sdfr flags |= alternate_flag; 374178825Sdfr else if(c == '0') 375178825Sdfr flags |= zero_flag; 376178825Sdfr else if(c == '\'') 377178825Sdfr ; /* just ignore */ 378178825Sdfr else 379178825Sdfr break; 380178825Sdfr } 381233294Sstas 382178825Sdfr if((flags & space_flag) && (flags & plus_flag)) 383178825Sdfr flags ^= space_flag; 38455682Smarkm 385178825Sdfr if((flags & minus_flag) && (flags & zero_flag)) 386178825Sdfr flags ^= zero_flag; 38755682Smarkm 388178825Sdfr /* width */ 389178825Sdfr if (isdigit(c)) 390178825Sdfr do { 391178825Sdfr width = width * 10 + c - '0'; 392178825Sdfr c = *format++; 393178825Sdfr } while(isdigit(c)); 394178825Sdfr else if(c == '*') { 395178825Sdfr width = va_arg(ap, int); 396178825Sdfr c = *format++; 397178825Sdfr } 39855682Smarkm 399178825Sdfr /* precision */ 400178825Sdfr if (c == '.') { 401178825Sdfr prec = 0; 402178825Sdfr c = *format++; 403178825Sdfr if (isdigit(c)) 404178825Sdfr do { 405178825Sdfr prec = prec * 10 + c - '0'; 406178825Sdfr c = *format++; 407178825Sdfr } while(isdigit(c)); 408178825Sdfr else if (c == '*') { 409178825Sdfr prec = va_arg(ap, int); 410178825Sdfr c = *format++; 411178825Sdfr } 412178825Sdfr } 41355682Smarkm 414178825Sdfr /* size */ 41555682Smarkm 416178825Sdfr if (c == 'h') { 417178825Sdfr short_flag = 1; 418178825Sdfr c = *format++; 419178825Sdfr } else if (c == 'z') { 420178825Sdfr size_t_flag = 1; 421178825Sdfr c = *format++; 422178825Sdfr } else if (c == 'l') { 423178825Sdfr long_flag = 1; 424178825Sdfr c = *format++; 425178825Sdfr if (c == 'l') { 426178825Sdfr long_long_flag = 1; 427178825Sdfr c = *format++; 428178825Sdfr } 429178825Sdfr } 43055682Smarkm 431178825Sdfr if(c != 'd' && c != 'i') 432178825Sdfr flags &= ~(plus_flag | space_flag); 43355682Smarkm 434178825Sdfr switch (c) { 435178825Sdfr case 'c' : 436178825Sdfr append_char(state, va_arg(ap, int), width, flags); 437178825Sdfr ++len; 438178825Sdfr break; 439178825Sdfr case 's' : 440178825Sdfr len += append_string(state, 441178825Sdfr va_arg(ap, unsigned char*), 442178825Sdfr width, 443233294Sstas prec, 444178825Sdfr flags); 445178825Sdfr break; 446178825Sdfr case 'd' : 447178825Sdfr case 'i' : { 448178825Sdfr longest arg; 449178825Sdfr u_longest num; 450178825Sdfr int minusp = 0; 45155682Smarkm 452178825Sdfr PARSE_INT_FORMAT(arg, ap, signed); 45355682Smarkm 454178825Sdfr if (arg < 0) { 455178825Sdfr minusp = 1; 456178825Sdfr num = -arg; 457178825Sdfr } else 458178825Sdfr num = arg; 45955682Smarkm 460178825Sdfr len += append_number (state, num, 10, "0123456789", 461178825Sdfr width, prec, flags, minusp); 462178825Sdfr break; 463178825Sdfr } 464178825Sdfr case 'u' : { 465178825Sdfr u_longest arg; 46655682Smarkm 467178825Sdfr PARSE_INT_FORMAT(arg, ap, unsigned); 46855682Smarkm 469178825Sdfr len += append_number (state, arg, 10, "0123456789", 470178825Sdfr width, prec, flags, 0); 471178825Sdfr break; 472178825Sdfr } 473178825Sdfr case 'o' : { 474178825Sdfr u_longest arg; 47555682Smarkm 476178825Sdfr PARSE_INT_FORMAT(arg, ap, unsigned); 47755682Smarkm 478178825Sdfr len += append_number (state, arg, 010, "01234567", 479178825Sdfr width, prec, flags, 0); 480178825Sdfr break; 481178825Sdfr } 482178825Sdfr case 'x' : { 483178825Sdfr u_longest arg; 48455682Smarkm 485178825Sdfr PARSE_INT_FORMAT(arg, ap, unsigned); 48655682Smarkm 487178825Sdfr len += append_number (state, arg, 0x10, "0123456789abcdef", 488178825Sdfr width, prec, flags, 0); 489178825Sdfr break; 490178825Sdfr } 491178825Sdfr case 'X' :{ 492178825Sdfr u_longest arg; 49355682Smarkm 494178825Sdfr PARSE_INT_FORMAT(arg, ap, unsigned); 49555682Smarkm 496178825Sdfr len += append_number (state, arg, 0x10, "0123456789ABCDEF", 497178825Sdfr width, prec, flags, 0); 498178825Sdfr break; 499178825Sdfr } 500178825Sdfr case 'p' : { 501233294Sstas u_longest arg = (u_longest)va_arg(ap, void*); 502178825Sdfr 503178825Sdfr len += append_number (state, arg, 0x10, "0123456789ABCDEF", 504178825Sdfr width, prec, flags, 0); 505178825Sdfr break; 506178825Sdfr } 507178825Sdfr case 'n' : { 508178825Sdfr int *arg = va_arg(ap, int*); 509178825Sdfr *arg = state->s - state->str; 510178825Sdfr break; 511178825Sdfr } 512178825Sdfr case '\0' : 513178825Sdfr --format; 514178825Sdfr /* FALLTHROUGH */ 515178825Sdfr case '%' : 516178825Sdfr (*state->append_char)(state, c); 517178825Sdfr ++len; 518178825Sdfr break; 519178825Sdfr default : 520178825Sdfr (*state->append_char)(state, '%'); 521178825Sdfr (*state->append_char)(state, c); 522178825Sdfr len += 2; 523178825Sdfr break; 524178825Sdfr } 525178825Sdfr } else { 526178825Sdfr (*state->append_char) (state, c); 527178825Sdfr ++len; 528178825Sdfr } 52990926Snectar } 530178825Sdfr return len; 53155682Smarkm} 53255682Smarkm 53390926Snectar#if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF) 534233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 535233294Sstasrk_snprintf (char *str, size_t sz, const char *format, ...) 53655682Smarkm{ 537178825Sdfr va_list args; 538178825Sdfr int ret; 53955682Smarkm 540178825Sdfr va_start(args, format); 541178825Sdfr ret = vsnprintf (str, sz, format, args); 542178825Sdfr va_end(args); 54355682Smarkm 54455682Smarkm#ifdef PARANOIA 545178825Sdfr { 546178825Sdfr int ret2; 547178825Sdfr char *tmp; 54855682Smarkm 549178825Sdfr tmp = malloc (sz); 550178825Sdfr if (tmp == NULL) 551178825Sdfr abort (); 55255682Smarkm 553178825Sdfr va_start(args, format); 554178825Sdfr ret2 = vsprintf (tmp, format, args); 555178825Sdfr va_end(args); 556178825Sdfr if (ret != ret2 || strcmp(str, tmp)) 557178825Sdfr abort (); 558178825Sdfr free (tmp); 559178825Sdfr } 56055682Smarkm#endif 56155682Smarkm 562178825Sdfr return ret; 56355682Smarkm} 56455682Smarkm#endif 56555682Smarkm 56690926Snectar#if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF) 567233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 568233294Sstasrk_asprintf (char **ret, const char *format, ...) 56955682Smarkm{ 570178825Sdfr va_list args; 571178825Sdfr int val; 57255682Smarkm 573178825Sdfr va_start(args, format); 574178825Sdfr val = vasprintf (ret, format, args); 575178825Sdfr va_end(args); 57655682Smarkm 57755682Smarkm#ifdef PARANOIA 578178825Sdfr { 579178825Sdfr int ret2; 580178825Sdfr char *tmp; 581178825Sdfr tmp = malloc (val + 1); 582178825Sdfr if (tmp == NULL) 583178825Sdfr abort (); 58455682Smarkm 585178825Sdfr va_start(args, format); 586178825Sdfr ret2 = vsprintf (tmp, format, args); 587178825Sdfr va_end(args); 588178825Sdfr if (val != ret2 || strcmp(*ret, tmp)) 589178825Sdfr abort (); 590178825Sdfr free (tmp); 591178825Sdfr } 59255682Smarkm#endif 59355682Smarkm 594178825Sdfr return val; 59555682Smarkm} 59655682Smarkm#endif 59755682Smarkm 59890926Snectar#if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF) 599233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 600233294Sstasrk_asnprintf (char **ret, size_t max_sz, const char *format, ...) 60155682Smarkm{ 602178825Sdfr va_list args; 603178825Sdfr int val; 60455682Smarkm 605178825Sdfr va_start(args, format); 606178825Sdfr val = vasnprintf (ret, max_sz, format, args); 60755682Smarkm 60855682Smarkm#ifdef PARANOIA 609178825Sdfr { 610178825Sdfr int ret2; 611178825Sdfr char *tmp; 612178825Sdfr tmp = malloc (val + 1); 613178825Sdfr if (tmp == NULL) 614178825Sdfr abort (); 61555682Smarkm 616178825Sdfr ret2 = vsprintf (tmp, format, args); 617178825Sdfr if (val != ret2 || strcmp(*ret, tmp)) 618178825Sdfr abort (); 619178825Sdfr free (tmp); 620178825Sdfr } 62155682Smarkm#endif 62255682Smarkm 623178825Sdfr va_end(args); 624178825Sdfr return val; 62555682Smarkm} 62655682Smarkm#endif 62755682Smarkm 62890926Snectar#if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF) 629233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 630233294Sstasrk_vasprintf (char **ret, const char *format, va_list args) 63155682Smarkm{ 632178825Sdfr return vasnprintf (ret, 0, format, args); 63355682Smarkm} 63455682Smarkm#endif 63555682Smarkm 63655682Smarkm 63790926Snectar#if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF) 638233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 639233294Sstasrk_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) 64055682Smarkm{ 641233294Sstas size_t st; 642178825Sdfr struct snprintf_state state; 64355682Smarkm 644178825Sdfr state.max_sz = max_sz; 645178825Sdfr state.sz = 1; 646178825Sdfr state.str = malloc(state.sz); 647178825Sdfr if (state.str == NULL) { 648178825Sdfr *ret = NULL; 649178825Sdfr return -1; 650178825Sdfr } 651178825Sdfr state.s = state.str; 652178825Sdfr state.theend = state.s + state.sz - 1; 653178825Sdfr state.append_char = as_append_char; 65455682Smarkm 655178825Sdfr st = xyzprintf (&state, format, args); 656178825Sdfr if (st > state.sz) { 657178825Sdfr free (state.str); 658178825Sdfr *ret = NULL; 659178825Sdfr return -1; 660178825Sdfr } else { 661178825Sdfr char *tmp; 66255682Smarkm 663178825Sdfr *state.s = '\0'; 664178825Sdfr tmp = realloc (state.str, st+1); 665178825Sdfr if (tmp == NULL) { 666178825Sdfr free (state.str); 667178825Sdfr *ret = NULL; 668178825Sdfr return -1; 669178825Sdfr } 670178825Sdfr *ret = tmp; 671178825Sdfr return st; 67255682Smarkm } 67355682Smarkm} 67455682Smarkm#endif 67555682Smarkm 67690926Snectar#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) 677233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 678233294Sstasrk_vsnprintf (char *str, size_t sz, const char *format, va_list args) 67955682Smarkm{ 680178825Sdfr struct snprintf_state state; 681178825Sdfr int ret; 682178825Sdfr unsigned char *ustr = (unsigned char *)str; 68355682Smarkm 684178825Sdfr state.max_sz = 0; 685178825Sdfr state.sz = sz; 686178825Sdfr state.str = ustr; 687178825Sdfr state.s = ustr; 688178825Sdfr state.theend = ustr + sz - (sz > 0); 689178825Sdfr state.append_char = sn_append_char; 69055682Smarkm 691178825Sdfr ret = xyzprintf (&state, format, args); 692178825Sdfr if (state.s != NULL && sz != 0) 693178825Sdfr *state.s = '\0'; 694178825Sdfr return ret; 69555682Smarkm} 69655682Smarkm#endif 697