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 z t    ('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 writing 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() an 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.17 2019/11/15 21:03:14 christos 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#include <limits.h>
120#include <stddef.h>
121
122#define ALLOC_CHUNK 2048
123#define ALLOC_SECURITY_MARGIN 1024   /* big value because some platforms have very big 'G' exponent */
124#if ALLOC_CHUNK < ALLOC_SECURITY_MARGIN
125#    error  !!! ALLOC_CHUNK < ALLOC_SECURITY_MARGIN !!!
126#endif
127/* note: to have some interest, ALLOC_CHUNK should be much greater than ALLOC_SECURITY_MARGIN */
128
129/*
130 *  To save a lot of push/pop, every variable are stored into this
131 *  structure, which is passed among nearly every sub-functions.
132 */
133typedef struct {
134  const char * src_string;        /* current position into intput string */
135  char *       buffer_base;       /* output buffer */
136  char *       dest_string;       /* current position into output string */
137  size_t       buffer_len;        /* length of output buffer */
138  size_t       real_len;          /* real current length of output text */
139  size_t       pseudo_len;        /* total length of output text if it were not limited in size */
140  size_t       maxlen;
141  va_list      vargs;             /* pointer to current position into vargs */
142  char *       sprintf_string;
143  FILE *       fprintf_file;
144} xprintf_struct;
145
146/*
147 *  Realloc buffer if needed
148 *  Return value:  0 = ok
149 *               EOF = not enought memory
150 */
151static int realloc_buff(xprintf_struct *s, size_t len)
152{
153  char * ptr;
154
155  if (len + ALLOC_SECURITY_MARGIN + s->real_len > s->buffer_len) {
156    len += s->real_len + ALLOC_CHUNK;
157    ptr = (char *)realloc((void *)(s->buffer_base), len);
158    if (ptr == NULL) {
159      s->buffer_base = NULL;
160      return EOF;
161    }
162
163    s->dest_string = ptr + (size_t)(s->dest_string - s->buffer_base);
164    s->buffer_base = ptr;
165    s->buffer_len = len;
166
167    (s->buffer_base)[s->buffer_len - 1] = 1; /* overflow marker */
168  }
169
170  return 0;
171}
172
173/*
174 *  Prints 'usual' characters    up to next '%'
175 *                            or up to end of text
176 */
177static int usual_char(xprintf_struct * s)
178{
179  size_t len;
180
181  len = strcspn(s->src_string, "%");     /* reachs the next '%' or end of input string */
182  /* note: 'len' is never 0 because the presence of '%' */
183  /* or end-of-line is checked in the calling function  */
184
185  if (realloc_buff(s,len) == EOF)
186    return EOF;
187
188  memcpy(s->dest_string, s->src_string, len);
189  s->src_string += len;
190  s->dest_string += len;
191  s->real_len += len;
192  s->pseudo_len += len;
193
194  return 0;
195}
196
197/*
198 *  Return value: 0 = ok
199 *                EOF = error
200 */
201static int print_it(xprintf_struct *s, size_t approx_len,
202                    const char *format_string, ...)
203{
204  va_list varg;
205  int vsprintf_len;
206  size_t len;
207
208  if (realloc_buff(s,approx_len) == EOF)
209    return EOF;
210
211  va_start(varg, format_string);
212  vsprintf_len = vsprintf(s->dest_string, format_string, varg);
213  va_end(varg);
214
215  /* Check for overflow */
216  assert((s->buffer_base)[s->buffer_len - 1] == 1);
217
218  if (vsprintf_len == EOF) /* must be done *after* overflow-check */
219    return EOF;
220
221  s->pseudo_len += vsprintf_len;
222  len = strlen(s->dest_string);
223  s->real_len += len;
224  s->dest_string += len;
225
226  return 0;
227}
228
229/*
230 *  Prints a string (%s)
231 *  We need special handling because:
232 *     a: the length of the string is unknown
233 *     b: when .prec is used, we must not access any extra byte of the
234 *        string (of course, if the original sprintf() does... what the
235 *        hell, not my problem)
236 *
237 *  Return value: 0 = ok
238 *                EOF = error
239 */
240static int type_s(xprintf_struct *s, int width, int prec,
241                  const char *format_string, const char *arg_string)
242{
243  size_t string_len;
244
245  if (arg_string == NULL)
246    return print_it(s, (size_t)6, "(null)", 0);
247
248  /* hand-made strlen() whitch stops when 'prec' is reached. */
249  /* if 'prec' is -1 then it is never reached. */
250  string_len = 0;
251  while (arg_string[string_len] != 0 && (size_t)prec != string_len)
252    string_len++;
253
254  if (width != -1 && string_len < (size_t)width)
255    string_len = (size_t)width;
256
257  return print_it(s, string_len, format_string, arg_string);
258}
259
260/*
261 *  Read a serie of digits. Stop when non-digit is found.
262 *  Return value: the value read (between 0 and 32767).
263 *  Note: no checks are made against overflow. If the string contain a big
264 *  number, then the return value won't be what we want (but, in this case,
265 *  the programmer don't know whatr he wants, then no problem).
266 */
267static int getint(const char **string)
268{
269  int i = 0;
270
271  while (isdigit((unsigned char)**string) != 0) {
272    i = i * 10 + (**string - '0');
273    (*string)++;
274  }
275
276  if (i < 0 || i > 32767)
277    i = 32767; /* if we have i==-10 this is not because the number is */
278  /* negative; this is because the number is big */
279  return i;
280}
281
282/*
283 *  Read a part of the format string. A part is 'usual characters' (ie "blabla")
284 *  or '%%' escape sequence (to print a single '%') or any combination of
285 *  format specifier (ie "%i" or "%10.2d").
286 *  After the current part is managed, the function returns to caller with
287 *  everything ready to manage the following part.
288 *  The caller must ensure than the string is not empty, i.e. the first byte
289 *  is not zero.
290 *
291 *  Return value:  0 = ok
292 *                 EOF = error
293 */
294static int dispatch(xprintf_struct *s)
295{
296  const char *initial_ptr;
297  char format_string[24]; /* max length may be something like  "% +-#032768.32768Ld" */
298  char *format_ptr;
299  int flag_plus, flag_minus, flag_space, flag_sharp, flag_zero;
300  int width, prec, modifier, approx_width;
301  char type;
302  /* most of those variables are here to rewrite the format string */
303
304#define SRCTXT  (s->src_string)
305#define DESTTXT (s->dest_string)
306
307  /* incoherent format string. Characters after the '%' will be printed with the next call */
308#define INCOHERENT()         do {SRCTXT=initial_ptr; return 0;} while (0)     /* do/while to avoid */
309#define INCOHERENT_TEST()    do {if(*SRCTXT==0)   INCOHERENT();} while (0)    /* a null statement  */
310
311  /* 'normal' text */
312  if (*SRCTXT != '%')
313    return usual_char(s);
314
315  /* we then have a '%' */
316  SRCTXT++;
317  /* don't check for end-of-string ; this is done later */
318
319  /* '%%' escape sequence */
320  if (*SRCTXT == '%') {
321    if (realloc_buff(s, (size_t)1) == EOF) /* because we can have "%%%%%%%%..." */
322      return EOF;
323    *DESTTXT = '%';
324    DESTTXT++;
325    SRCTXT++;
326    (s->real_len)++;
327    (s->pseudo_len)++;
328    return 0;
329  }
330
331  /* '%' managing */
332  initial_ptr = SRCTXT;   /* save current pointer in case of incorrect */
333  /* 'decoding'. Points just after the '%' so the '%' */
334  /* won't be printed in any case, as required. */
335
336  /* flag */
337  flag_plus = flag_minus = flag_space = flag_sharp = flag_zero = 0;
338
339  for (;; SRCTXT++) {
340    if (*SRCTXT == ' ')
341      flag_space = 1;
342    else if (*SRCTXT == '+')
343      flag_plus = 1;
344    else if (*SRCTXT == '-')
345      flag_minus = 1;
346    else if (*SRCTXT == '#')
347      flag_sharp = 1;
348    else if (*SRCTXT == '0')
349      flag_zero = 1;
350    else
351      break;
352  }
353
354  INCOHERENT_TEST();    /* here is the first test for end of string */
355
356  /* width */
357  if (*SRCTXT == '*') {         /* width given by next argument */
358    SRCTXT++;
359    width = va_arg(s->vargs, int);
360    if ((size_t)width > 0x3fffU) /* 'size_t' to check against negative values too */
361      width = 0x3fff;
362  } else if (isdigit((unsigned char)*SRCTXT)) /* width given as ASCII number */
363    width = getint(&SRCTXT);
364  else
365    width = -1;                 /* no width specified */
366
367  INCOHERENT_TEST();
368
369  /* .prec */
370  if (*SRCTXT == '.') {
371    SRCTXT++;
372    if (*SRCTXT == '*') {       /* .prec given by next argument */
373      SRCTXT++;
374      prec = va_arg(s->vargs, int);
375      if ((size_t)prec >= 0x3fffU) /* 'size_t' to check against negative values too */
376        prec = 0x3fff;
377    } else {                    /* .prec given as ASCII number */
378      if (isdigit((unsigned char)*SRCTXT) == 0)
379        INCOHERENT();
380      prec = getint(&SRCTXT);
381    }
382    INCOHERENT_TEST();
383  } else
384    prec = -1;                  /* no .prec specified */
385
386  /* modifier */
387  switch (*SRCTXT) {
388  case 'L':
389  case 'h':
390  case 'l':
391  case 'z':
392  case 't':
393    modifier = *SRCTXT;
394    SRCTXT++;
395    if (modifier=='l' && *SRCTXT=='l') {
396      SRCTXT++;
397      modifier = 'L';  /* 'll' == 'L'      long long == long double */
398    } /* only for compatibility ; not portable */
399    INCOHERENT_TEST();
400    break;
401  default:
402    modifier = -1;              /* no modifier specified */
403    break;
404  }
405
406  /* type */
407  type = *SRCTXT;
408  if (strchr("diouxXfegEGcspn",type) == NULL)
409    INCOHERENT();               /* unknown type */
410  SRCTXT++;
411
412  /* rewrite format-string */
413  format_string[0] = '%';
414  format_ptr = &(format_string[1]);
415
416  if (flag_plus) {
417    *format_ptr = '+';
418    format_ptr++;
419  }
420  if (flag_minus) {
421    *format_ptr = '-';
422    format_ptr++;
423  }
424  if (flag_space) {
425    *format_ptr = ' ';
426    format_ptr++;
427  }
428  if (flag_sharp) {
429    *format_ptr = '#';
430    format_ptr++;
431  }
432  if (flag_zero) {
433    *format_ptr = '0';
434    format_ptr++;
435  } /* '0' *must* be the last one */
436
437  if (width != -1) {
438    sprintf(format_ptr, "%i", width);
439    format_ptr += strlen(format_ptr);
440  }
441
442  if (prec != -1) {
443    *format_ptr = '.';
444    format_ptr++;
445    sprintf(format_ptr, "%i", prec);
446    format_ptr += strlen(format_ptr);
447  }
448
449  if (modifier != -1) {
450    if (modifier == 'L' && strchr("diouxX",type) != NULL) {
451      *format_ptr = 'l';
452      format_ptr++;
453      *format_ptr = 'l';
454      format_ptr++;
455    } else {
456      *format_ptr = modifier;
457      format_ptr++;
458    }
459  }
460
461  *format_ptr = type;
462  format_ptr++;
463  *format_ptr = 0;
464
465  /* vague approximation of minimal length if width or prec are specified */
466  approx_width = width + prec;
467  if (approx_width < 0) /* because width == -1 and/or prec == -1 */
468    approx_width = 0;
469
470  switch (type) {
471    /* int */
472  case 'd':
473  case 'i':
474  case 'o':
475  case 'u':
476  case 'x':
477  case 'X':
478    switch (modifier) {
479    case -1 :
480      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
481    case 'L':
482      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long long int));
483    case 'l':
484      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long int));
485    case 'h':
486      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
487    case 'z':
488      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, size_t));
489    case 't':
490      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, ptrdiff_t));
491      /* 'int' instead of 'short int' because default promotion is 'int' */
492    default:
493      INCOHERENT();
494    }
495
496    /* char */
497  case 'c':
498    if (modifier != -1)
499      INCOHERENT();
500    return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
501    /* 'int' instead of 'char' because default promotion is 'int' */
502
503    /* math */
504  case 'e':
505  case 'f':
506  case 'g':
507  case 'E':
508  case 'G':
509    switch (modifier) {
510    case -1 : /* because of default promotion, no modifier means 'l' */
511    case 'l':
512      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, double));
513    case 'L':
514      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long double));
515    default:
516      INCOHERENT();
517    }
518
519    /* string */
520  case 's':
521    return type_s(s, width, prec, format_string, va_arg(s->vargs, const char*));
522
523    /* pointer */
524  case 'p':
525    if (modifier == -1)
526      return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, void *));
527    INCOHERENT();
528
529    /* store */
530  case 'n':
531    if (modifier == -1) {
532      int * p;
533      p = va_arg(s->vargs, int *);
534      if (p != NULL) {
535        *p = s->pseudo_len;
536        return 0;
537      }
538      return EOF;
539    }
540    INCOHERENT();
541
542  } /* switch */
543
544  INCOHERENT();                 /* unknown type */
545
546#undef INCOHERENT
547#undef INCOHERENT_TEST
548#undef SRCTXT
549#undef DESTTXT
550}
551
552/*
553 *  Return value: number of *virtually* written characters
554 *                EOF = error
555 */
556static int core(xprintf_struct *s)
557{
558  size_t save_len;
559  char *dummy_base;
560
561  /* basic checks */
562  if ((int)(s->maxlen) <= 0) /* 'int' to check against some conversion */
563    return EOF;           /* error for example if value is (int)-10 */
564  s->maxlen--;      /* because initial maxlen counts final 0 */
565  /* note: now 'maxlen' _can_ be zero */
566
567  if (s->src_string == NULL)
568    s->src_string = "(null)";
569
570  /* struct init and memory allocation */
571  s->buffer_base = NULL;
572  s->buffer_len = 0;
573  s->real_len = 0;
574  s->pseudo_len = 0;
575  if (realloc_buff(s, (size_t)0) == EOF)
576    return EOF;
577  s->dest_string = s->buffer_base;
578
579  /* process source string */
580  for (;;) {
581    /* up to end of source string */
582    if (*(s->src_string) == 0) {
583      *(s->dest_string) = '\0';    /* final NUL */
584      break;
585    }
586
587    if (dispatch(s) == EOF)
588      goto free_EOF;
589
590    /* up to end of dest string */
591    if (s->real_len >= s->maxlen) {
592      (s->buffer_base)[s->maxlen] = '\0'; /* final NUL */
593      break;
594    }
595  }
596
597  /* for (v)asnprintf */
598  dummy_base = s->buffer_base;
599
600  dummy_base = s->buffer_base + s->real_len;
601  save_len = s->real_len;
602
603  /* process the remaining of source string to compute 'pseudo_len'. We
604   * overwrite again and again, starting at 'dummy_base' because we don't
605   * need the text, only char count. */
606  while(*(s->src_string) != 0) { /* up to end of source string */
607    s->real_len = 0;
608    s->dest_string = dummy_base;
609    if (dispatch(s) == EOF)
610      goto free_EOF;
611  }
612
613  s->buffer_base = (char *)realloc((void *)(s->buffer_base), save_len + 1);
614  if (s->buffer_base == NULL)
615    return EOF; /* should rarely happen because we shrink the buffer */
616  return s->pseudo_len;
617
618 free_EOF:
619  free(s->buffer_base);
620  return EOF;
621}
622
623int vasprintf(char **ptr, const char *format_string, va_list vargs)
624{
625  xprintf_struct s;
626  int retval;
627
628  s.src_string = format_string;
629#ifdef va_copy
630  va_copy (s.vargs, vargs);
631#else
632# ifdef __va_copy
633  __va_copy (s.vargs, vargs);
634# else
635#  ifdef WIN32
636  s.vargs = vargs;
637#  else
638  memcpy (&s.vargs, &vargs, sizeof (s.va_args));
639#  endif /* WIN32 */
640# endif /* __va_copy */
641#endif /* va_copy */
642  s.maxlen = (size_t)INT_MAX;
643
644  retval = core(&s);
645  va_end(s.vargs);
646  if (retval == EOF) {
647    *ptr = NULL;
648    return EOF;
649  }
650
651  *ptr = s.buffer_base;
652  return retval;
653}
654