Home | History | Annotate | Download | only in libiberty
      1 /* Estimate the length of the string generated by a vprintf-like
      2    function.  Used by vasprintf and xvasprintf.
      3    Copyright (C) 1994, 2003, 2011, 2013, 2014 Free Software Foundation, Inc.
      4 
      5 This file is part of the libiberty library.
      6 Libiberty is free software; you can redistribute it and/or
      7 modify it under the terms of the GNU Library General Public
      8 License as published by the Free Software Foundation; either
      9 version 2 of the License, or (at your option) any later version.
     10 
     11 Libiberty is distributed in the hope that it will be useful,
     12 but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 Library General Public License for more details.
     15 
     16 You should have received a copy of the GNU Library General Public
     17 License along with libiberty; see the file COPYING.LIB.  If not, write
     18 to the Free Software Foundation, Inc., 51 Franklin Street - Fifth
     19 Floor, Boston, MA 02110-1301, USA.  */
     20 
     21 #ifdef HAVE_CONFIG_H
     22 #include "config.h"
     23 #endif
     24 #include <ansidecl.h>
     25 #include <stdarg.h>
     26 #if !defined (va_copy) && defined (__va_copy)
     27 # define va_copy(d,s)  __va_copy((d),(s))
     28 #endif
     29 #include <stdio.h>
     30 #ifdef HAVE_STRING_H
     31 #include <string.h>
     32 #endif
     33 #ifdef HAVE_STDLIB_H
     34 #include <stdlib.h>
     35 #else
     36 extern unsigned long strtoul ();
     37 #endif
     38 #include "libiberty.h"
     39 
     40 int
     41 libiberty_vprintf_buffer_size (const char *format, va_list args)
     42 {
     43   const char *p = format;
     44   /* Add one to make sure that it is never zero, which might cause malloc
     45      to return NULL.  */
     46   int total_width = strlen (format) + 1;
     47   va_list ap;
     48 
     49 #ifdef va_copy
     50   va_copy (ap, args);
     51 #else
     52   memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list));
     53 #endif
     54 
     55   while (*p != '\0')
     56     {
     57       if (*p++ == '%')
     58 	{
     59 	  while (strchr ("-+ #0", *p))
     60 	    ++p;
     61 	  if (*p == '*')
     62 	    {
     63 	      ++p;
     64 	      total_width += abs (va_arg (ap, int));
     65 	    }
     66 	  else
     67 	    total_width += strtoul (p, (char **) &p, 10);
     68 	  if (*p == '.')
     69 	    {
     70 	      ++p;
     71 	      if (*p == '*')
     72 		{
     73 		  ++p;
     74 		  total_width += abs (va_arg (ap, int));
     75 		}
     76 	      else
     77 	      total_width += strtoul (p, (char **) &p, 10);
     78 	    }
     79 	  while (strchr ("hlL", *p))
     80 	    ++p;
     81 	  /* Should be big enough for any format specifier except %s and floats.  */
     82 	  total_width += 30;
     83 	  switch (*p)
     84 	    {
     85 	    case 'd':
     86 	    case 'i':
     87 	    case 'o':
     88 	    case 'u':
     89 	    case 'x':
     90 	    case 'X':
     91 	    case 'c':
     92 	      (void) va_arg (ap, int);
     93 	      break;
     94 	    case 'f':
     95 	    case 'e':
     96 	    case 'E':
     97 	    case 'g':
     98 	    case 'G':
     99 	      (void) va_arg (ap, double);
    100 	      /* Since an ieee double can have an exponent of 307, we'll
    101 		 make the buffer wide enough to cover the gross case. */
    102 	      total_width += 307;
    103 	      break;
    104 	    case 's':
    105 	      total_width += strlen (va_arg (ap, char *));
    106 	      break;
    107 	    case 'p':
    108 	    case 'n':
    109 	      (void) va_arg (ap, char *);
    110 	      break;
    111 	    }
    112 	  p++;
    113 	}
    114     }
    115 #ifdef va_copy
    116   va_end (ap);
    117 #endif
    118   return total_width;
    119 }
    120