1 /* $NetBSD: vasprintf.c,v 1.1.1.1 2009/05/08 16:35:05 christos Exp $ */
4 * Copyright (c) Ian F. Darwin 1986-1995.
5 * Software written by Ian F. Darwin and others;
6 * maintained 1995-present by Christos Zoulas and others.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice immediately at the beginning of the file, without modification,
13 * this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 /*###########################################################################
34 # Copyright (c) 2002-2005 David TAILLANDIER #
36 ###########################################################################*/
40 This software is distributed under the "modified BSD licence".
42 This software is also released with GNU license (GPL) in another file (same
43 source-code, only license differ).
47 Redistribution and use in source and binary forms, with or without
48 modification, are permitted provided that the following conditions are met:
50 Redistributions of source code must retain the above copyright notice, this
51 list of conditions and the following disclaimer. Redistributions in binary
52 form must reproduce the above copyright notice, this list of conditions and
53 the following disclaimer in the documentation and/or other materials
54 provided with the distribution. The name of the author may not be used to
55 endorse or promote products derived from this software without specific
56 prior written permission.
58 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
59 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
60 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
61 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
62 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
63 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
64 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
65 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
66 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
67 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
71 Hacked from xnprintf version of 26th February 2005 to provide only
72 vasprintf by Reuben Thomas <rrt@sc3d.org>.
77 'printf' function family use the following format string:
79 %[flag][width][.prec][modifier]type
81 %% is the escape sequence to print a '%'
82 % followed by an unknown format will print the characters without
83 trying to do any interpretation
85 flag: none + - # (blank)
88 modifier: F N L h l ll ('F' and 'N' are ms-dos/16-bit specific)
89 type: d i o u x X f e g E G c s p n
92 The function needs to allocate memory to store the full text before to
93 actually writting it. i.e if you want to fnprintf() 1000 characters, the
94 functions will allocate 1000 bytes.
95 This behaviour can be modified: you have to customise the code to flush the
96 internal buffer (writing to screen or file) when it reach a given size. Then
97 the buffer can have a shorter length. But what? If you really need to write
98 HUGE string, don't use printf!
99 During the process, some other memory is allocated (1024 bytes minimum)
100 to handle the output of partial sprintf() calls. If you have only 10000 bytes
101 free in memory, you *may* not be able to nprintf() a 8000 bytes-long text.
103 note: if a buffer overflow occurs, exit() is called. This situation should
104 never appear ... but if you want to be *really* sure, you have to modify the
105 code to handle those situations (only one place to modify).
106 A buffer overflow can only occur if your sprintf() do strange things or when
107 you use strange formats.
114 FILE_RCSID("@(#)$File: vasprintf.c,v 1.7 2009/02/03 20:27:52 christos Exp $")
116 __RCSID("$NetBSD: vasprintf.c,v 1.1.1.1 2009/05/08 16:35:05 christos Exp $");
129 #define ALLOC_CHUNK 2048
130 #define ALLOC_SECURITY_MARGIN 1024 /* big value because some platforms have very big 'G' exponent */
131 #if ALLOC_CHUNK < ALLOC_SECURITY_MARGIN
132 # error !!! ALLOC_CHUNK < ALLOC_SECURITY_MARGIN !!!
134 /* note: to have some interest, ALLOC_CHUNK should be much greater than ALLOC_SECURITY_MARGIN */
137 * To save a lot of push/pop, every variable are stored into this
138 * structure, which is passed among nearly every sub-functions.
141 const char * src_string
; /* current position into intput string */
142 char * buffer_base
; /* output buffer */
143 char * dest_string
; /* current position into output string */
144 size_t buffer_len
; /* length of output buffer */
145 size_t real_len
; /* real current length of output text */
146 size_t pseudo_len
; /* total length of output text if it were not limited in size */
148 va_list vargs
; /* pointer to current position into vargs */
149 char * sprintf_string
;
154 * Realloc buffer if needed
155 * Return value: 0 = ok
156 * EOF = not enought memory
158 static int realloc_buff(xprintf_struct
*s
, size_t len
)
162 if (len
+ ALLOC_SECURITY_MARGIN
+ s
->real_len
> s
->buffer_len
) {
163 len
+= s
->real_len
+ ALLOC_CHUNK
;
164 ptr
= (char *)realloc((void *)(s
->buffer_base
), len
);
166 s
->buffer_base
= NULL
;
170 s
->dest_string
= ptr
+ (size_t)(s
->dest_string
- s
->buffer_base
);
171 s
->buffer_base
= ptr
;
174 (s
->buffer_base
)[s
->buffer_len
- 1] = 1; /* overflow marker */
181 * Prints 'usual' characters up to next '%'
182 * or up to end of text
184 static int usual_char(xprintf_struct
* s
)
188 len
= strcspn(s
->src_string
, "%"); /* reachs the next '%' or end of input string */
189 /* note: 'len' is never 0 because the presence of '%' */
190 /* or end-of-line is checked in the calling function */
192 if (realloc_buff(s
,len
) == EOF
)
195 memcpy(s
->dest_string
, s
->src_string
, len
);
196 s
->src_string
+= len
;
197 s
->dest_string
+= len
;
199 s
->pseudo_len
+= len
;
205 * Return value: 0 = ok
208 static int print_it(xprintf_struct
*s
, size_t approx_len
,
209 const char *format_string
, ...)
215 if (realloc_buff(s
,approx_len
) == EOF
)
218 va_start(varg
, format_string
);
219 vsprintf_len
= vsprintf(s
->dest_string
, format_string
, varg
);
222 /* Check for overflow */
223 assert((s
->buffer_base
)[s
->buffer_len
- 1] == 1);
225 if (vsprintf_len
== EOF
) /* must be done *after* overflow-check */
228 s
->pseudo_len
+= vsprintf_len
;
229 len
= strlen(s
->dest_string
);
231 s
->dest_string
+= len
;
237 * Prints a string (%s)
238 * We need special handling because:
239 * a: the length of the string is unknown
240 * b: when .prec is used, we must not access any extra byte of the
241 * string (of course, if the original sprintf() does... what the
242 * hell, not my problem)
244 * Return value: 0 = ok
247 static int type_s(xprintf_struct
*s
, int width
, int prec
,
248 const char *format_string
, const char *arg_string
)
252 if (arg_string
== NULL
)
253 return print_it(s
, (size_t)6, "(null)", 0);
255 /* hand-made strlen() whitch stops when 'prec' is reached. */
256 /* if 'prec' is -1 then it is never reached. */
258 while (arg_string
[string_len
] != 0 && (size_t)prec
!= string_len
)
261 if (width
!= -1 && string_len
< (size_t)width
)
262 string_len
= (size_t)width
;
264 return print_it(s
, string_len
, format_string
, arg_string
);
268 * Read a serie of digits. Stop when non-digit is found.
269 * Return value: the value read (between 0 and 32767).
270 * Note: no checks are made against overflow. If the string contain a big
271 * number, then the return value won't be what we want (but, in this case,
272 * the programmer don't know whatr he wants, then no problem).
274 static int getint(const char **string
)
278 while (isdigit((unsigned char)**string
) != 0) {
279 i
= i
* 10 + (**string
- '0');
283 if (i
< 0 || i
> 32767)
284 i
= 32767; /* if we have i==-10 this is not because the number is */
285 /* negative; this is because the number is big */
290 * Read a part of the format string. A part is 'usual characters' (ie "blabla")
291 * or '%%' escape sequence (to print a single '%') or any combination of
292 * format specifier (ie "%i" or "%10.2d").
293 * After the current part is managed, the function returns to caller with
294 * everything ready to manage the following part.
295 * The caller must ensure than the string is not empty, i.e. the first byte
298 * Return value: 0 = ok
301 static int dispatch(xprintf_struct
*s
)
303 const char *initial_ptr
;
304 char format_string
[24]; /* max length may be something like "% +-#032768.32768Ld" */
306 int flag_plus
, flag_minus
, flag_space
, flag_sharp
, flag_zero
;
307 int width
, prec
, modifier
, approx_width
;
309 /* most of those variables are here to rewrite the format string */
311 #define SRCTXT (s->src_string)
312 #define DESTTXT (s->dest_string)
314 /* incoherent format string. Characters after the '%' will be printed with the next call */
315 #define INCOHERENT() do {SRCTXT=initial_ptr; return 0;} while (0) /* do/while to avoid */
316 #define INCOHERENT_TEST() do {if(*SRCTXT==0) INCOHERENT();} while (0) /* a null statement */
320 return usual_char(s
);
322 /* we then have a '%' */
324 /* don't check for end-of-string ; this is done later */
326 /* '%%' escape sequence */
327 if (*SRCTXT
== '%') {
328 if (realloc_buff(s
, (size_t)1) == EOF
) /* because we can have "%%%%%%%%..." */
339 initial_ptr
= SRCTXT
; /* save current pointer in case of incorrect */
340 /* 'decoding'. Points just after the '%' so the '%' */
341 /* won't be printed in any case, as required. */
344 flag_plus
= flag_minus
= flag_space
= flag_sharp
= flag_zero
= 0;
349 else if (*SRCTXT
== '+')
351 else if (*SRCTXT
== '-')
353 else if (*SRCTXT
== '#')
355 else if (*SRCTXT
== '0')
361 INCOHERENT_TEST(); /* here is the first test for end of string */
364 if (*SRCTXT
== '*') { /* width given by next argument */
366 width
= va_arg(s
->vargs
, int);
367 if ((size_t)width
> 0x3fffU
) /* 'size_t' to check against negative values too */
369 } else if (isdigit((unsigned char)*SRCTXT
)) /* width given as ASCII number */
370 width
= getint(&SRCTXT
);
372 width
= -1; /* no width specified */
377 if (*SRCTXT
== '.') {
379 if (*SRCTXT
== '*') { /* .prec given by next argument */
381 prec
= va_arg(s
->vargs
, int);
382 if ((size_t)prec
>= 0x3fffU
) /* 'size_t' to check against negative values too */
384 } else { /* .prec given as ASCII number */
385 if (isdigit((unsigned char)*SRCTXT
) == 0)
387 prec
= getint(&SRCTXT
);
391 prec
= -1; /* no .prec specified */
394 if (*SRCTXT
== 'L' || *SRCTXT
== 'h' || *SRCTXT
== 'l') {
397 if (modifier
=='l' && *SRCTXT
=='l') {
399 modifier
= 'L'; /* 'll' == 'L' long long == long double */
400 } /* only for compatibility ; not portable */
403 modifier
= -1; /* no modifier specified */
407 if (strchr("diouxXfegEGcspn",type
) == NULL
)
408 INCOHERENT(); /* unknown type */
411 /* rewrite format-string */
412 format_string
[0] = '%';
413 format_ptr
= &(format_string
[1]);
434 } /* '0' *must* be the last one */
437 sprintf(format_ptr
, "%i", width
);
438 format_ptr
+= strlen(format_ptr
);
444 sprintf(format_ptr
, "%i", prec
);
445 format_ptr
+= strlen(format_ptr
);
448 if (modifier
!= -1) {
449 if (modifier
== 'L' && strchr("diouxX",type
) != NULL
) {
455 *format_ptr
= modifier
;
464 /* vague approximation of minimal length if width or prec are specified */
465 approx_width
= width
+ prec
;
466 if (approx_width
< 0) /* because width == -1 and/or prec == -1 */
479 return print_it(s
, (size_t)approx_width
, format_string
, va_arg(s
->vargs
, int));
481 return print_it(s
, (size_t)approx_width
, format_string
, va_arg(s
->vargs
, long long int));
483 return print_it(s
, (size_t)approx_width
, format_string
, va_arg(s
->vargs
, long int));
485 return print_it(s
, (size_t)approx_width
, format_string
, va_arg(s
->vargs
, int));
486 /* 'int' instead of 'short int' because default promotion is 'int' */
495 return print_it(s
, (size_t)approx_width
, format_string
, va_arg(s
->vargs
, int));
496 /* 'int' instead of 'char' because default promotion is 'int' */
505 case -1 : /* because of default promotion, no modifier means 'l' */
507 return print_it(s
, (size_t)approx_width
, format_string
, va_arg(s
->vargs
, double));
509 return print_it(s
, (size_t)approx_width
, format_string
, va_arg(s
->vargs
, long double));
516 return type_s(s
, width
, prec
, format_string
, va_arg(s
->vargs
, const char*));
521 return print_it(s
, (size_t)approx_width
, format_string
, va_arg(s
->vargs
, void *));
526 if (modifier
== -1) {
528 p
= va_arg(s
->vargs
, int *);
539 INCOHERENT(); /* unknown type */
542 #undef INCOHERENT_TEST
548 * Return value: number of *virtually* written characters
551 static int core(xprintf_struct
*s
)
553 size_t len
, save_len
;
557 if ((int)(s
->maxlen
) <= 0) /* 'int' to check against some conversion */
558 return EOF
; /* error for example if value is (int)-10 */
559 s
->maxlen
--; /* because initial maxlen counts final 0 */
560 /* note: now 'maxlen' _can_ be zero */
562 if (s
->src_string
== NULL
)
563 s
->src_string
= "(null)";
565 /* struct init and memory allocation */
566 s
->buffer_base
= NULL
;
570 if (realloc_buff(s
, (size_t)0) == EOF
)
572 s
->dest_string
= s
->buffer_base
;
574 /* process source string */
576 /* up to end of source string */
577 if (*(s
->src_string
) == 0) {
578 *(s
->dest_string
) = 0; /* final 0 */
579 len
= s
->real_len
+ 1;
583 if (dispatch(s
) == EOF
)
586 /* up to end of dest string */
587 if (s
->real_len
>= s
->maxlen
) {
588 (s
->buffer_base
)[s
->maxlen
] = 0; /* final 0 */
594 /* for (v)asnprintf */
595 dummy_base
= s
->buffer_base
;
596 save_len
= 0; /* just to avoid a compiler warning */
598 dummy_base
= s
->buffer_base
+ s
->real_len
;
599 save_len
= s
->real_len
;
601 /* process the remaining of source string to compute 'pseudo_len'. We
602 * overwrite again and again, starting at 'dummy_base' because we don't
603 * need the text, only char count. */
604 while(*(s
->src_string
) != 0) { /* up to end of source string */
606 s
->dest_string
= dummy_base
;
607 if (dispatch(s
) == EOF
)
611 s
->buffer_base
= (char *)realloc((void *)(s
->buffer_base
), save_len
+ 1);
612 if (s
->buffer_base
== NULL
)
613 return EOF
; /* should rarely happen because we shrink the buffer */
614 return s
->pseudo_len
;
617 if (s
->buffer_base
!= NULL
)
618 free(s
->buffer_base
);
622 int vasprintf(char **ptr
, const char *format_string
, va_list vargs
)
627 s
.src_string
= format_string
;
629 va_copy (s
.vargs
, vargs
);
632 __va_copy (s
.vargs
, vargs
);
634 memcpy (&s
.vargs
, vargs
, sizeof (va_list));
635 #endif /* __va_copy */
637 s
.maxlen
= (size_t)INT_MAX
;
646 *ptr
= s
.buffer_base
;