root/sweep/trunk/intl/vasnprintf.c

Revision 409, 15.3 kB (checked in by erikd, 6 years ago)

sweep : Replace all usage of sprintf with snprintf.

Line 
1 /* vasnprintf with automatic memory allocation.
2    Copyright (C) 1999, 2002-2005 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU Library General Public License as published
6    by the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17    USA.  */
18
19 /* Tell glibc's <stdio.h> to provide a prototype for snprintf().
20    This must come before <config.h> because <config.h> may include
21    <features.h>, and once <features.h> has been included, it's too late.  */
22 #ifndef _GNU_SOURCE
23 # define _GNU_SOURCE    1
24 #endif
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29 #ifndef IN_LIBINTL
30 # include <alloca.h>
31 #endif
32
33 /* Specification.  */
34 #if WIDE_CHAR_VERSION
35 # include "vasnwprintf.h"
36 #else
37 # include "vasnprintf.h"
38 #endif
39
40 #include <stdio.h>      /* snprintf() */
41 #include <stdlib.h>     /* abort(), malloc(), realloc(), free() */
42 #include <string.h>     /* memcpy(), strlen() */
43 #include <errno.h>      /* errno */
44 #include <limits.h>     /* CHAR_BIT, INT_MAX */
45 #include <float.h>      /* DBL_MAX_EXP, LDBL_MAX_EXP */
46 #if WIDE_CHAR_VERSION
47 # include "wprintf-parse.h"
48 #else
49 # include "printf-parse.h"
50 #endif
51
52 /* Checked size_t computations.  */
53 #include "xsize.h"
54
55 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
56 #ifndef EOVERFLOW
57 # define EOVERFLOW E2BIG
58 #endif
59
60 #ifdef HAVE_WCHAR_T
61 # ifdef HAVE_WCSLEN
62 #  define local_wcslen wcslen
63 # else
64    /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
65       a dependency towards this library, here is a local substitute.
66       Define this substitute only once, even if this file is included
67       twice in the same compilation unit.  */
68 #  ifndef local_wcslen_defined
69 #   define local_wcslen_defined 1
70 static size_t
71 local_wcslen (const wchar_t *s)
72 {
73   const wchar_t *ptr;
74
75   for (ptr = s; *ptr != (wchar_t) 0; ptr++)
76     ;
77   return ptr - s;
78 }
79 #  endif
80 # endif
81 #endif
82
83 #if WIDE_CHAR_VERSION
84 # define VASNPRINTF vasnwprintf
85 # define CHAR_T wchar_t
86 # define DIRECTIVE wchar_t_directive
87 # define DIRECTIVES wchar_t_directives
88 # define PRINTF_PARSE wprintf_parse
89 # define USE_SNPRINTF 1
90 # if HAVE_DECL__SNWPRINTF
91    /* On Windows, the function swprintf() has a different signature than
92       on Unix; we use the _snwprintf() function instead.  */
93 #  define SNPRINTF _snwprintf
94 # else
95    /* Unix.  */
96 #  define SNPRINTF swprintf
97 # endif
98 #else
99 # define VASNPRINTF vasnprintf
100 # define CHAR_T char
101 # define DIRECTIVE char_directive
102 # define DIRECTIVES char_directives
103 # define PRINTF_PARSE printf_parse
104 # define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
105 # if HAVE_DECL__SNPRINTF
106    /* Windows.  */
107 #  define SNPRINTF _snprintf
108 # else
109    /* Unix.  */
110 #  define SNPRINTF snprintf
111 # endif
112 #endif
113
114 CHAR_T *
115 VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
116 {
117   DIRECTIVES d;
118   arguments a;
119
120   if (PRINTF_PARSE (format, &d, &a) < 0)
121     {
122       errno = EINVAL;
123       return NULL;
124     }
125
126 #define CLEANUP() \
127   free (d.dir);                                                         \
128   if (a.arg)                                                            \
129     free (a.arg);
130
131   if (printf_fetchargs (args, &a) < 0)
132     {
133       CLEANUP ();
134       errno = EINVAL;
135       return NULL;
136     }
137
138   {
139     size_t buf_neededlength;
140     CHAR_T *buf;
141     CHAR_T *buf_malloced;
142     const CHAR_T *cp;
143     size_t i;
144     DIRECTIVE *dp;
145     /* Output string accumulator.  */
146     CHAR_T *result;
147     size_t allocated;
148     size_t length;
149
150     /* Allocate a small buffer that will hold a directive passed to
151        snprintf.  */
152     buf_neededlength =
153       xsum4 (7, d.max_width_length, d.max_precision_length, 6);
154 #if HAVE_ALLOCA
155     if (buf_neededlength < 4000 / sizeof (CHAR_T))
156       {
157         buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
158         buf_malloced = NULL;
159       }
160     else
161 #endif
162       {
163         size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
164         if (size_overflow_p (buf_memsize))
165           goto out_of_memory_1;
166         buf = (CHAR_T *) malloc (buf_memsize);
167         if (buf == NULL)
168           goto out_of_memory_1;
169         buf_malloced = buf;
170       }
171
172     if (resultbuf != NULL)
173       {
174         result = resultbuf;
175         allocated = *lengthp;
176       }
177     else
178       {
179         result = NULL;
180         allocated = 0;
181       }
182     length = 0;
183     /* Invariants:
184        result is either == resultbuf or == NULL or malloc-allocated.
185        If length > 0, then result != NULL.  */
186
187     /* Ensures that allocated >= needed.  Aborts through a jump to
188        out_of_memory if needed is SIZE_MAX or otherwise too big.  */
189 #define ENSURE_ALLOCATION(needed) \
190     if ((needed) > allocated)                                                \
191       {                                                                      \
192         size_t memory_size;                                                  \
193         CHAR_T *memory;                                                      \
194                                                                              \
195         allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);            \
196         if ((needed) > allocated)                                            \
197           allocated = (needed);                                              \
198         memory_size = xtimes (allocated, sizeof (CHAR_T));                   \
199         if (size_overflow_p (memory_size))                                   \
200           goto out_of_memory;                                                \
201         if (result == resultbuf || result == NULL)                           \
202           memory = (CHAR_T *) malloc (memory_size);                          \
203         else                                                                 \
204           memory = (CHAR_T *) realloc (result, memory_size);                 \
205         if (memory == NULL)                                                  \
206           goto out_of_memory;                                                \
207         if (result == resultbuf && length > 0)                               \
208           memcpy (memory, result, length * sizeof (CHAR_T));                 \
209         result = memory;                                                     \
210       }
211
212     for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
213       {
214         if (cp != dp->dir_start)
215           {
216             size_t n = dp->dir_start - cp;
217             size_t augmented_length = xsum (length, n);
218
219             ENSURE_ALLOCATION (augmented_length);
220             memcpy (result + length, cp, n * sizeof (CHAR_T));
221             length = augmented_length;
222           }
223         if (i == d.count)
224           break;
225
226         /* Execute a single directive.  */
227         if (dp->conversion == '%')
228           {
229             size_t augmented_length;
230
231             if (!(dp->arg_index == ARG_NONE))
232               abort ();
233             augmented_length = xsum (length, 1);
234             ENSURE_ALLOCATION (augmented_length);
235             result[length] = '%';
236             length = augmented_length;
237           }
238         else
239           {
240             if (!(dp->arg_index != ARG_NONE))
241               abort ();
242
243             if (dp->conversion == 'n')
244               {
245                 switch (a.arg[dp->arg_index].type)
246                   {
247                   case TYPE_COUNT_SCHAR_POINTER:
248                     *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
249                     break;
250                   case TYPE_COUNT_SHORT_POINTER:
251                     *a.arg[dp->arg_index].a.a_count_short_pointer = length;
252                     break;
253                   case TYPE_COUNT_INT_POINTER:
254                     *a.arg[dp->arg_index].a.a_count_int_pointer = length;
255                     break;
256                   case TYPE_COUNT_LONGINT_POINTER:
257                     *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
258                     break;
259 #ifdef HAVE_LONG_LONG
260                   case TYPE_COUNT_LONGLONGINT_POINTER:
261                     *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
262                     break;
263 #endif
264                   default:
265                     abort ();
266                   }
267               }
268             else
269               {
270                 arg_type type = a.arg[dp->arg_index].type;
271                 CHAR_T *p;
272                 unsigned int prefix_count;
273                 int prefixes[2];
274
275                 /* Construct the format string for calling snprintf.  */
276                 p = buf;
277                 *p++ = '%';
278                 if (dp->flags & FLAG_GROUP)
279                   *p++ = '\'';
280                 if (dp->flags & FLAG_LEFT)
281                   *p++ = '-';
282                 if (dp->flags & FLAG_SHOWSIGN)
283                   *p++ = '+';
284                 if (dp->flags & FLAG_SPACE)
285                   *p++ = ' ';
286                 if (dp->flags & FLAG_ALT)
287                   *p++ = '#';
288                 if (dp->flags & FLAG_ZERO)
289                   *p++ = '0';
290                 if (dp->width_start != dp->width_end)
291                   {
292                     size_t n = dp->width_end - dp->width_start;
293                     memcpy (p, dp->width_start, n * sizeof (CHAR_T));
294                     p += n;
295                   }
296                 if (dp->precision_start != dp->precision_end)
297                   {
298                     size_t n = dp->precision_end - dp->precision_start;
299                     memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
300                     p += n;
301                   }
302
303                 switch (type)
304                   {
305 #ifdef HAVE_LONG_LONG
306                   case TYPE_LONGLONGINT:
307                   case TYPE_ULONGLONGINT:
308                     *p++ = 'l';
309                     /*FALLTHROUGH*/
310 #endif
311                   case TYPE_LONGINT:
312                   case TYPE_ULONGINT:
313 #ifdef HAVE_WINT_T
314                   case TYPE_WIDE_CHAR:
315 #endif
316 #ifdef HAVE_WCHAR_T
317                   case TYPE_WIDE_STRING:
318 #endif
319                     *p++ = 'l';
320                     break;
321 #ifdef HAVE_LONG_DOUBLE
322                   case TYPE_LONGDOUBLE:
323                     *p++ = 'L';
324                     break;
325 #endif
326                   default:
327                     break;
328                   }
329                 *p = dp->conversion;
330 #if USE_SNPRINTF
331                 p[1] = '%';
332                 p[2] = 'n';
333                 p[3] = '\0';
334 #else
335                 p[1] = '\0';
336 #endif
337
338                 /* Construct the arguments for calling snprintf.  */
339                 prefix_count = 0;
340                 if (dp->width_arg_index != ARG_NONE)
341                   {
342                     if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
343                       abort ();
344                     prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
345                   }
346                 if (dp->precision_arg_index != ARG_NONE)
347                   {
348                     if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
349                       abort ();
350                     prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
351                   }
352
353 #if USE_SNPRINTF
354                 /* Prepare checking whether snprintf returns the count
355                    via %n.  */
356                 ENSURE_ALLOCATION (xsum (length, 1));
357                 result[length] = '\0';
358 #endif
359
360                 for (;;)
361                   {
362                     size_t maxlen;
363                     int count;
364                     int retcount;
365
366                     maxlen = allocated - length;
367                     count = -1;
368                     retcount = 0;
369
370 #if USE_SNPRINTF
371 # define SNPRINTF_BUF(arg) \
372                     switch (prefix_count)                                   \
373                       {                                                     \
374                       case 0:                                               \
375                         retcount = SNPRINTF (result + length, maxlen, buf,  \
376                                              arg, &count);                  \
377                         break;                                              \
378                       case 1:                                               \
379                         retcount = SNPRINTF (result + length, maxlen, buf,  \
380                                              prefixes[0], arg, &count);     \
381                         break;                                              \
382                       case 2:                                               \
383                         retcount = SNPRINTF (result + length, maxlen, buf,  \
384                                              prefixes[0], prefixes[1], arg, \
385                                              &count);                       \
386                         break;                                              \
387                       default:                                              \
388                         abort ();                                           \
389                       }
390 #endif
391
392                     switch (type)
393                       {
394                       case TYPE_SCHAR:
395                         {
396                           int arg = a.arg[dp->arg_index].a.a_schar;
397                           SNPRINTF_BUF (arg);
398                         }
399                         break;
400                       case TYPE_UCHAR:
401                         {
402                           unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
403                           SNPRINTF_BUF (arg);
404                         }
405                         break;
406                       case TYPE_SHORT:
407                         {
408                           int arg = a.arg[dp->arg_index].a.a_short;
409                           SNPRINTF_BUF (arg);
410                         }
411                         break;
412                       case TYPE_USHORT:
413                         {
414                           unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
415                           SNPRINTF_BUF (arg);
416                         }
417                         break;
418                       case TYPE_INT:
419                         {
420                           int arg = a.arg[dp->arg_index].a.a_int;
421                           SNPRINTF_BUF (arg);
422                         }
423                         break;
424                       case TYPE_UINT:
425                         {
426                           unsigned int arg = a.arg[dp->arg_index].a.a_uint;
427                           SNPRINTF_BUF (arg);
428                         }
429                         break;
430                       case TYPE_LONGINT:
431                         {
432                           long int arg = a.arg[dp->arg_index].a.a_longint;
433                           SNPRINTF_BUF (arg);
434                         }
435                         break;
436                       case TYPE_ULONGINT:
437                         {
438                           unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
439                           SNPRINTF_BUF (arg);
440                         }
441                         break;
442 #ifdef HAVE_LONG_LONG
443                       case TYPE_LONGLONGINT:
444                         {
445                           long long int arg = a.arg[dp->arg_index].a.a_longlongint;
446                           SNPRINTF_BUF (arg);
447                         }
448                         break;
449                       case TYPE_ULONGLONGINT:
450                         {
451                           unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
452                           SNPRINTF_BUF (arg);
453                         }
454                         break;
455 #endif
456                       case TYPE_DOUBLE:
457                         {
458                           double arg = a.arg[dp->arg_index].a.a_double;
459                           SNPRINTF_BUF (arg);
460                         }
461                         break;
462 #ifdef HAVE_LONG_DOUBLE
463                       case TYPE_LONGDOUBLE:
464                         {
465                           long double arg = a.arg[dp->arg_index].a.a_longdouble;
466                           SNPRINTF_BUF (arg);
467                         }
468                         break;
469 #endif
470                       case TYPE_CHAR:
471                         {
472                           int arg = a.arg[dp->arg_index].a.a_char;
473                           SNPRINTF_BUF (arg);
474                         }
475                         break;
476 #ifdef HAVE_WINT_T
477                       case TYPE_WIDE_CHAR:
478                         {
479                           wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
480                           SNPRINTF_BUF (arg);
481                         }
482                         break;
483 #endif
484                       case TYPE_STRING:
485                         {
486                           const char *arg = a.arg[dp->arg_index].a.a_string;
487                           SNPRINTF_BUF (arg);
488                         }
489                         break;
490 #ifdef HAVE_WCHAR_T
491                       case TYPE_WIDE_STRING:
492                         {
493                           const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
494                           SNPRINTF_BUF (arg);
495                         }
496                         break;
497 #endif
498                       case TYPE_POINTER:
499                         {
500                           void *arg = a.arg[dp->arg_index].a.a_pointer;
501                           SNPRINTF_BUF (arg);
502                         }
503                         break;
504                       default:
505                         abort ();
506                       }
507
508 #if USE_SNPRINTF
509                     /* Portability: Not all implementations of snprintf()
510                        are ISO C 99 compliant.  Determine the number of
511                        bytes that snprintf() has produced or would have
512                        produced.  */
513                     if (count >= 0)
514                       {
515                         /* Verify that snprintf() has NUL-terminated its
516                            result.  */
517                         if (count < maxlen && result[length + count] != '\0')
518                           abort ();
519                         /* Portability hack.  */
520                         if (retcount > count)
521                           count = retcount;
522                       }
523                     else
524                       {
525                         /* snprintf() doesn't understand the '%n'
526                            directive.  */
527                         if (p[1] != '\0')
528                           {
529                             /* Don't use the '%n' directive; instead, look
530                                at the snprintf() return value.  */
531                             p[1] = '\0';
532                             continue;
533                           }
534                         else
535                           {
536                             /* Look at the snprintf() return value.  */
537                             if (retcount < 0)
538                               {
539                                 /* HP-UX 10.20 snprintf() is doubly deficient:
540                                    It doesn't understand the '%n' directive,
541                                    *and* it returns -1 (rather than the length
542                                    that would have been required) when the
543                                    buffer is too small.  */
544                                 size_t bigger_need =
545                                   xsum (xtimes (allocated, 2), 12);
546                                 ENSURE_ALLOCATION (bigger_need);
547                                 continue;
548                               }
549                             else
550                               count = retcount;
551                           }
552                       }
553 #endif
554
555                     /* Attempt to handle failure.  */
556                     if (count < 0)
557                       {
558                         if (!(result == resultbuf || result == NULL))
559                           free (result);
560                         if (buf_malloced != NULL)
561                           free (buf_malloced);
562                         CLEANUP ();
563                         errno = EINVAL;
564                         return NULL;
565                       }
566
567 #if !USE_SNPRINTF
568                     if (count >= tmp_length)
569                       /* tmp_length was incorrectly calculated - fix the
570                          code above!  */
571                       abort ();
572 #endif
573
574                     /* Make room for the result.  */
575                     if (count >= maxlen)
576                       {
577                         /* Need at least count bytes.  But allocate
578                            proportionally, to avoid looping eternally if
579                            snprintf() reports a too small count.  */
580                         size_t n =
581                           xmax (xsum (length, count), xtimes (allocated, 2));
582
583                         ENSURE_ALLOCATION (n);
584 #if USE_SNPRINTF
585                         continue;
586 #endif
587                       }
588
589                     length += count;
590                     break;
591                   }
592               }
593           }
594       }
595
596     /* Add the final NUL.  */
597     ENSURE_ALLOCATION (xsum (length, 1));
598     result[length] = '\0';
599
600     if (result != resultbuf && length + 1 < allocated)
601       {
602         /* Shrink the allocated memory if possible.  */
603         CHAR_T *memory;
604
605         memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
606         if (memory != NULL)
607           result = memory;
608       }
609
610     if (buf_malloced != NULL)
611       free (buf_malloced);
612     CLEANUP ();
613     *lengthp = length;
614     if (length > INT_MAX)
615       goto length_overflow;
616     return result;
617
618   length_overflow:
619     /* We could produce such a big string, but its length doesn't fit into
620        an 'int'.  POSIX says that snprintf() fails with errno = EOVERFLOW in
621        this case.  */
622     if (result != resultbuf)
623       free (result);
624     errno = EOVERFLOW;
625     return NULL;
626
627   out_of_memory:
628     if (!(result == resultbuf || result == NULL))
629       free (result);
630     if (buf_malloced != NULL)
631       free (buf_malloced);
632   out_of_memory_1:
633     CLEANUP ();
634     errno = ENOMEM;
635     return NULL;
636   }
637 }
638
639 #undef SNPRINTF
640 #undef USE_SNPRINTF
641 #undef PRINTF_PARSE
642 #undef DIRECTIVES
643 #undef DIRECTIVE
644 #undef CHAR_T
645 #undef VASNPRINTF
Note: See TracBrowser for help on using the browser.