1/*
2 * Copyright (c) Ian F. Darwin 1986-1995.
3 * Software written by Ian F. Darwin and others;
4 * maintained 1995-present by Christos Zoulas and others.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice immediately at the beginning of the file, without modification,
11 *    this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28/*###########################################################################
29  #                                                                           #
30  #                                vasprintf                                  #
31  #                                                                           #
32  #               Copyright (c) 2002-2005 David TAILLANDIER                   #
33  #                                                                           #
34  ###########################################################################*/
35
36/*
37
38This software is distributed under the "modified BSD licence".
39
40This software is also released with GNU license (GPL) in another file (same
41source-code, only license differ).
42
43
44
45Redistribution and use in source and binary forms, with or without
46modification, are permitted provided that the following conditions are met:
47
48Redistributions of source code must retain the above copyright notice, this
49list of conditions and the following disclaimer. Redistributions in binary
50form must reproduce the above copyright notice, this list of conditions and
51the following disclaimer in the documentation and/or other materials
52provided with the distribution. The name of the author may not be used to
53endorse or promote products derived from this software without specific
54prior written permission.
55
56THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
57WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
58MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
59EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
60SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
61PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
62OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
63WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
64OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
65ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66
67====================
68
69Hacked from xnprintf version of 26th February 2005 to provide only
70vasprintf by Reuben Thomas <rrt@sc3d.org>.
71
72====================
73
74
75'printf' function family use the following format string:
76
77%[flag][width][.prec][modifier]type
78
79%% is the escape sequence to print a '%'
80%  followed by an unknown format will print the characters without
81trying to do any interpretation
82
83flag:   none   +     -     #     (blank)
84width:  n    0n    *
85prec:   none   .0    .n     .*
86modifier:    F N L h l ll    ('F' and 'N' are ms-dos/16-bit specific)
87type:  d i o u x X f e g E G c s p n
88
89
90The function needs to allocate memory to store the full text before to
91actually writting it.  i.e if you want to fnprintf() 1000 characters, the
92functions will allocate 1000 bytes.
93This behaviour can be modified: you have to customise the code to flush the
94internal buffer (writing to screen or file) when it reach a given size. Then
95the buffer can have a shorter length. But what? If you really need to write
96HUGE string, don't use printf!
97During the process, some other memory is allocated (1024 bytes minimum)
98to handle the output of partial sprintf() calls. If you have only 10000 bytes
99free in memory, you *may* not be able to nprintf() a 8000 bytes-long text.
100
101note: if a buffer overflow occurs, exit() is called. This situation should
102never appear ... but if you want to be *really* sure, you have to modify the
103code to handle those situations (only one place to modify).
104A buffer overflow can only occur if your sprintf() do strange things or when
105you use strange formats.
106
107*/
108#include "file.h"
109
110#ifndef	lint
111FILE_RCSID("@(#)$File: vasprintf.c,v 1.8 2011/12/08 12:38:24 rrt Exp $")
112#endif	/* lint */
113
114#include <assert.h>
115#include <string.h>
116#include <stdlib.h>
117#include <stdarg.h>
118#include <ctype.h>
119#ifdef HAVE_LIMITS_H
120#include <limits.h>
121#endif
122
123#define ALLOC_CHUNK 2048
124#define ALLOC_SECURITY_MARGIN 1024   /* big value because some platforms have very big 'G' exponent */
125#if ALLOC_CHUNK < ALLOC_SECURITY_MARGIN
126#    error  !!! ALLOC_CHUNK < ALLOC_SECURITY_MARGIN !!!
127#endif
128/* note: to have some interest, ALLOC_CHUNK should be much greater than ALLOC_SECURITY_MARGIN */
129
130/*
131 *  To save a lot of push/pop, every variable are stored into this
132 *  structure, which is passed among nearly every sub-functions.
133 */
134typedef struct {
135  const char * src_string;        /* current position into intput string */
136  char *       buffer_base;       /* output buffer */
137  char *       dest_string;       /* current position into output string */
138  size_t       buffer_len;        /* length of output buffer */
139  size_t       real_len;          /* real current length of output text */
140  size_t       pseudo_len;        /* total length of output text if it were not limited in size */
141  size_t       maxlen;
142  va_list      vargs;             /* pointer to current position into vargs */
143  char *       sprintf_string;
144  FILE *       fprintf_file;
145} xprintf_struct;
146
147/*
148 *  Realloc buffer if needed
149 *  Return value:  0 = ok
150 *               EOF = not enought memory
151 */
152static int realloc_buff(xprintf_struct *s, size_t len)
153{
154  char * ptr;
155
156  if (len + ALLOC_SECURITY_MARGIN + s->real_len > s->buffer_len) {
157    len += s->real_len + ALLOC_CHUNK;
158    ptr = (char *)realloc((void *)(s->buffer_base), len);
159    if (ptr == NULL) {
160      s->buffer_base = NULL;
161      return EOF;
162    }
163
164    s->dest_string = ptr + (size_t)(s->dest_string - s->buffer_base);
165    s->buffer_base = ptr;
166    s->buffer_len = len;
167
168    (s->buffer_base)[s->buffer_len - 1] = 1; /* overflow marker */
169  }
170
171  return 0;
172}
173
174/*
175 *  Prints 'usual' characters    up to next '%'
176 *                            or up to end of text
177 */
178static int usual_char(xprintf_struct * s)
179{
180  size_t len;
181
182  len = strcspn(s->src_string, "%");     /* reachs the next '%' or end of input string */
183  /* note: 'len' is never 0 because the presence of '%' */
184  /* or end-of-line is checked in the calling function  */
185
186  if (realloc_buff(s,len) == EOF)
187    return EOF;
188
189  memcpy(s->dest_string, s->src_string, len);
190  s->src_string += len;
191  s->dest_string += len;
192  s->real_len += len;
193  s->pseudo_len += len;
194
195  return 0;
196}
197
198/*
199 *  Return value: 0 = ok
200 *                EOF = error
201 */
202static int print_it(xprintf_struct *s, size_t approx_len,
203                    const char *format_string, ...)
204{
205  va_list varg;
206  int vsprintf_len;
207  size_t len;
208
209  if (realloc_buff(s,approx_len) == EOF)
210    return EOF;
211
212  va_start(varg, format_string);
213  vsprintf_len = vsprintf(s->dest_string, format_string, varg);
214  va_end(varg);
215
216  /* Check for overflow */
217  assert((s->buffer_base)[s->buffer_len - 1] == 1);
218
219  if (vsprintf_len == EOF) /* must be done *after* overflow-check */
220    return EOF;
221
222  s->pseudo_len += vsprintf_len;
223  len = strlen(s->dest_string);
224  s->real_len += len;
225  s->dest_string += len;
226
227  return 0;
228}
229
230/*
231 *  Prints a string (%s)
232 *  We need special handling because:
233 *     a: the length of the string is unknown
234 *     b: when .prec is used, we must not access any extra byte of the
235 *        string (of course, if the original sprintf() does... what the
236 *        hell, not my problem)
237 *
238 *  Return value: 0 = ok
239 *                EOF = error
240 */
241static int type_s(xprintf_struct *s, int width, int prec,
242                  const char *format_string, const char *arg_string)
243{
244  size_t string_len;
245
246  if (arg_string == NULL)
247    return print_it(s, (size_t)6, "(null)", 0);
248
249  /* hand-made strlen() whitch stops when 'prec' is reached. */
250  /* if 'prec' is -1 then it is never reached. */
251  string_len = 0;
252  while (arg_string[string_len] != 0 && (size_t)prec != string_len)
253    string_len++;
254
255  if (width != -1 && string_len < (size_t)width)
256    string_len = (size_t)width;
257
258  return print_it(s, string_len, format_string, arg_string);
259}
260
261/*
262 *  Read a serie of digits. Stop when non-digit is found.
263 *  Return value: the value read (between 0 and 32767).
264 *  Note: no checks are made against overflow. If the string contain a big
265 *  number, then the return value won't be what we want (but, in this case,
266 *  the programmer don't know whatr he wants, then no problem).
267 */
268static int getint(const char **string)
269{
270  int i = 0;
271
272  while (isdigit((unsigned char)**string) != 0) {
273    i = i * 10 + (**string - '0');
274    (*string)++;
275  }
276
277  if (i < 0 || i > 32767)
278    i = 32767; /* if we have i==-10 this is not because the number is */
279  /* negative; this is because the number is big */
280  return i;
281}
282
283/*
284 *  Read a part of the format string. A part is 'usual characters' (ie "blabla")
285 *  or '%%' escape sequence (to print a single '%') or any combination of
286 *  format specifier (ie "%i" or "%10.2d").
287 *  After the current part is managed, the function returns to caller with
288 *  everything ready to manage the following part.
289 *  The caller must ensure than the string is not empty, i.e. the first byte
290 *  is not zero.
291 *
292 *  Return value:  0 = ok
293 *                 EOF = error
294 */
295static int dispatch(xprintf_struct *s)
296{
297  const char *initial_ptr;
298  char format_string[24]; /* max length may be something like  "% +-#032768.32768Ld" */
299  char *format_ptr;
300  int flag_plus, flag_minus, flag_space, flag_sharp, flag_zero;
301  int width, prec, modifier, approx_width;
302  char type;
303  /* most of those variables are here to rewrite the format string */
304
305#define SRCTXT  (s->src_string)
306#define DESTTXT (s->dest_string)
307
308  /* incoherent format string. Characters after the '%' will be printed with the next call */
309#define INCOHERENT()         do {SRCTXT=initial_ptr; return 0;} while (0)     /* do/while to avoid */
310#define INCOHERENT_TEST()    do {if(*SRCTXT==0)   INCOHERENT();} while (0)    /* a null statement  */
311
312  /* 'normal' text */
313  if (*SRCTXT != '%')
314    return usual_char(s);
315
316  /* we then have a '%' */
317  SRCTXT++;
318  /* don't check for end-of-string ; this is done later */
319
320  /* '%%' escape sequence */
321  if (*SRCTXT == '%') {
322    if (realloc_buff(s, (size_t)1) == EOF) /* because we can have "%%%%%%%%..." */
323      return EOF;
324    *DESTTXT = '%';
325    DESTTXT++;
326    SRCTXT++;
327    (s->real_len)++;
328    (s->pseudo_len)++;
329    return 0;
330  }
331
332  /* '%' managing */
333  initial_ptr = SRCTXT;   /* save current pointer in case of incorrect */
334  /* 'decoding'. Points just after the '%' so the '%' */
335  /* won't be printed in any case, as required. */
336
337  /* flag */
338  flag_plus = flag_minus = flag_space = flag_sharp = flag_zero = 0;
339
340  for (;; SRCTXT++) {
341    if (*SRCTXT == ' ')
342      flag_space = 1;
343    else if (*SRCTXT == '+')
344      flag_plus = 1;
345    else if (*SRCTXT == '-')
346      flag_minus = 1;
347    else if (*SRCTXT == '#')
348      flag_sharp = 1;
349    else if (*SRCTXT == '0')
350      flag_zero = 1;
351    else
352      break;
353  }
354
355  INCOHERENT_TEST();    /* here is the first test for end of string */
356
357  /* width */
358  if (*SRCTXT == '*') {         /* width given by next argument */
359    SRCTXT++;
360    width = va_arg(s->vargs, int);
361    if ((size_t)width > 0x3fffU) /* 'size_t' to check against negative values too */
362      width = 0x3fff;
363  } else if (isdigit((unsigned char)*SRCTXT)) /* width given as ASCII number */
364    width = getint(&SRCTXT);
365  else
366    width = -1;                 /* no width specified */
367
368  INCOHERENT_TEST();
369
370  /* .prec */
371  if (*SRCTXT == '.') {
372    SRCTXT++;
373    if (*SRCTXT == '*') {       /* .prec given by next argument */
374      SRCTXT++;
375      prec = va_arg(s->vargs, int);
376      if ((size_t)prec >= 0x3fffU) /* 'size_t' to check against negative values too */
377        prec = 0x3fff;
378    } else {                    /* .prec given as ASCII number */
379      if (isdigit((unsigned char)*SRCTXT) == 0)
380        INCOHERENT();
381      prec = getint(&SRCTXT);
382    }
383    INCOHERENT_TEST();
384  } else
385    prec = -1;                  /* no .prec specified */
386
387  /* modifier */
388  if (*SRCTXT == 'L' || *SRCTXT == 'h' || *SRCTXT == 'l') {
389    modifier = *SRCTXT;
390    SRCTXT++;
391    if (modifier=='l' && *SRCTXT=='l') {
392      SRCTXT++;
393      modifier = 'L';  /* 'll' == 'L'      long long == long double */
394    } /* only for compatibility ; not portable */
395    INCOHERENT_TEST();
396  } else
397    modifier = -1;              /* no modifier specified */
398
399  /* type */
400  type = *SRCTXT;
401  if (strchr("diouxXfegEGcspn",type) == NULL)
402    INCOHERENT();               /* unknown type */
403  SRCTXT++;
404
405  /* rewrite format-string */
406  format_string[0] = '%';
407  format_ptr = &(format_string[1]);
408
409  if (flag_plus) {
410    *format_ptr = '+';
411    format_ptr++;
412  }
413  if (flag_minus) {
414    *format_ptr = '-';
415    format_ptr++;
416  }
417  if (flag_space) {
418    *format_ptr = ' ';
419    format_ptr++;
420  }
421  if (flag_sharp) {
422    *format_ptr = '#';
423    format_ptr++;
424  }
425  if (flag_zero) {
426    *format_ptr = '0';
427    format_ptr++;
428  } /* '0' *must* be the last one */
429
430  if (width != -1) {
431    sprintf(format_ptr, "%i", width);
432    format_ptr += strlen(format_ptr);
433  }
434
435  if (prec != -1) {
436    *format_ptr = '.';
437    format_ptr++;
438    sprintf(format_ptr, "%i", prec);
439    format_ptr += strlen(format_ptr);
440  }
441
442  if (modifier != -1) {
443    if (modifier == 'L' && strchr("diouxX",type) != NULL) {
444      *format_ptr = 'l';
445      format_ptr++;
446      *format_ptr = 'l';
447      format_ptr++;
448    } else {
449      *format_ptr = modifier;
450      format_ptr++;
451    }
452  }
453
454  *format_ptr = type;
455  format_ptr++;
456  *format_ptr = 0;
457
458  /* vague approximation of minimal length if width or prec are specified */
459  approx_width = width + prec;
460  if (approx_width < 0) /* because width == -1 and/or prec == -1 */
461    approx_width = 0;
462
463  switch (type) {
464    /* int */
465  case 'd':
466  case 'i':
467  case 'o':
468  case 'u':
469  case 'x':
470  case 'X':
471    switch (modifier) {
472    case -1 :
473      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
474    case 'L':
475      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long long int));
476    case 'l':
477      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long int));
478    case 'h':
479      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
480      /* 'int' instead of 'short int' because default promotion is 'int' */
481    default:
482      INCOHERENT();
483    }
484
485    /* char */
486  case 'c':
487    if (modifier != -1)
488      INCOHERENT();
489    return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
490    /* 'int' instead of 'char' because default promotion is 'int' */
491
492    /* math */
493  case 'e':
494  case 'f':
495  case 'g':
496  case 'E':
497  case 'G':
498    switch (modifier) {
499    case -1 : /* because of default promotion, no modifier means 'l' */
500    case 'l':
501      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, double));
502    case 'L':
503      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long double));
504    default:
505      INCOHERENT();
506    }
507
508    /* string */
509  case 's':
510    return type_s(s, width, prec, format_string, va_arg(s->vargs, const char*));
511
512    /* pointer */
513  case 'p':
514    if (modifier == -1)
515      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, void *));
516    INCOHERENT();
517
518    /* store */
519  case 'n':
520    if (modifier == -1) {
521      int * p;
522      p = va_arg(s->vargs, int *);
523      if (p != NULL) {
524        *p = s->pseudo_len;
525        return 0;
526      }
527      return EOF;
528    }
529    INCOHERENT();
530
531  } /* switch */
532
533  INCOHERENT();                 /* unknown type */
534
535#undef INCOHERENT
536#undef INCOHERENT_TEST
537#undef SRCTXT
538#undef DESTTXT
539}
540
541/*
542 *  Return value: number of *virtually* written characters
543 *                EOF = error
544 */
545static int core(xprintf_struct *s)
546{
547  size_t len, save_len;
548  char *dummy_base;
549
550  /* basic checks */
551  if ((int)(s->maxlen) <= 0) /* 'int' to check against some conversion */
552    return EOF;           /* error for example if value is (int)-10 */
553  s->maxlen--;      /* because initial maxlen counts final 0 */
554  /* note: now 'maxlen' _can_ be zero */
555
556  if (s->src_string == NULL)
557    s->src_string = "(null)";
558
559  /* struct init and memory allocation */
560  s->buffer_base = NULL;
561  s->buffer_len = 0;
562  s->real_len = 0;
563  s->pseudo_len = 0;
564  if (realloc_buff(s, (size_t)0) == EOF)
565    return EOF;
566  s->dest_string = s->buffer_base;
567
568  /* process source string */
569  for (;;) {
570    /* up to end of source string */
571    if (*(s->src_string) == 0) {
572      *(s->dest_string) = 0;    /* final 0 */
573      len = s->real_len + 1;
574      break;
575    }
576
577    if (dispatch(s) == EOF)
578      goto free_EOF;
579
580    /* up to end of dest string */
581    if (s->real_len >= s->maxlen) {
582      (s->buffer_base)[s->maxlen] = 0; /* final 0 */
583      len = s->maxlen + 1;
584      break;
585    }
586  }
587
588  /* for (v)asnprintf */
589  dummy_base = s->buffer_base;
590  save_len = 0;                 /* just to avoid a compiler warning */
591
592  dummy_base = s->buffer_base + s->real_len;
593  save_len = s->real_len;
594
595  /* process the remaining of source string to compute 'pseudo_len'. We
596   * overwrite again and again, starting at 'dummy_base' because we don't
597   * need the text, only char count. */
598  while(*(s->src_string) != 0) { /* up to end of source string */
599    s->real_len = 0;
600    s->dest_string = dummy_base;
601    if (dispatch(s) == EOF)
602      goto free_EOF;
603  }
604
605  s->buffer_base = (char *)realloc((void *)(s->buffer_base), save_len + 1);
606  if (s->buffer_base == NULL)
607    return EOF; /* should rarely happen because we shrink the buffer */
608  return s->pseudo_len;
609
610 free_EOF:
611  free(s->buffer_base);
612  return EOF;
613}
614
615int vasprintf(char **ptr, const char *format_string, va_list vargs)
616{
617  xprintf_struct s;
618  int retval;
619
620  s.src_string = format_string;
621#ifdef va_copy
622  va_copy (s.vargs, vargs);
623#else
624#ifdef __va_copy
625  __va_copy (s.vargs, vargs);
626#else
627  memcpy (&s.vargs, vargs, sizeof (va_list));
628#endif /* __va_copy */
629#endif /* va_copy */
630  s.maxlen = (size_t)INT_MAX;
631
632  retval = core(&s);
633  va_end(s.vargs);
634  if (retval == EOF) {
635    *ptr = NULL;
636    return EOF;
637  }
638
639  *ptr = s.buffer_base;
640  return retval;
641}
642