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