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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
28 /*###########################################################################
32 # Copyright (c) 2002-2005 David TAILLANDIER #
34 ###########################################################################*/
38 This software is distributed under the "modified BSD licence".
40 This software is also released with GNU license (GPL) in another file (same
41 source-code, only license differ).
45 Redistribution and use in source and binary forms, with or without
46 modification, are permitted provided that the following conditions are met:
48 Redistributions of source code must retain the above copyright notice, this
49 list of conditions and the following disclaimer. Redistributions in binary
50 form must reproduce the above copyright notice, this list of conditions and
51 the following disclaimer in the documentation and/or other materials
52 provided with the distribution. The name of the author may not be used to
53 endorse or promote products derived from this software without specific
54 prior written permission.
56 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
57 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
58 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
59 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
60 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
61 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
62 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
63 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
64 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
65 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 Hacked from xnprintf version of 26th February 2005 to provide only
70 vasprintf by Reuben Thomas <rrt@sc3d.org>.
75 'printf' function family use the following format string:
77 %[flag][width][.prec][modifier]type
79 %% is the escape sequence to print a '%'
80 % followed by an unknown format will print the characters without
81 trying to do any interpretation
83 flag: none + - # (blank)
86 modifier: F N L h l ll ('F' and 'N' are ms-dos/16-bit specific)
87 type: d i o u x X f e g E G c s p n
90 The function needs to allocate memory to store the full text before to
91 actually writting it. i.e if you want to fnprintf() 1000 characters, the
92 functions will allocate 1000 bytes.
93 This behaviour can be modified: you have to customise the code to flush the
94 internal buffer (writing to screen or file) when it reach a given size. Then
95 the buffer can have a shorter length. But what? If you really need to write
96 HUGE string, don't use printf!
97 During the process, some other memory is allocated (1024 bytes minimum)
98 to handle the output of partial sprintf() calls. If you have only 10000 bytes
99 free in memory, you *may* not be able to nprintf() a 8000 bytes-long text.
101 note: if a buffer overflow occurs, exit() is called. This situation should
102 never appear ... but if you want to be *really* sure, you have to modify the
103 code to handle those situations (only one place to modify).
104 A buffer overflow can only occur if your sprintf() do strange things or when
105 you use strange formats.
111 FILE_RCSID("@(#)$File: vasprintf.c,v 1.7 2009/02/03 20:27:52 christos Exp $")
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 !!!
128 /* note: to have some interest, ALLOC_CHUNK should be much greater than ALLOC_SECURITY_MARGIN */
131 * To save a lot of push/pop, every variable are stored into this
132 * structure, which is passed among nearly every sub-functions.
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 */
142 va_list vargs; /* pointer to current position into vargs */
143 char * sprintf_string;
148 * Realloc buffer if needed
149 * Return value: 0 = ok
150 * EOF = not enought memory
152 static int realloc_buff(xprintf_struct *s, size_t len)
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);
160 s->buffer_base = NULL;
164 s->dest_string = ptr + (size_t)(s->dest_string - s->buffer_base);
165 s->buffer_base = ptr;
168 (s->buffer_base)[s->buffer_len - 1] = 1; /* overflow marker */
175 * Prints 'usual' characters up to next '%'
176 * or up to end of text
178 static int usual_char(xprintf_struct * s)
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 */
186 if (realloc_buff(s,len) == EOF)
189 memcpy(s->dest_string, s->src_string, len);
190 s->src_string += len;
191 s->dest_string += len;
193 s->pseudo_len += len;
199 * Return value: 0 = ok
202 static int print_it(xprintf_struct *s, size_t approx_len,
203 const char *format_string, ...)
209 if (realloc_buff(s,approx_len) == EOF)
212 va_start(varg, format_string);
213 vsprintf_len = vsprintf(s->dest_string, format_string, varg);
216 /* Check for overflow */
217 assert((s->buffer_base)[s->buffer_len - 1] == 1);
219 if (vsprintf_len == EOF) /* must be done *after* overflow-check */
222 s->pseudo_len += vsprintf_len;
223 len = strlen(s->dest_string);
225 s->dest_string += len;
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)
238 * Return value: 0 = ok
241 static int type_s(xprintf_struct *s, int width, int prec,
242 const char *format_string, const char *arg_string)
246 if (arg_string == NULL)
247 return print_it(s, (size_t)6, "(null)", 0);
249 /* hand-made strlen() whitch stops when 'prec' is reached. */
250 /* if 'prec' is -1 then it is never reached. */
252 while (arg_string[string_len] != 0 && (size_t)prec != string_len)
255 if (width != -1 && string_len < (size_t)width)
256 string_len = (size_t)width;
258 return print_it(s, string_len, format_string, arg_string);
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).
268 static int getint(const char **string)
272 while (isdigit((unsigned char)**string) != 0) {
273 i = i * 10 + (**string - '0');
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 */
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
292 * Return value: 0 = ok
295 static int dispatch(xprintf_struct *s)
297 const char *initial_ptr;
298 char format_string[24]; /* max length may be something like "% +-#032768.32768Ld" */
300 int flag_plus, flag_minus, flag_space, flag_sharp, flag_zero;
301 int width, prec, modifier, approx_width;
303 /* most of those variables are here to rewrite the format string */
305 #define SRCTXT (s->src_string)
306 #define DESTTXT (s->dest_string)
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 */
314 return usual_char(s);
316 /* we then have a '%' */
318 /* don't check for end-of-string ; this is done later */
320 /* '%%' escape sequence */
321 if (*SRCTXT == '%') {
322 if (realloc_buff(s, (size_t)1) == EOF) /* because we can have "%%%%%%%%..." */
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. */
338 flag_plus = flag_minus = flag_space = flag_sharp = flag_zero = 0;
343 else if (*SRCTXT == '+')
345 else if (*SRCTXT == '-')
347 else if (*SRCTXT == '#')
349 else if (*SRCTXT == '0')
355 INCOHERENT_TEST(); /* here is the first test for end of string */
358 if (*SRCTXT == '*') { /* width given by next argument */
360 width = va_arg(s->vargs, int);
361 if ((size_t)width > 0x3fffU) /* 'size_t' to check against negative values too */
363 } else if (isdigit((unsigned char)*SRCTXT)) /* width given as ASCII number */
364 width = getint(&SRCTXT);
366 width = -1; /* no width specified */
371 if (*SRCTXT == '.') {
373 if (*SRCTXT == '*') { /* .prec given by next argument */
375 prec = va_arg(s->vargs, int);
376 if ((size_t)prec >= 0x3fffU) /* 'size_t' to check against negative values too */
378 } else { /* .prec given as ASCII number */
379 if (isdigit((unsigned char)*SRCTXT) == 0)
381 prec = getint(&SRCTXT);
385 prec = -1; /* no .prec specified */
388 if (*SRCTXT == 'L' || *SRCTXT == 'h' || *SRCTXT == 'l') {
391 if (modifier=='l' && *SRCTXT=='l') {
393 modifier = 'L'; /* 'll' == 'L' long long == long double */
394 } /* only for compatibility ; not portable */
397 modifier = -1; /* no modifier specified */
401 if (strchr("diouxXfegEGcspn",type) == NULL)
402 INCOHERENT(); /* unknown type */
405 /* rewrite format-string */
406 format_string[0] = '%';
407 format_ptr = &(format_string[1]);
428 } /* '0' *must* be the last one */
431 sprintf(format_ptr, "%i", width);
432 format_ptr += strlen(format_ptr);
438 sprintf(format_ptr, "%i", prec);
439 format_ptr += strlen(format_ptr);
442 if (modifier != -1) {
443 if (modifier == 'L' && strchr("diouxX",type) != NULL) {
449 *format_ptr = modifier;
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 */
473 return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
475 return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long long int));
477 return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long int));
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' */
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' */
499 case -1 : /* because of default promotion, no modifier means 'l' */
501 return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, double));
503 return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long double));
510 return type_s(s, width, prec, format_string, va_arg(s->vargs, const char*));
515 return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, void *));
520 if (modifier == -1) {
522 p = va_arg(s->vargs, int *);
533 INCOHERENT(); /* unknown type */
536 #undef INCOHERENT_TEST
542 * Return value: number of *virtually* written characters
545 static int core(xprintf_struct *s)
547 size_t len, save_len;
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 */
556 if (s->src_string == NULL)
557 s->src_string = "(null)";
559 /* struct init and memory allocation */
560 s->buffer_base = NULL;
564 if (realloc_buff(s, (size_t)0) == EOF)
566 s->dest_string = s->buffer_base;
568 /* process source string */
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;
577 if (dispatch(s) == EOF)
580 /* up to end of dest string */
581 if (s->real_len >= s->maxlen) {
582 (s->buffer_base)[s->maxlen] = 0; /* final 0 */
588 /* for (v)asnprintf */
589 dummy_base = s->buffer_base;
590 save_len = 0; /* just to avoid a compiler warning */
592 dummy_base = s->buffer_base + s->real_len;
593 save_len = s->real_len;
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 */
600 s->dest_string = dummy_base;
601 if (dispatch(s) == EOF)
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;
611 if (s->buffer_base != NULL)
612 free(s->buffer_base);
616 int vasprintf(char **ptr, const char *format_string, va_list vargs)
621 s.src_string = format_string;
623 va_copy (s.vargs, vargs);
626 __va_copy (s.vargs, vargs);
628 memcpy (&s.vargs, vargs, sizeof (va_list));
629 #endif /* __va_copy */
631 s.maxlen = (size_t)INT_MAX;
640 *ptr = s.buffer_base;