Home | History | Annotate | Line # | Download | only in libgettextpo
      1  1.1  christos /* Like vsprintf but provides a pointer to malloc'd storage, which must
      2  1.1  christos    be freed by the caller.
      3  1.1  christos    Copyright (C) 1994, 1998, 1999, 2000-2003, 2006 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos This program is free software; you can redistribute it and/or modify
      6  1.1  christos it under the terms of the GNU General Public License as published by
      7  1.1  christos the Free Software Foundation; either version 2, or (at your option)
      8  1.1  christos any later version.
      9  1.1  christos 
     10  1.1  christos This program is distributed in the hope that it will be useful,
     11  1.1  christos but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  1.1  christos GNU General Public License for more details.
     14  1.1  christos 
     15  1.1  christos You should have received a copy of the GNU General Public License
     16  1.1  christos along with this program; if not, write to the Free Software Foundation,
     17  1.1  christos Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
     18  1.1  christos 
     19  1.1  christos #include <config.h>
     20  1.1  christos 
     21  1.1  christos /* Specification.  */
     22  1.1  christos #include "vasprintf.h"
     23  1.1  christos 
     24  1.1  christos #include <stdio.h>
     25  1.1  christos #include <string.h>
     26  1.1  christos #include <stdlib.h>
     27  1.1  christos #include <stdarg.h>
     28  1.1  christos #include <math.h>
     29  1.1  christos 
     30  1.1  christos #ifdef TEST
     31  1.1  christos size_t global_total_width;
     32  1.1  christos #endif
     33  1.1  christos 
     34  1.1  christos static int
     35  1.1  christos int_vasprintf (char **result, const char *format, va_list *args)
     36  1.1  christos {
     37  1.1  christos   const char *p = format;
     38  1.1  christos   /* Add one to make sure that it is never zero, which might cause malloc
     39  1.1  christos      to return NULL.  */
     40  1.1  christos   size_t total_width = strlen (format) + 1;
     41  1.1  christos   va_list ap = *args;
     42  1.1  christos 
     43  1.1  christos   while (*p != '\0')
     44  1.1  christos     {
     45  1.1  christos       if (*p++ == '%')
     46  1.1  christos 	{
     47  1.1  christos 	  while (strchr ("-+ #0", *p))
     48  1.1  christos 	    ++p;
     49  1.1  christos 	  if (*p == '*')
     50  1.1  christos 	    {
     51  1.1  christos 	      ++p;
     52  1.1  christos 	      total_width += abs (va_arg (ap, int));
     53  1.1  christos 	    }
     54  1.1  christos 	  else
     55  1.1  christos 	    total_width += strtoul (p, (char **) &p, 10);
     56  1.1  christos 	  if (*p == '.')
     57  1.1  christos 	    {
     58  1.1  christos 	      ++p;
     59  1.1  christos 	      if (*p == '*')
     60  1.1  christos 		{
     61  1.1  christos 		  ++p;
     62  1.1  christos 		  total_width += abs (va_arg (ap, int));
     63  1.1  christos 		}
     64  1.1  christos 	      else
     65  1.1  christos 		total_width += strtoul (p, (char **) &p, 10);
     66  1.1  christos 	    }
     67  1.1  christos 	  while (strchr ("hlLjtz", *p))
     68  1.1  christos 	    ++p;
     69  1.1  christos 	  /* Should be big enough for any format specifier except %s
     70  1.1  christos 	     and floats.  */
     71  1.1  christos 	  total_width += 30;
     72  1.1  christos 	  switch (*p)
     73  1.1  christos 	    {
     74  1.1  christos 	    case 'd':
     75  1.1  christos 	    case 'i':
     76  1.1  christos 	    case 'o':
     77  1.1  christos 	    case 'u':
     78  1.1  christos 	    case 'x':
     79  1.1  christos 	    case 'X':
     80  1.1  christos 	    case 'c':
     81  1.1  christos 	      (void) va_arg (ap, int);
     82  1.1  christos 	      break;
     83  1.1  christos 	    case 'f':
     84  1.1  christos 	    case 'F':
     85  1.1  christos 	      {
     86  1.1  christos 		double arg = va_arg (ap, double);
     87  1.1  christos 		if (arg >= 1.0 || arg <= -1.0)
     88  1.1  christos 		  /* Since an ieee double can have an exponent of 307, we'll
     89  1.1  christos 		     make the buffer wide enough to cover the gross case. */
     90  1.1  christos 		  total_width += 307;
     91  1.1  christos 	      }
     92  1.1  christos 	      break;
     93  1.1  christos 	    case 'e':
     94  1.1  christos 	    case 'E':
     95  1.1  christos 	    case 'g':
     96  1.1  christos 	    case 'G':
     97  1.1  christos 	      (void) va_arg (ap, double);
     98  1.1  christos 	      break;
     99  1.1  christos 	    case 's':
    100  1.1  christos 	      total_width += strlen (va_arg (ap, char *));
    101  1.1  christos 	      break;
    102  1.1  christos 	    case 'p':
    103  1.1  christos 	    case 'n':
    104  1.1  christos 	      (void) va_arg (ap, char *);
    105  1.1  christos 	      break;
    106  1.1  christos 	    }
    107  1.1  christos 	  p++;
    108  1.1  christos 	}
    109  1.1  christos     }
    110  1.1  christos #ifdef TEST
    111  1.1  christos   global_total_width = total_width;
    112  1.1  christos #endif
    113  1.1  christos   *result = malloc (total_width);
    114  1.1  christos   if (*result != NULL)
    115  1.1  christos     return vsprintf (*result, format, *args);
    116  1.1  christos   else
    117  1.1  christos     return -1;
    118  1.1  christos }
    119  1.1  christos 
    120  1.1  christos int
    121  1.1  christos vasprintf (char **result, const char *format, va_list args)
    122  1.1  christos {
    123  1.1  christos   return int_vasprintf (result, format, &args);
    124  1.1  christos }
    125  1.1  christos 
    126  1.1  christos int
    127  1.1  christos asprintf (char **result, const char *format, ...)
    128  1.1  christos {
    129  1.1  christos   va_list args;
    130  1.1  christos   int done;
    131  1.1  christos 
    132  1.1  christos   va_start (args, format);
    133  1.1  christos   done = vasprintf (result, format, args);
    134  1.1  christos   va_end (args);
    135  1.1  christos 
    136  1.1  christos   return done;
    137  1.1  christos }
    138  1.1  christos 
    139  1.1  christos /* ========================= test program ========================= */
    140  1.1  christos 
    141  1.1  christos #ifdef TEST
    142  1.1  christos 
    143  1.1  christos #include <float.h>
    144  1.1  christos 
    145  1.1  christos void
    146  1.1  christos checkit (const char* format, ...)
    147  1.1  christos {
    148  1.1  christos   va_list args;
    149  1.1  christos   char *result;
    150  1.1  christos 
    151  1.1  christos   va_start (args, format);
    152  1.1  christos   vasprintf (&result, format, args);
    153  1.1  christos   if (strlen (result) < global_total_width)
    154  1.1  christos     printf ("PASS: ");
    155  1.1  christos   else
    156  1.1  christos     printf ("FAIL: ");
    157  1.1  christos   printf ("%lu %s\n", (unsigned long) global_total_width, result);
    158  1.1  christos }
    159  1.1  christos 
    160  1.1  christos int
    161  1.1  christos main ()
    162  1.1  christos {
    163  1.1  christos   checkit ("%d", 0x12345678);
    164  1.1  christos   checkit ("%200d", 5);
    165  1.1  christos   checkit ("%.300d", 6);
    166  1.1  christos   checkit ("%100.150d", 7);
    167  1.1  christos   checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
    168  1.1  christos 777777777777777777333333333333366666666666622222222222777777777777733333");
    169  1.1  christos   checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
    170  1.1  christos   checkit ("%e", DBL_MIN);
    171  1.1  christos   checkit ("%e", DBL_MAX);
    172  1.1  christos   checkit ("%.400f", DBL_MIN);
    173  1.1  christos   checkit ("%f", DBL_MAX);
    174  1.1  christos   checkit ("%g", DBL_MIN);
    175  1.1  christos   checkit ("%g", DBL_MAX);
    176  1.1  christos   return 0;
    177  1.1  christos }
    178  1.1  christos 
    179  1.1  christos #endif /* TEST */
    180