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