120ab0271b2600ebf767b004f7ba63337e08362b
[runtime.git] / lib / silcutil / silcsnprintf.c
1 /*
2  * Copyright Patrick Powell 1995
3  * This code is based on code written by Patrick Powell (papowell@astart.com)
4  * It may be used for any purpose as long as this notice remains intact
5  * on all source code distributions
6  */
7
8 /**************************************************************
9  * Original:
10  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
11  * A bombproof version of doprnt (dopr) included.
12  * Sigh.  This sort of thing is always nasty do deal with.  Note that
13  * the version here does not include floating point...
14  *
15  * snprintf() is used instead of sprintf() as it does limit checks
16  * for string length.  This covers a nasty loophole.
17  *
18  * The other functions are there to prevent NULL pointers from
19  * causing nast effects.
20  *
21  * More Recently:
22  *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
23  *  This was ugly.  It is still ugly.  I opted out of floating point
24  *  numbers, but the formatter understands just about everything
25  *  from the normal C string format, at least as far as I can tell from
26  *  the Solaris 2.5 printf(3S) man page.
27  *
28  *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
29  *    Ok, added some minimal floating point support, which means this
30  *    probably requires libm on most operating systems.  Don't yet
31  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
32  *    was pretty badly broken, it just wasn't being exercised in ways
33  *    which showed it, so that's been fixed.  Also, formated the code
34  *    to mutt conventions, and removed dead code left over from the
35  *    original.  Also, there is now a builtin-test, just compile with:
36  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
37  *    and run snprintf for results.
38  *
39  *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
40  *    The PGP code was using unsigned hexadecimal formats.
41  *    Unfortunately, unsigned formats simply didn't work.
42  *
43  *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
44  *    The original code assumed that both snprintf() and vsnprintf() were
45  *    missing.  Some systems only have snprintf() but not vsnprintf(), so
46  *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
47  *
48  *  Andrew Tridgell (tridge@samba.org) Oct 1998
49  *    fixed handling of %.0f
50  *    added test for HAVE_LONG_DOUBLE
51  *
52  * tridge@samba.org, idra@samba.org, April 2001
53  *    got rid of fcvt code (twas buggy and made testing harder)
54  *    added C99 semantics
55  *
56  **************************************************************/
57
58 #include "silcruntime.h"
59
60 #ifdef HAVE_LONG_DOUBLE
61 #define LDOUBLE long double
62 #else
63 #define LDOUBLE double
64 #endif
65
66 #ifdef HAVE_LONG_LONG
67 #define LLONG long long
68 #else
69 #define LLONG long
70 #endif
71
72 /*
73  * dopr(): poor man's version of doprintf
74  */
75
76 /* format read states */
77 #define DP_S_DEFAULT 0
78 #define DP_S_FLAGS   1
79 #define DP_S_MIN     2
80 #define DP_S_DOT     3
81 #define DP_S_MAX     4
82 #define DP_S_MOD     5
83 #define DP_S_CONV    6
84 #define DP_S_DONE    7
85
86 /* format flags - Bits */
87 #define DP_F_MINUS      (1 << 0)
88 #define DP_F_PLUS       (1 << 1)
89 #define DP_F_SPACE      (1 << 2)
90 #define DP_F_NUM        (1 << 3)
91 #define DP_F_ZERO       (1 << 4)
92 #define DP_F_UP         (1 << 5)
93 #define DP_F_UNSIGNED   (1 << 6)
94 #define DP_F_HEXPREFIX  (1 << 7)
95
96 /* Conversion Flags */
97 #define DP_C_SHORT   1
98 #define DP_C_LONG    2
99 #define DP_C_LDOUBLE 3
100 #define DP_C_LLONG   4
101
102 #define char_to_int(p) ((p)- '0')
103 #ifndef MAX
104 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
105 #endif
106
107 static size_t dopr(char *buffer, size_t maxlen, const char *format,
108                    va_list args_in);
109 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
110                     char *value, int flags, int min, int max);
111 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
112                     long value, int base, int min, int max, int flags);
113 static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
114                    LDOUBLE fvalue, int min, int max, int flags);
115 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
116
117 static size_t dopr(char *buffer, size_t maxlen, const char *format,
118                    va_list args_in)
119 {
120   char ch;
121   LLONG value;
122   LDOUBLE fvalue;
123   char *strvalue;
124   int min;
125   int max;
126   int state;
127   int flags;
128   int cflags;
129   size_t currlen;
130   va_list args;
131   SilcSnprintfRender render;
132
133   silc_va_copy(args, args_in);
134
135   state = DP_S_DEFAULT;
136   currlen = flags = cflags = min = 0;
137   max = -1;
138   ch = *format++;
139
140   while (state != DP_S_DONE) {
141     if (ch == '\0')
142       state = DP_S_DONE;
143
144     switch(state) {
145     case DP_S_DEFAULT:
146       if (ch == '%')
147         state = DP_S_FLAGS;
148       else
149         dopr_outch (buffer, &currlen, maxlen, ch);
150       ch = *format++;
151       break;
152     case DP_S_FLAGS:
153       switch (ch) {
154       case '-':
155         flags |= DP_F_MINUS;
156         ch = *format++;
157         break;
158       case '+':
159         flags |= DP_F_PLUS;
160         ch = *format++;
161         break;
162       case ' ':
163         flags |= DP_F_SPACE;
164         ch = *format++;
165         break;
166       case '#':
167         flags |= DP_F_NUM;
168         ch = *format++;
169         break;
170       case '0':
171         flags |= DP_F_ZERO;
172         ch = *format++;
173         break;
174       default:
175         state = DP_S_MIN;
176         break;
177       }
178       break;
179     case DP_S_MIN:
180       if (isdigit((unsigned char)ch)) {
181         min = 10*min + char_to_int (ch);
182         ch = *format++;
183       } else if (ch == '*') {
184         min = va_arg (args, int);
185         ch = *format++;
186         state = DP_S_DOT;
187       } else {
188         state = DP_S_DOT;
189       }
190       break;
191     case DP_S_DOT:
192       if (ch == '.') {
193         state = DP_S_MAX;
194         ch = *format++;
195       } else {
196         state = DP_S_MOD;
197       }
198       break;
199     case DP_S_MAX:
200       if (isdigit((unsigned char)ch)) {
201         if (max < 0)
202           max = 0;
203         max = 10*max + char_to_int (ch);
204         ch = *format++;
205       } else if (ch == '*') {
206         max = va_arg (args, int);
207         ch = *format++;
208         state = DP_S_MOD;
209       } else {
210         state = DP_S_MOD;
211       }
212       break;
213     case DP_S_MOD:
214       switch (ch) {
215       case 'h':
216         cflags = DP_C_SHORT;
217         ch = *format++;
218         break;
219       case 'l':
220         cflags = DP_C_LONG;
221         ch = *format++;
222         if (ch == 'l') {        /* It's a long long */
223           cflags = DP_C_LLONG;
224           ch = *format++;
225         }
226         break;
227       case 'L':
228         cflags = DP_C_LDOUBLE;
229         ch = *format++;
230         break;
231       default:
232         break;
233       }
234       state = DP_S_CONV;
235       break;
236     case DP_S_CONV:
237       switch (ch) {
238       case 'd':
239       case 'i':
240         if (cflags == DP_C_SHORT)
241           value = va_arg (args, int);
242         else if (cflags == DP_C_LONG)
243           value = va_arg (args, long int);
244         else if (cflags == DP_C_LLONG)
245           value = va_arg (args, LLONG);
246         else
247           value = va_arg (args, int);
248         fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
249         break;
250       case 'o':
251         flags |= DP_F_UNSIGNED;
252         if (cflags == DP_C_SHORT)
253           value = va_arg (args, unsigned int);
254         else if (cflags == DP_C_LONG)
255           value = (long)va_arg (args, unsigned long int);
256         else if (cflags == DP_C_LLONG)
257           value = (long)va_arg (args, unsigned LLONG);
258         else
259           value = (long)va_arg (args, unsigned int);
260         fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
261         break;
262       case 'u':
263         flags |= DP_F_UNSIGNED;
264         if (cflags == DP_C_SHORT)
265           value = va_arg (args, unsigned int);
266         else if (cflags == DP_C_LONG)
267           value = (long)va_arg (args, unsigned long int);
268         else if (cflags == DP_C_LLONG)
269           value = (LLONG)va_arg (args, unsigned LLONG);
270         else
271           value = (long)va_arg (args, unsigned int);
272         fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
273         break;
274       case 'X':
275         flags |= DP_F_UP;
276       case 'x':
277         flags |= DP_F_UNSIGNED;
278         if (cflags == DP_C_SHORT)
279           value = va_arg (args, unsigned int);
280         else if (cflags == DP_C_LONG)
281           value = (long)va_arg (args, unsigned long int);
282         else if (cflags == DP_C_LLONG)
283           value = (LLONG)va_arg (args, unsigned LLONG);
284         else
285           value = (long)va_arg (args, unsigned int);
286         fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
287         break;
288       case 'f':
289         if (cflags == DP_C_LDOUBLE)
290           fvalue = va_arg (args, LDOUBLE);
291         else
292           fvalue = va_arg (args, double);
293         /* um, floating point? */
294         fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
295         break;
296       case 'E':
297         flags |= DP_F_UP;
298       case 'e':
299         if (cflags == DP_C_LDOUBLE)
300           fvalue = va_arg (args, LDOUBLE);
301         else
302           fvalue = va_arg (args, double);
303         fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
304         break;
305       case 'G':
306         flags |= DP_F_UP;
307       case 'g':
308         if (cflags == DP_C_LDOUBLE)
309           fvalue = va_arg (args, LDOUBLE);
310         else
311           fvalue = va_arg (args, double);
312         fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
313         break;
314       case 'c':
315         dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
316         break;
317       case 's':
318         strvalue = va_arg (args, char *);
319         if (!strvalue) strvalue = "(NULL)";
320         if (max == -1) {
321           max = strlen(strvalue);
322         }
323         if (min > 0 && max >= 0 && min > max) max = min;
324         fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
325         break;
326       case 'p':
327         flags |= (DP_F_UNSIGNED | DP_F_HEXPREFIX);
328         strvalue = va_arg (args, void *);
329         fmtint (buffer, &currlen, maxlen, (long )strvalue, 16, min, max,
330                 flags);
331         break;
332       case 'n':
333         if (cflags == DP_C_SHORT) {
334           short int *num;
335           num = va_arg (args, short int *);
336           *num = currlen;
337         } else if (cflags == DP_C_LONG) {
338           long int *num;
339           num = va_arg (args, long int *);
340           *num = (long int)currlen;
341         } else if (cflags == DP_C_LLONG) {
342           LLONG *num;
343           num = va_arg (args, LLONG *);
344           *num = (LLONG)currlen;
345         } else {
346           int *num;
347           num = va_arg (args, int *);
348           *num = currlen;
349         }
350         break;
351       case '%':
352         dopr_outch (buffer, &currlen, maxlen, ch);
353         break;
354       case 'w':
355         /* not supported yet, treat as next char */
356         ch = *format++;
357         break;
358       case '@':
359         /* Renderer function */
360         render = va_arg (args, SilcSnprintfRender);
361         if (render) {
362           void *ptr = va_arg (args, void *);
363           if (ptr) {
364             strvalue = render (ptr);
365             if (strvalue) {
366               if (max == -1)
367                 max = strlen(strvalue);
368               if (min > 0 && max >= 0 && min > max) max = min;
369               fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
370               silc_free(strvalue);
371             }
372           }
373         }
374         break;
375       default:
376         /* Unknown, skip */
377         break;
378       }
379       ch = *format++;
380       state = DP_S_DEFAULT;
381       flags = cflags = min = 0;
382       max = -1;
383       break;
384     case DP_S_DONE:
385       break;
386     default:
387       /* hmm? */
388       break; /* some picky compilers need this */
389     }
390   }
391   if (maxlen != 0) {
392     if (currlen < maxlen - 1)
393       buffer[currlen] = '\0';
394     else if (maxlen > 0)
395       buffer[maxlen - 1] = '\0';
396   }
397
398   return currlen;
399 }
400
401 static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
402                     char *value, int flags, int min, int max)
403 {
404   int padlen, strln;     /* amount to pad */
405   int cnt = 0;
406
407   if (value == 0) {
408     value = "<NULL>";
409   }
410
411   for (strln = 0; value[strln]; ++strln); /* strlen */
412   padlen = min - strln;
413   if (padlen < 0)
414     padlen = 0;
415   if (flags & DP_F_MINUS)
416     padlen = -padlen; /* Left Justify */
417
418   while ((padlen > 0) && (cnt < max)) {
419     dopr_outch (buffer, currlen, maxlen, ' ');
420     --padlen;
421     ++cnt;
422   }
423   while (*value && (cnt < max)) {
424     dopr_outch (buffer, currlen, maxlen, *value++);
425     ++cnt;
426   }
427   while ((padlen < 0) && (cnt < max)) {
428     dopr_outch (buffer, currlen, maxlen, ' ');
429     ++padlen;
430     ++cnt;
431   }
432 }
433
434 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
435
436 static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
437                    long value, int base, int min, int max, int flags)
438 {
439   int signvalue = 0;
440   unsigned long uvalue;
441   char convert[20];
442   int place = 0;
443   int spadlen = 0; /* amount to space pad */
444   int zpadlen = 0; /* amount to zero pad */
445   int caps = 0;
446
447   if (max < 0)
448     max = 0;
449
450   uvalue = value;
451
452   if(!(flags & DP_F_UNSIGNED)) {
453     if( value < 0 ) {
454       signvalue = '-';
455       uvalue = -value;
456     } else {
457       if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
458         signvalue = '+';
459       else if (flags & DP_F_SPACE)
460         signvalue = ' ';
461     }
462   }
463
464   if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
465
466   do {
467     convert[place++] =
468       (caps? "0123456789ABCDEF":"0123456789abcdef")
469       [uvalue % (unsigned)base  ];
470     uvalue = (uvalue / (unsigned)base );
471   } while(uvalue && (place < 20));
472   if (place == 20) place--;
473   convert[place] = 0;
474
475   zpadlen = max - place;
476   spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
477   if (zpadlen < 0) zpadlen = 0;
478   if (spadlen < 0) spadlen = 0;
479   if (flags & DP_F_ZERO) {
480     zpadlen = MAX(zpadlen, spadlen);
481     spadlen = 0;
482   }
483   if (flags & DP_F_MINUS)
484     spadlen = -spadlen; /* Left Justifty */
485
486   /* Spaces */
487   while (spadlen > 0) {
488     dopr_outch (buffer, currlen, maxlen, ' ');
489     --spadlen;
490   }
491
492   /* 0x prefix */
493   if (flags & DP_F_HEXPREFIX) {
494     dopr_outch (buffer, currlen, maxlen, '0');
495     dopr_outch (buffer, currlen, maxlen, 'x');
496   }
497
498   /* Sign */
499   if (signvalue)
500     dopr_outch (buffer, currlen, maxlen, signvalue);
501
502   /* Zeros */
503   if (zpadlen > 0) {
504     while (zpadlen > 0) {
505       dopr_outch (buffer, currlen, maxlen, '0');
506       --zpadlen;
507     }
508   }
509
510   /* Digits */
511   while (place > 0)
512     dopr_outch (buffer, currlen, maxlen, convert[--place]);
513
514   /* Left Justified spaces */
515   while (spadlen < 0) {
516     dopr_outch (buffer, currlen, maxlen, ' ');
517     ++spadlen;
518   }
519 }
520
521 static LDOUBLE abs_val(LDOUBLE value)
522 {
523   LDOUBLE result = value;
524
525   if (value < 0)
526     result = -value;
527
528   return result;
529 }
530
531 static LDOUBLE POW10(int exp)
532 {
533   LDOUBLE result = 1;
534
535   while (exp) {
536     result *= 10;
537     exp--;
538   }
539
540   return result;
541 }
542
543 static LLONG ROUND(LDOUBLE value)
544 {
545   LLONG intpart;
546
547   intpart = (LLONG)value;
548   value = value - intpart;
549   if (value >= 0.5) intpart++;
550
551   return intpart;
552 }
553
554 /* a replacement for modf that doesn't need the math library. Should
555    be portable, but slow */
556 static double my_modf(double x0, double *iptr)
557 {
558   int i;
559   long l;
560   double x = x0;
561   double f = 1.0;
562
563   for (i=0;i<100;i++) {
564     l = (long)x;
565     if (l <= (x+1) && l >= (x-1)) break;
566     x *= 0.1;
567     f *= 10.0;
568   }
569
570   if (i == 100) {
571     /* yikes! the number is beyond what we can handle.
572        What do we do? */
573     (*iptr) = 0;
574     return 0;
575   }
576
577   if (i != 0) {
578     double i2;
579     double ret;
580
581     ret = my_modf(x0-l*f, &i2);
582     (*iptr) = l*f + i2;
583     return ret;
584   }
585
586   (*iptr) = l;
587   return x - (*iptr);
588 }
589
590
591 static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
592                    LDOUBLE fvalue, int min, int max, int flags)
593 {
594   int signvalue = 0;
595   double ufvalue;
596   char iconvert[311];
597   char fconvert[311];
598   int iplace = 0;
599   int fplace = 0;
600   int padlen = 0; /* amount to pad */
601   int zpadlen = 0;
602   int caps = 0;
603   int idx;
604   double intpart;
605   double fracpart;
606   double temp;
607
608   /*
609    * AIX manpage says the default is 0, but Solaris says the default
610    * is 6, and sprintf on AIX defaults to 6
611    */
612   if (max < 0)
613     max = 6;
614
615   ufvalue = abs_val (fvalue);
616
617   if (fvalue < 0) {
618     signvalue = '-';
619   } else {
620     if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
621       signvalue = '+';
622     } else {
623       if (flags & DP_F_SPACE)
624         signvalue = ' ';
625     }
626   }
627
628 #if 0
629   if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
630 #endif
631
632 #if 0
633   if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
634 #endif
635
636   /*
637    * Sorry, we only support 16 digits past the decimal because of our
638    * conversion method
639    */
640   if (max > 16)
641     max = 16;
642
643   /* We "cheat" by converting the fractional part to integer by
644    * multiplying by a factor of 10
645    */
646
647   temp = ufvalue;
648   my_modf(temp, &intpart);
649
650   fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
651
652   if (fracpart >= POW10(max)) {
653     intpart++;
654     fracpart -= POW10(max);
655   }
656
657
658   /* Convert integer part */
659   do {
660     temp = intpart*0.1;
661     my_modf(temp, &intpart);
662     idx = (int) ((temp -intpart +0.05)* 10.0);
663     /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
664     /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
665     iconvert[iplace++] =
666       (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
667   } while (intpart && (iplace < 311));
668   if (iplace == 311) iplace--;
669   iconvert[iplace] = 0;
670
671   /* Convert fractional part */
672   if (fracpart)
673     {
674       do {
675         temp = fracpart*0.1;
676         my_modf(temp, &fracpart);
677         idx = (int) ((temp -fracpart +0.05)* 10.0);
678         /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
679         /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
680         fconvert[fplace++] =
681           (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
682       } while(fracpart && (fplace < 311));
683       if (fplace == 311) fplace--;
684     }
685   fconvert[fplace] = 0;
686
687   /* -1 for decimal point, another -1 if we are printing a sign */
688   padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
689   zpadlen = max - fplace;
690   if (zpadlen < 0) zpadlen = 0;
691   if (padlen < 0)
692     padlen = 0;
693   if (flags & DP_F_MINUS)
694     padlen = -padlen; /* Left Justifty */
695
696   if ((flags & DP_F_ZERO) && (padlen > 0)) {
697     if (signvalue) {
698       dopr_outch (buffer, currlen, maxlen, signvalue);
699       --padlen;
700       signvalue = 0;
701     }
702     while (padlen > 0) {
703       dopr_outch (buffer, currlen, maxlen, '0');
704       --padlen;
705     }
706   }
707   while (padlen > 0) {
708     dopr_outch (buffer, currlen, maxlen, ' ');
709     --padlen;
710   }
711   if (signvalue)
712     dopr_outch (buffer, currlen, maxlen, signvalue);
713
714   while (iplace > 0)
715     dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
716
717   /*
718    * Decimal point.  This should probably use locale to find the correct
719    * char to print out.
720    */
721   if (max > 0) {
722     dopr_outch (buffer, currlen, maxlen, '.');
723
724     while (zpadlen > 0) {
725       dopr_outch (buffer, currlen, maxlen, '0');
726       --zpadlen;
727     }
728
729     while (fplace > 0)
730       dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
731   }
732
733   while (padlen < 0) {
734     dopr_outch (buffer, currlen, maxlen, ' ');
735     ++padlen;
736   }
737 }
738
739 static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
740 {
741   if (*currlen < maxlen) {
742     buffer[(*currlen)] = c;
743   }
744   (*currlen)++;
745 }
746
747 int silc_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
748 {
749   if (str != NULL)
750     str[0] = 0;
751   return dopr(str, count, fmt, args);
752 }
753
754 int silc_snprintf(char *str, size_t count, const char *fmt, ...)
755 {
756   size_t ret;
757   va_list ap;
758
759   va_start(ap, fmt);
760   ret = silc_vsnprintf(str, count, fmt, ap);
761   va_end(ap);
762   return ret;
763 }
764
765 int silc_vasprintf(char **ptr, const char *format, va_list ap)
766 {
767   int ret;
768   va_list ap2;
769
770   silc_va_copy(ap2, ap);
771
772   ret = silc_vsnprintf(NULL, 0, format, ap2);
773   if (ret <= 0) return ret;
774
775   (*ptr) = (char *)silc_malloc(ret+1);
776   if (!*ptr) return -1;
777
778   silc_va_copy(ap2, ap);
779
780   ret = silc_vsnprintf(*ptr, ret+1, format, ap2);
781
782   return ret;
783 }
784
785 int silc_asprintf(char **ptr, const char *format, ...)
786 {
787   va_list ap;
788   int ret;
789
790   *ptr = NULL;
791   va_start(ap, format);
792   ret = silc_vasprintf(ptr, format, ap);
793   va_end(ap);
794
795   return ret;
796 }