Home | History | Annotate | Line # | Download | only in compat
snprintf.c revision 1.2
      1  1.1  tv /*
      2  1.1  tv  * Copyright (c) 1995-2001 Kungliga Tekniska Hgskolan
      3  1.1  tv  * (Royal Institute of Technology, Stockholm, Sweden).
      4  1.1  tv  * All rights reserved.
      5  1.1  tv  *
      6  1.1  tv  * Redistribution and use in source and binary forms, with or without
      7  1.1  tv  * modification, are permitted provided that the following conditions
      8  1.1  tv  * are met:
      9  1.1  tv  *
     10  1.1  tv  * 1. Redistributions of source code must retain the above copyright
     11  1.1  tv  *    notice, this list of conditions and the following disclaimer.
     12  1.1  tv  *
     13  1.1  tv  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.1  tv  *    notice, this list of conditions and the following disclaimer in the
     15  1.1  tv  *    documentation and/or other materials provided with the distribution.
     16  1.1  tv  *
     17  1.1  tv  * 3. Neither the name of the Institute nor the names of its contributors
     18  1.1  tv  *    may be used to endorse or promote products derived from this software
     19  1.1  tv  *    without specific prior written permission.
     20  1.1  tv  *
     21  1.1  tv  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     22  1.1  tv  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  1.1  tv  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  1.1  tv  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     25  1.1  tv  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  1.1  tv  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  1.1  tv  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  1.1  tv  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  1.1  tv  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  1.1  tv  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  1.1  tv  * SUCH DAMAGE.
     32  1.1  tv  */
     33  1.1  tv 
     34  1.1  tv /* From heimdal lib/roken/snprintf.c. */
     35  1.1  tv 
     36  1.1  tv #ifdef HAVE_CONFIG_H
     37  1.1  tv #include <config.h>
     38  1.2  tv #if 0
     39  1.2  tv RCSID("$Id: snprintf.c,v 1.2 2002/01/31 19:23:14 tv Exp $");
     40  1.2  tv #endif
     41  1.1  tv #endif
     42  1.1  tv #include <stdio.h>
     43  1.1  tv #include <stdarg.h>
     44  1.1  tv #include <stdlib.h>
     45  1.1  tv #include <string.h>
     46  1.1  tv #include <ctype.h>
     47  1.1  tv #if 0
     48  1.1  tv #include <roken.h>
     49  1.1  tv #endif
     50  1.1  tv 
     51  1.1  tv #undef min
     52  1.1  tv #define min(a,b) ((a) < (b) ? (a) : (b))
     53  1.1  tv #undef max
     54  1.1  tv #define max(a,b) ((a) > (b) ? (a) : (b))
     55  1.1  tv 
     56  1.1  tv enum format_flags {
     57  1.1  tv     minus_flag     =  1,
     58  1.1  tv     plus_flag      =  2,
     59  1.1  tv     space_flag     =  4,
     60  1.1  tv     alternate_flag =  8,
     61  1.1  tv     zero_flag      = 16
     62  1.1  tv };
     63  1.1  tv 
     64  1.1  tv /*
     65  1.1  tv  * Common state
     66  1.1  tv  */
     67  1.1  tv 
     68  1.1  tv struct state {
     69  1.1  tv   unsigned char *str;
     70  1.1  tv   unsigned char *s;
     71  1.1  tv   unsigned char *theend;
     72  1.1  tv   size_t sz;
     73  1.1  tv   size_t max_sz;
     74  1.1  tv   void (*append_char)(struct state *, unsigned char);
     75  1.1  tv   /* XXX - methods */
     76  1.1  tv };
     77  1.1  tv 
     78  1.1  tv #if TEST_SNPRINTF
     79  1.1  tv #include "snprintf-test.h"
     80  1.1  tv #endif /* TEST_SNPRINTF */
     81  1.1  tv 
     82  1.1  tv #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
     83  1.1  tv static int
     84  1.1  tv sn_reserve (struct state *state, size_t n)
     85  1.1  tv {
     86  1.1  tv   return state->s + n > state->theend;
     87  1.1  tv }
     88  1.1  tv 
     89  1.1  tv static void
     90  1.1  tv sn_append_char (struct state *state, unsigned char c)
     91  1.1  tv {
     92  1.1  tv   if (!sn_reserve (state, 1))
     93  1.1  tv     *state->s++ = c;
     94  1.1  tv }
     95  1.1  tv #endif
     96  1.1  tv 
     97  1.1  tv static int
     98  1.1  tv as_reserve (struct state *state, size_t n)
     99  1.1  tv {
    100  1.1  tv   if (state->s + n > state->theend) {
    101  1.1  tv     int off = state->s - state->str;
    102  1.1  tv     unsigned char *tmp;
    103  1.1  tv 
    104  1.1  tv     if (state->max_sz && state->sz >= state->max_sz)
    105  1.1  tv       return 1;
    106  1.1  tv 
    107  1.1  tv     state->sz = max(state->sz * 2, state->sz + n);
    108  1.1  tv     if (state->max_sz)
    109  1.1  tv       state->sz = min(state->sz, state->max_sz);
    110  1.1  tv     tmp = realloc (state->str, state->sz);
    111  1.1  tv     if (tmp == NULL)
    112  1.1  tv       return 1;
    113  1.1  tv     state->str = tmp;
    114  1.1  tv     state->s = state->str + off;
    115  1.1  tv     state->theend = state->str + state->sz - 1;
    116  1.1  tv   }
    117  1.1  tv   return 0;
    118  1.1  tv }
    119  1.1  tv 
    120  1.1  tv static void
    121  1.1  tv as_append_char (struct state *state, unsigned char c)
    122  1.1  tv {
    123  1.1  tv   if(!as_reserve (state, 1))
    124  1.1  tv     *state->s++ = c;
    125  1.1  tv }
    126  1.1  tv 
    127  1.1  tv /* longest integer types */
    128  1.1  tv 
    129  1.1  tv #ifdef HAVE_LONG_LONG
    130  1.1  tv typedef unsigned long long u_longest;
    131  1.1  tv typedef long long longest;
    132  1.1  tv #else
    133  1.1  tv typedef unsigned long u_longest;
    134  1.1  tv typedef long longest;
    135  1.1  tv #endif
    136  1.1  tv 
    137  1.1  tv /*
    138  1.1  tv  * is # supposed to do anything?
    139  1.1  tv  */
    140  1.1  tv 
    141  1.1  tv static int
    142  1.1  tv use_alternative (int flags, u_longest num, unsigned base)
    143  1.1  tv {
    144  1.1  tv   return flags & alternate_flag && (base == 16 || base == 8) && num != 0;
    145  1.1  tv }
    146  1.1  tv 
    147  1.1  tv static int
    148  1.1  tv append_number(struct state *state,
    149  1.1  tv 	      u_longest num, unsigned base, char *rep,
    150  1.1  tv 	      int width, int prec, int flags, int minusp)
    151  1.1  tv {
    152  1.1  tv   int len = 0;
    153  1.1  tv   int i;
    154  1.1  tv   u_longest n = num;
    155  1.1  tv 
    156  1.1  tv   /* given precision, ignore zero flag */
    157  1.1  tv   if(prec != -1)
    158  1.1  tv     flags &= ~zero_flag;
    159  1.1  tv   else
    160  1.1  tv     prec = 1;
    161  1.1  tv   /* zero value with zero precision -> "" */
    162  1.1  tv   if(prec == 0 && n == 0)
    163  1.1  tv     return 0;
    164  1.1  tv   do{
    165  1.1  tv     (*state->append_char)(state, rep[n % base]);
    166  1.1  tv     ++len;
    167  1.1  tv     n /= base;
    168  1.1  tv   } while(n);
    169  1.1  tv   prec -= len;
    170  1.1  tv   /* pad with prec zeros */
    171  1.1  tv   while(prec-- > 0){
    172  1.1  tv     (*state->append_char)(state, '0');
    173  1.1  tv     ++len;
    174  1.1  tv   }
    175  1.1  tv   /* add length of alternate prefix (added later) to len */
    176  1.1  tv   if(use_alternative(flags, num, base))
    177  1.1  tv     len += base / 8;
    178  1.1  tv   /* pad with zeros */
    179  1.1  tv   if(flags & zero_flag){
    180  1.1  tv     width -= len;
    181  1.1  tv     if(minusp || (flags & space_flag) || (flags & plus_flag))
    182  1.1  tv       width--;
    183  1.1  tv     while(width-- > 0){
    184  1.1  tv       (*state->append_char)(state, '0');
    185  1.1  tv       len++;
    186  1.1  tv     }
    187  1.1  tv   }
    188  1.1  tv   /* add alternate prefix */
    189  1.1  tv   if(use_alternative(flags, num, base)){
    190  1.1  tv     if(base == 16)
    191  1.1  tv       (*state->append_char)(state, rep[10] + 23); /* XXX */
    192  1.1  tv     (*state->append_char)(state, '0');
    193  1.1  tv   }
    194  1.1  tv   /* add sign */
    195  1.1  tv   if(minusp){
    196  1.1  tv     (*state->append_char)(state, '-');
    197  1.1  tv     ++len;
    198  1.1  tv   } else if(flags & plus_flag) {
    199  1.1  tv     (*state->append_char)(state, '+');
    200  1.1  tv     ++len;
    201  1.1  tv   } else if(flags & space_flag) {
    202  1.1  tv     (*state->append_char)(state, ' ');
    203  1.1  tv     ++len;
    204  1.1  tv   }
    205  1.1  tv   if(flags & minus_flag)
    206  1.1  tv     /* swap before padding with spaces */
    207  1.1  tv     for(i = 0; i < len / 2; i++){
    208  1.1  tv       char c = state->s[-i-1];
    209  1.1  tv       state->s[-i-1] = state->s[-len+i];
    210  1.1  tv       state->s[-len+i] = c;
    211  1.1  tv     }
    212  1.1  tv   width -= len;
    213  1.1  tv   while(width-- > 0){
    214  1.1  tv     (*state->append_char)(state,  ' ');
    215  1.1  tv     ++len;
    216  1.1  tv   }
    217  1.1  tv   if(!(flags & minus_flag))
    218  1.1  tv     /* swap after padding with spaces */
    219  1.1  tv     for(i = 0; i < len / 2; i++){
    220  1.1  tv       char c = state->s[-i-1];
    221  1.1  tv       state->s[-i-1] = state->s[-len+i];
    222  1.1  tv       state->s[-len+i] = c;
    223  1.1  tv     }
    224  1.1  tv   return len;
    225  1.1  tv }
    226  1.1  tv 
    227  1.1  tv /*
    228  1.1  tv  * return length
    229  1.1  tv  */
    230  1.1  tv 
    231  1.1  tv static int
    232  1.1  tv append_string (struct state *state,
    233  1.1  tv 	       const unsigned char *arg,
    234  1.1  tv 	       int width,
    235  1.1  tv 	       int prec,
    236  1.1  tv 	       int flags)
    237  1.1  tv {
    238  1.1  tv     int len = 0;
    239  1.1  tv 
    240  1.1  tv     if(arg == NULL)
    241  1.1  tv 	arg = (const unsigned char*)"(null)";
    242  1.1  tv 
    243  1.1  tv     if(prec != -1)
    244  1.1  tv 	width -= prec;
    245  1.1  tv     else
    246  1.1  tv 	width -= strlen((const char *)arg);
    247  1.1  tv     if(!(flags & minus_flag))
    248  1.1  tv 	while(width-- > 0) {
    249  1.1  tv 	    (*state->append_char) (state, ' ');
    250  1.1  tv 	    ++len;
    251  1.1  tv 	}
    252  1.1  tv     if (prec != -1) {
    253  1.1  tv 	while (*arg && prec--) {
    254  1.1  tv 	    (*state->append_char) (state, *arg++);
    255  1.1  tv 	    ++len;
    256  1.1  tv 	}
    257  1.1  tv     } else {
    258  1.1  tv 	while (*arg) {
    259  1.1  tv 	    (*state->append_char) (state, *arg++);
    260  1.1  tv 	    ++len;
    261  1.1  tv 	}
    262  1.1  tv     }
    263  1.1  tv     if(flags & minus_flag)
    264  1.1  tv 	while(width-- > 0) {
    265  1.1  tv 	    (*state->append_char) (state, ' ');
    266  1.1  tv 	    ++len;
    267  1.1  tv 	}
    268  1.1  tv     return len;
    269  1.1  tv }
    270  1.1  tv 
    271  1.1  tv static int
    272  1.1  tv append_char(struct state *state,
    273  1.1  tv 	    unsigned char arg,
    274  1.1  tv 	    int width,
    275  1.1  tv 	    int flags)
    276  1.1  tv {
    277  1.1  tv   int len = 0;
    278  1.1  tv 
    279  1.1  tv   while(!(flags & minus_flag) && --width > 0) {
    280  1.1  tv     (*state->append_char) (state, ' ')    ;
    281  1.1  tv     ++len;
    282  1.1  tv   }
    283  1.1  tv   (*state->append_char) (state, arg);
    284  1.1  tv   ++len;
    285  1.1  tv   while((flags & minus_flag) && --width > 0) {
    286  1.1  tv     (*state->append_char) (state, ' ');
    287  1.1  tv     ++len;
    288  1.1  tv   }
    289  1.1  tv   return 0;
    290  1.1  tv }
    291  1.1  tv 
    292  1.1  tv /*
    293  1.1  tv  * This can't be made into a function...
    294  1.1  tv  */
    295  1.1  tv 
    296  1.1  tv #ifdef HAVE_LONG_LONG
    297  1.1  tv 
    298  1.1  tv #define PARSE_INT_FORMAT(res, arg, unsig) \
    299  1.1  tv if (long_long_flag) \
    300  1.1  tv      res = (unsig long long)va_arg(arg, unsig long long); \
    301  1.1  tv else if (long_flag) \
    302  1.1  tv      res = (unsig long)va_arg(arg, unsig long); \
    303  1.1  tv else if (short_flag) \
    304  1.1  tv      res = (unsig short)va_arg(arg, unsig int); \
    305  1.1  tv else \
    306  1.1  tv      res = (unsig int)va_arg(arg, unsig int)
    307  1.1  tv 
    308  1.1  tv #else
    309  1.1  tv 
    310  1.1  tv #define PARSE_INT_FORMAT(res, arg, unsig) \
    311  1.1  tv if (long_flag) \
    312  1.1  tv      res = (unsig long)va_arg(arg, unsig long); \
    313  1.1  tv else if (short_flag) \
    314  1.1  tv      res = (unsig short)va_arg(arg, unsig int); \
    315  1.1  tv else \
    316  1.1  tv      res = (unsig int)va_arg(arg, unsig int)
    317  1.1  tv 
    318  1.1  tv #endif
    319  1.1  tv 
    320  1.1  tv /*
    321  1.1  tv  * zyxprintf - return length, as snprintf
    322  1.1  tv  */
    323  1.1  tv 
    324  1.1  tv static int
    325  1.1  tv xyzprintf (struct state *state, const char *char_format, va_list ap)
    326  1.1  tv {
    327  1.1  tv   const unsigned char *format = (const unsigned char *)char_format;
    328  1.1  tv   unsigned char c;
    329  1.1  tv   int len = 0;
    330  1.1  tv 
    331  1.1  tv   while((c = *format++)) {
    332  1.1  tv     if (c == '%') {
    333  1.1  tv       int flags          = 0;
    334  1.1  tv       int width          = 0;
    335  1.1  tv       int prec           = -1;
    336  1.1  tv       int long_long_flag = 0;
    337  1.1  tv       int long_flag      = 0;
    338  1.1  tv       int short_flag     = 0;
    339  1.1  tv 
    340  1.1  tv       /* flags */
    341  1.1  tv       while((c = *format++)){
    342  1.1  tv 	if(c == '-')
    343  1.1  tv 	  flags |= minus_flag;
    344  1.1  tv 	else if(c == '+')
    345  1.1  tv 	  flags |= plus_flag;
    346  1.1  tv 	else if(c == ' ')
    347  1.1  tv 	  flags |= space_flag;
    348  1.1  tv 	else if(c == '#')
    349  1.1  tv 	  flags |= alternate_flag;
    350  1.1  tv 	else if(c == '0')
    351  1.1  tv 	  flags |= zero_flag;
    352  1.1  tv 	else
    353  1.1  tv 	  break;
    354  1.1  tv       }
    355  1.1  tv 
    356  1.1  tv       if((flags & space_flag) && (flags & plus_flag))
    357  1.1  tv 	flags ^= space_flag;
    358  1.1  tv 
    359  1.1  tv       if((flags & minus_flag) && (flags & zero_flag))
    360  1.1  tv 	flags ^= zero_flag;
    361  1.1  tv 
    362  1.1  tv       /* width */
    363  1.1  tv       if (isdigit(c))
    364  1.1  tv 	do {
    365  1.1  tv 	  width = width * 10 + c - '0';
    366  1.1  tv 	  c = *format++;
    367  1.1  tv 	} while(isdigit(c));
    368  1.1  tv       else if(c == '*') {
    369  1.1  tv 	width = va_arg(ap, int);
    370  1.1  tv 	c = *format++;
    371  1.1  tv       }
    372  1.1  tv 
    373  1.1  tv       /* precision */
    374  1.1  tv       if (c == '.') {
    375  1.1  tv 	prec = 0;
    376  1.1  tv 	c = *format++;
    377  1.1  tv 	if (isdigit(c))
    378  1.1  tv 	  do {
    379  1.1  tv 	    prec = prec * 10 + c - '0';
    380  1.1  tv 	    c = *format++;
    381  1.1  tv 	  } while(isdigit(c));
    382  1.1  tv 	else if (c == '*') {
    383  1.1  tv 	  prec = va_arg(ap, int);
    384  1.1  tv 	  c = *format++;
    385  1.1  tv 	}
    386  1.1  tv       }
    387  1.1  tv 
    388  1.1  tv       /* size */
    389  1.1  tv 
    390  1.1  tv       if (c == 'h') {
    391  1.1  tv 	short_flag = 1;
    392  1.1  tv 	c = *format++;
    393  1.1  tv       } else if (c == 'l') {
    394  1.1  tv 	long_flag = 1;
    395  1.1  tv 	c = *format++;
    396  1.1  tv 	if (c == 'l') {
    397  1.1  tv 	    long_long_flag = 1;
    398  1.1  tv 	    c = *format++;
    399  1.1  tv 	}
    400  1.1  tv       }
    401  1.1  tv 
    402  1.1  tv       switch (c) {
    403  1.1  tv       case 'c' :
    404  1.1  tv 	append_char(state, va_arg(ap, int), width, flags);
    405  1.1  tv 	++len;
    406  1.1  tv 	break;
    407  1.1  tv       case 's' :
    408  1.1  tv 	len += append_string(state,
    409  1.1  tv 			     va_arg(ap, unsigned char*),
    410  1.1  tv 			     width,
    411  1.1  tv 			     prec,
    412  1.1  tv 			     flags);
    413  1.1  tv 	break;
    414  1.1  tv       case 'd' :
    415  1.1  tv       case 'i' : {
    416  1.1  tv 	longest arg;
    417  1.1  tv 	u_longest num;
    418  1.1  tv 	int minusp = 0;
    419  1.1  tv 
    420  1.1  tv 	PARSE_INT_FORMAT(arg, ap, signed);
    421  1.1  tv 
    422  1.1  tv 	if (arg < 0) {
    423  1.1  tv 	  minusp = 1;
    424  1.1  tv 	  num = -arg;
    425  1.1  tv 	} else
    426  1.1  tv 	  num = arg;
    427  1.1  tv 
    428  1.1  tv 	len += append_number (state, num, 10, "0123456789",
    429  1.1  tv 			      width, prec, flags, minusp);
    430  1.1  tv 	break;
    431  1.1  tv       }
    432  1.1  tv       case 'u' : {
    433  1.1  tv 	u_longest arg;
    434  1.1  tv 
    435  1.1  tv 	PARSE_INT_FORMAT(arg, ap, unsigned);
    436  1.1  tv 
    437  1.1  tv 	len += append_number (state, arg, 10, "0123456789",
    438  1.1  tv 			      width, prec, flags, 0);
    439  1.1  tv 	break;
    440  1.1  tv       }
    441  1.1  tv       case 'o' : {
    442  1.1  tv 	u_longest arg;
    443  1.1  tv 
    444  1.1  tv 	PARSE_INT_FORMAT(arg, ap, unsigned);
    445  1.1  tv 
    446  1.1  tv 	len += append_number (state, arg, 010, "01234567",
    447  1.1  tv 			      width, prec, flags, 0);
    448  1.1  tv 	break;
    449  1.1  tv       }
    450  1.1  tv       case 'x' : {
    451  1.1  tv 	u_longest arg;
    452  1.1  tv 
    453  1.1  tv 	PARSE_INT_FORMAT(arg, ap, unsigned);
    454  1.1  tv 
    455  1.1  tv 	len += append_number (state, arg, 0x10, "0123456789abcdef",
    456  1.1  tv 			      width, prec, flags, 0);
    457  1.1  tv 	break;
    458  1.1  tv       }
    459  1.1  tv       case 'X' :{
    460  1.1  tv 	u_longest arg;
    461  1.1  tv 
    462  1.1  tv 	PARSE_INT_FORMAT(arg, ap, unsigned);
    463  1.1  tv 
    464  1.1  tv 	len += append_number (state, arg, 0x10, "0123456789ABCDEF",
    465  1.1  tv 			      width, prec, flags, 0);
    466  1.1  tv 	break;
    467  1.1  tv       }
    468  1.1  tv       case 'p' : {
    469  1.1  tv 	unsigned long arg = (unsigned long)va_arg(ap, void*);
    470  1.1  tv 
    471  1.1  tv 	len += append_number (state, arg, 0x10, "0123456789ABCDEF",
    472  1.1  tv 			      width, prec, flags, 0);
    473  1.1  tv 	break;
    474  1.1  tv       }
    475  1.1  tv       case 'n' : {
    476  1.1  tv 	int *arg = va_arg(ap, int*);
    477  1.1  tv 	*arg = state->s - state->str;
    478  1.1  tv 	break;
    479  1.1  tv       }
    480  1.1  tv       case '\0' :
    481  1.1  tv 	  --format;
    482  1.1  tv 	  /* FALLTHROUGH */
    483  1.1  tv       case '%' :
    484  1.1  tv 	(*state->append_char)(state, c);
    485  1.1  tv 	++len;
    486  1.1  tv 	break;
    487  1.1  tv       default :
    488  1.1  tv 	(*state->append_char)(state, '%');
    489  1.1  tv 	(*state->append_char)(state, c);
    490  1.1  tv 	len += 2;
    491  1.1  tv 	break;
    492  1.1  tv       }
    493  1.1  tv     } else {
    494  1.1  tv       (*state->append_char) (state, c);
    495  1.1  tv       ++len;
    496  1.1  tv     }
    497  1.1  tv   }
    498  1.1  tv   return len;
    499  1.1  tv }
    500  1.1  tv 
    501  1.1  tv #if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF)
    502  1.1  tv int
    503  1.1  tv snprintf (char *str, size_t sz, const char *format, ...)
    504  1.1  tv {
    505  1.1  tv   va_list args;
    506  1.1  tv   int ret;
    507  1.1  tv 
    508  1.1  tv   va_start(args, format);
    509  1.1  tv   ret = vsnprintf (str, sz, format, args);
    510  1.1  tv   va_end(args);
    511  1.1  tv 
    512  1.1  tv #ifdef PARANOIA
    513  1.1  tv   {
    514  1.1  tv     int ret2;
    515  1.1  tv     char *tmp;
    516  1.1  tv 
    517  1.1  tv     tmp = malloc (sz);
    518  1.1  tv     if (tmp == NULL)
    519  1.1  tv       abort ();
    520  1.1  tv 
    521  1.1  tv     va_start(args, format);
    522  1.1  tv     ret2 = vsprintf (tmp, format, args);
    523  1.1  tv     va_end(args);
    524  1.1  tv     if (ret != ret2 || strcmp(str, tmp))
    525  1.1  tv       abort ();
    526  1.1  tv     free (tmp);
    527  1.1  tv   }
    528  1.1  tv #endif
    529  1.1  tv 
    530  1.1  tv   return ret;
    531  1.1  tv }
    532  1.1  tv #endif
    533  1.1  tv 
    534  1.1  tv #if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF)
    535  1.1  tv int
    536  1.1  tv asprintf (char **ret, const char *format, ...)
    537  1.1  tv {
    538  1.1  tv   va_list args;
    539  1.1  tv   int val;
    540  1.1  tv 
    541  1.1  tv   va_start(args, format);
    542  1.1  tv   val = vasprintf (ret, format, args);
    543  1.1  tv 
    544  1.1  tv #ifdef PARANOIA
    545  1.1  tv   {
    546  1.1  tv     int ret2;
    547  1.1  tv     char *tmp;
    548  1.1  tv     tmp = malloc (val + 1);
    549  1.1  tv     if (tmp == NULL)
    550  1.1  tv       abort ();
    551  1.1  tv 
    552  1.1  tv     ret2 = vsprintf (tmp, format, args);
    553  1.1  tv     if (val != ret2 || strcmp(*ret, tmp))
    554  1.1  tv       abort ();
    555  1.1  tv     free (tmp);
    556  1.1  tv   }
    557  1.1  tv #endif
    558  1.1  tv 
    559  1.1  tv   va_end(args);
    560  1.1  tv   return val;
    561  1.1  tv }
    562  1.1  tv #endif
    563  1.1  tv 
    564  1.1  tv #if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF)
    565  1.1  tv int
    566  1.1  tv asnprintf (char **ret, size_t max_sz, const char *format, ...)
    567  1.1  tv {
    568  1.1  tv   va_list args;
    569  1.1  tv   int val;
    570  1.1  tv 
    571  1.1  tv   va_start(args, format);
    572  1.1  tv   val = vasnprintf (ret, max_sz, format, args);
    573  1.1  tv 
    574  1.1  tv #ifdef PARANOIA
    575  1.1  tv   {
    576  1.1  tv     int ret2;
    577  1.1  tv     char *tmp;
    578  1.1  tv     tmp = malloc (val + 1);
    579  1.1  tv     if (tmp == NULL)
    580  1.1  tv       abort ();
    581  1.1  tv 
    582  1.1  tv     ret2 = vsprintf (tmp, format, args);
    583  1.1  tv     if (val != ret2 || strcmp(*ret, tmp))
    584  1.1  tv       abort ();
    585  1.1  tv     free (tmp);
    586  1.1  tv   }
    587  1.1  tv #endif
    588  1.1  tv 
    589  1.1  tv   va_end(args);
    590  1.1  tv   return val;
    591  1.1  tv }
    592  1.1  tv #endif
    593  1.1  tv 
    594  1.1  tv #if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF)
    595  1.1  tv int
    596  1.1  tv vasprintf (char **ret, const char *format, va_list args)
    597  1.1  tv {
    598  1.1  tv   return vasnprintf (ret, 0, format, args);
    599  1.1  tv }
    600  1.1  tv #endif
    601  1.1  tv 
    602  1.1  tv 
    603  1.1  tv #if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF)
    604  1.1  tv int
    605  1.1  tv vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
    606  1.1  tv {
    607  1.1  tv   int st;
    608  1.1  tv   struct state state;
    609  1.1  tv 
    610  1.1  tv   state.max_sz = max_sz;
    611  1.1  tv   state.sz     = 1;
    612  1.1  tv   state.str    = malloc(state.sz);
    613  1.1  tv   if (state.str == NULL) {
    614  1.1  tv     *ret = NULL;
    615  1.1  tv     return -1;
    616  1.1  tv   }
    617  1.1  tv   state.s = state.str;
    618  1.1  tv   state.theend = state.s + state.sz - 1;
    619  1.1  tv   state.append_char = as_append_char;
    620  1.1  tv 
    621  1.1  tv   st = xyzprintf (&state, format, args);
    622  1.1  tv   if (st > state.sz) {
    623  1.1  tv     free (state.str);
    624  1.1  tv     *ret = NULL;
    625  1.1  tv     return -1;
    626  1.1  tv   } else {
    627  1.1  tv     char *tmp;
    628  1.1  tv 
    629  1.1  tv     *state.s = '\0';
    630  1.1  tv     tmp = realloc (state.str, st+1);
    631  1.1  tv     if (tmp == NULL) {
    632  1.1  tv       free (state.str);
    633  1.1  tv       *ret = NULL;
    634  1.1  tv       return -1;
    635  1.1  tv     }
    636  1.1  tv     *ret = tmp;
    637  1.1  tv     return st;
    638  1.1  tv   }
    639  1.1  tv }
    640  1.1  tv #endif
    641  1.1  tv 
    642  1.1  tv #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
    643  1.1  tv int
    644  1.1  tv vsnprintf (char *str, size_t sz, const char *format, va_list args)
    645  1.1  tv {
    646  1.1  tv   struct state state;
    647  1.1  tv   int ret;
    648  1.1  tv   unsigned char *ustr = (unsigned char *)str;
    649  1.1  tv 
    650  1.1  tv   state.max_sz = 0;
    651  1.1  tv   state.sz     = sz;
    652  1.1  tv   state.str    = ustr;
    653  1.1  tv   state.s      = ustr;
    654  1.1  tv   state.theend = ustr + sz - (sz > 0);
    655  1.1  tv   state.append_char = sn_append_char;
    656  1.1  tv 
    657  1.1  tv   ret = xyzprintf (&state, format, args);
    658  1.1  tv   if (state.s != NULL)
    659  1.1  tv     *state.s = '\0';
    660  1.1  tv   return ret;
    661  1.1  tv }
    662  1.1  tv #endif
    663