]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/file/vasprintf.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / file / vasprintf.c
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
38 This software is distributed under the "modified BSD licence".
39
40 This software is also released with GNU license (GPL) in another file (same
41 source-code, only license differ).
42
43
44
45 Redistribution and use in source and binary forms, with or without
46 modification, are permitted provided that the following conditions are met:
47
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. 
55
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.
66
67 ====================
68
69 Hacked from xnprintf version of 26th February 2005 to provide only
70 vasprintf 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
81 trying to do any interpretation
82
83 flag:   none   +     -     #     (blank)
84 width:  n    0n    *
85 prec:   none   .0    .n     .*
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
88
89
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.
100
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.
106
107 */
108 #include "file.h"
109
110 #ifndef lint
111 FILE_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  */
134 typedef 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  */
152 static 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  */
178 static 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  */
202 static 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  */
241 static 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  */
268 static 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  */
295 static 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  */
545 static 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
615 int 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 }