]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/file/vasprintf.c
Record that base/vendor/file/dist@186675 was merged.
[FreeBSD/FreeBSD.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 #ifdef HAVE_CONFIG_H
109 #include "config.h"
110 #endif
111
112 #include <assert.h>
113 #include <stdio.h>
114 #include <string.h>
115 #include <stdlib.h>
116 #include <stdarg.h>
117 #include <ctype.h>
118 #ifdef HAVE_LIMITS_H
119 #include <limits.h>
120 #endif
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  */
133 typedef 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  */
151 static 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  */
177 static 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  */
201 static 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  */
240 static 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  */
267 static 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  */
294 static 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   if (*SRCTXT == 'L' || *SRCTXT == 'h' || *SRCTXT == 'l') {
388     modifier = *SRCTXT;
389     SRCTXT++;
390     if (modifier=='l' && *SRCTXT=='l') {
391       SRCTXT++;
392       modifier = 'L';  /* 'll' == 'L'      long long == long double */
393     } /* only for compatibility ; not portable */
394     INCOHERENT_TEST();
395   } else
396     modifier = -1;              /* no modifier specified */
397
398   /* type */
399   type = *SRCTXT;
400   if (strchr("diouxXfegEGcspn",type) == NULL)
401     INCOHERENT();               /* unknown type */
402   SRCTXT++;
403
404   /* rewrite format-string */
405   format_string[0] = '%';
406   format_ptr = &(format_string[1]);
407
408   if (flag_plus) {
409     *format_ptr = '+';
410     format_ptr++;
411   }
412   if (flag_minus) {
413     *format_ptr = '-';
414     format_ptr++;
415   }
416   if (flag_space) {
417     *format_ptr = ' ';
418     format_ptr++;
419   }
420   if (flag_sharp) {
421     *format_ptr = '#';
422     format_ptr++;
423   }
424   if (flag_zero) {
425     *format_ptr = '0';
426     format_ptr++;
427   } /* '0' *must* be the last one */
428
429   if (width != -1) {
430     sprintf(format_ptr, "%i", width);
431     format_ptr += strlen(format_ptr);
432   }
433
434   if (prec != -1) {
435     *format_ptr = '.';
436     format_ptr++;
437     sprintf(format_ptr, "%i", prec);
438     format_ptr += strlen(format_ptr);
439   }
440
441   if (modifier != -1) {
442     if (modifier == 'L' && strchr("diouxX",type) != NULL) {
443       *format_ptr = 'l';
444       format_ptr++;
445       *format_ptr = 'l';
446       format_ptr++;
447     } else {
448       *format_ptr = modifier;
449       format_ptr++;
450     }
451   }
452
453   *format_ptr = type;
454   format_ptr++;
455   *format_ptr = 0;
456
457   /* vague approximation of minimal length if width or prec are specified */
458   approx_width = width + prec;
459   if (approx_width < 0) /* because width == -1 and/or prec == -1 */
460     approx_width = 0;
461
462   switch (type) {
463     /* int */
464   case 'd':
465   case 'i':
466   case 'o':
467   case 'u':
468   case 'x':
469   case 'X':
470     switch (modifier) {
471     case -1 :
472       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
473     case 'L':
474       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long long int));
475     case 'l':
476       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long int));
477     case 'h':
478       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
479       /* 'int' instead of 'short int' because default promotion is 'int' */
480     default:
481       INCOHERENT();
482     }
483
484     /* char */
485   case 'c':
486     if (modifier != -1)
487       INCOHERENT();
488     return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, int));
489     /* 'int' instead of 'char' because default promotion is 'int' */
490
491     /* math */
492   case 'e':
493   case 'f':
494   case 'g':
495   case 'E':
496   case 'G':
497     switch (modifier) {
498     case -1 : /* because of default promotion, no modifier means 'l' */
499     case 'l':
500       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, double));
501     case 'L':
502       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, long double));
503     default:
504       INCOHERENT();
505     }
506
507     /* string */
508   case 's':
509     return type_s(s, width, prec, format_string, va_arg(s->vargs, const char*));
510
511     /* pointer */
512   case 'p':
513     if (modifier == -1)
514       return print_it(s, (size_t)approx_width, format_string, va_arg(s->vargs, void *));
515     INCOHERENT();
516
517     /* store */
518   case 'n':
519     if (modifier == -1) {
520       int * p;
521       p = va_arg(s->vargs, int *);
522       if (p != NULL) {
523         *p = s->pseudo_len;
524         return 0;
525       }
526       return EOF;
527     }
528     INCOHERENT();
529
530   } /* switch */
531
532   INCOHERENT();                 /* unknown type */
533
534 #undef INCOHERENT
535 #undef INCOHERENT_TEST
536 #undef SRCTXT
537 #undef DESTTXT
538 }
539
540 /*
541  *  Return value: number of *virtually* written characters
542  *                EOF = error
543  */
544 static int core(xprintf_struct *s)
545 {
546   size_t len, save_len;
547   char *dummy_base;
548
549   /* basic checks */
550   if ((int)(s->maxlen) <= 0) /* 'int' to check against some conversion */
551     return EOF;           /* error for example if value is (int)-10 */
552   s->maxlen--;      /* because initial maxlen counts final 0 */
553   /* note: now 'maxlen' _can_ be zero */
554
555   if (s->src_string == NULL)
556     s->src_string = "(null)";
557
558   /* struct init and memory allocation */
559   s->buffer_base = NULL;
560   s->buffer_len = 0;
561   s->real_len = 0;
562   s->pseudo_len = 0;
563   if (realloc_buff(s, (size_t)0) == EOF)
564     return EOF;
565   s->dest_string = s->buffer_base;
566
567   /* process source string */
568   for (;;) {
569     /* up to end of source string */
570     if (*(s->src_string) == 0) {
571       *(s->dest_string) = 0;    /* final 0 */
572       len = s->real_len + 1;
573       break;
574     }
575
576     if (dispatch(s) == EOF)
577       goto free_EOF;
578
579     /* up to end of dest string */
580     if (s->real_len >= s->maxlen) {
581       (s->buffer_base)[s->maxlen] = 0; /* final 0 */
582       len = s->maxlen + 1;
583       break;
584     }
585   }
586
587   /* for (v)asnprintf */
588   dummy_base = s->buffer_base;
589   save_len = 0;                 /* just to avoid a compiler warning */
590
591   dummy_base = s->buffer_base + s->real_len;
592   save_len = s->real_len;
593
594   /* process the remaining of source string to compute 'pseudo_len'. We
595    * overwrite again and again, starting at 'dummy_base' because we don't
596    * need the text, only char count. */
597   while(*(s->src_string) != 0) { /* up to end of source string */
598     s->real_len = 0;
599     s->dest_string = dummy_base;
600     if (dispatch(s) == EOF)
601       goto free_EOF;
602   }
603
604   s->buffer_base = (char *)realloc((void *)(s->buffer_base), save_len + 1);
605   if (s->buffer_base == NULL)
606     return EOF; /* should rarely happen because we shrink the buffer */
607   return s->pseudo_len;
608
609  free_EOF:
610   if (s->buffer_base != NULL)
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 }