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
5This file is part of the libiberty library.
6Libiberty is free software; you can redistribute it and/or
7modify it under the terms of the GNU Library General Public
8License as published by the Free Software Foundation; either
9version 2 of the License, or (at your option) any later version.
10
11Libiberty is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14Library General Public License for more details.
15
16You should have received a copy of the GNU Library General Public
17License along with libiberty; see the file COPYING.LIB.  If not, write
18to the Free Software Foundation, Inc., 51 Franklin Street - Fifth
19Floor, 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
36extern unsigned long strtoul ();
37#endif
38#include "libiberty.h"
39
40int
41libiberty_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