1/* Estimate the length of the string generated by a vprintf-like
2   function.  Used by vasprintf and xvasprintf.
3   Copyright (C) 1994-2020 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#include "vprintf-support.h"
40
41int
42libiberty_vprintf_buffer_size (const char *format, va_list args)
43{
44  const char *p = format;
45  /* Add one to make sure that it is never zero, which might cause malloc
46     to return NULL.  */
47  int total_width = strlen (format) + 1;
48  va_list ap;
49
50#ifdef va_copy
51  va_copy (ap, args);
52#else
53  memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list));
54#endif
55
56  while (*p != '\0')
57    {
58      if (*p++ == '%')
59	{
60	  while (strchr ("-+ #0", *p))
61	    ++p;
62	  if (*p == '*')
63	    {
64	      ++p;
65	      total_width += abs (va_arg (ap, int));
66	    }
67	  else
68	    total_width += strtoul (p, (char **) &p, 10);
69	  if (*p == '.')
70	    {
71	      ++p;
72	      if (*p == '*')
73		{
74		  ++p;
75		  total_width += abs (va_arg (ap, int));
76		}
77	      else
78	      total_width += strtoul (p, (char **) &p, 10);
79	    }
80	  while (strchr ("hlL", *p))
81	    ++p;
82	  /* Should be big enough for any format specifier except %s and floats.  */
83	  total_width += 30;
84	  switch (*p)
85	    {
86	    case 'd':
87	    case 'i':
88	    case 'o':
89	    case 'u':
90	    case 'x':
91	    case 'X':
92	    case 'c':
93	      (void) va_arg (ap, int);
94	      break;
95	    case 'f':
96	    case 'e':
97	    case 'E':
98	    case 'g':
99	    case 'G':
100	      (void) va_arg (ap, double);
101	      /* Since an ieee double can have an exponent of 307, we'll
102		 make the buffer wide enough to cover the gross case. */
103	      total_width += 307;
104	      break;
105	    case 's':
106	      total_width += strlen (va_arg (ap, char *));
107	      break;
108	    case 'p':
109	    case 'n':
110	      (void) va_arg (ap, char *);
111	      break;
112	    }
113	  p++;
114	}
115    }
116#ifdef va_copy
117  va_end (ap);
118#endif
119  return total_width;
120}
121