xref: /netbsd-src/external/gpl3/binutils/dist/libiberty/vprintf-support.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
19573673dSchristos /* Estimate the length of the string generated by a vprintf-like
29573673dSchristos    function.  Used by vasprintf and xvasprintf.
3*cb63e24eSchristos    Copyright (C) 1994-2024 Free Software Foundation, Inc.
49573673dSchristos 
59573673dSchristos This file is part of the libiberty library.
69573673dSchristos Libiberty is free software; you can redistribute it and/or
79573673dSchristos modify it under the terms of the GNU Library General Public
89573673dSchristos License as published by the Free Software Foundation; either
99573673dSchristos version 2 of the License, or (at your option) any later version.
109573673dSchristos 
119573673dSchristos Libiberty is distributed in the hope that it will be useful,
129573673dSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
139573673dSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
149573673dSchristos Library General Public License for more details.
159573673dSchristos 
169573673dSchristos You should have received a copy of the GNU Library General Public
179573673dSchristos License along with libiberty; see the file COPYING.LIB.  If not, write
189573673dSchristos to the Free Software Foundation, Inc., 51 Franklin Street - Fifth
199573673dSchristos Floor, Boston, MA 02110-1301, USA.  */
209573673dSchristos 
219573673dSchristos #ifdef HAVE_CONFIG_H
229573673dSchristos #include "config.h"
239573673dSchristos #endif
249573673dSchristos #include <ansidecl.h>
259573673dSchristos #include <stdarg.h>
269573673dSchristos #if !defined (va_copy) && defined (__va_copy)
279573673dSchristos # define va_copy(d,s)  __va_copy((d),(s))
289573673dSchristos #endif
299573673dSchristos #include <stdio.h>
309573673dSchristos #ifdef HAVE_STRING_H
319573673dSchristos #include <string.h>
329573673dSchristos #endif
339573673dSchristos #ifdef HAVE_STDLIB_H
349573673dSchristos #include <stdlib.h>
359573673dSchristos #else
369573673dSchristos extern unsigned long strtoul ();
379573673dSchristos #endif
389573673dSchristos #include "libiberty.h"
399573673dSchristos 
409573673dSchristos int
libiberty_vprintf_buffer_size(const char * format,va_list args)419573673dSchristos libiberty_vprintf_buffer_size (const char *format, va_list args)
429573673dSchristos {
439573673dSchristos   const char *p = format;
449573673dSchristos   /* Add one to make sure that it is never zero, which might cause malloc
459573673dSchristos      to return NULL.  */
469573673dSchristos   int total_width = strlen (format) + 1;
479573673dSchristos   va_list ap;
489573673dSchristos 
499573673dSchristos #ifdef va_copy
509573673dSchristos   va_copy (ap, args);
519573673dSchristos #else
524f645668Schristos   memcpy ((void *) &ap, (void *) &args, sizeof (va_list));
539573673dSchristos #endif
549573673dSchristos 
559573673dSchristos   while (*p != '\0')
569573673dSchristos     {
579573673dSchristos       if (*p++ == '%')
589573673dSchristos 	{
599573673dSchristos 	  while (strchr ("-+ #0", *p))
609573673dSchristos 	    ++p;
619573673dSchristos 	  if (*p == '*')
629573673dSchristos 	    {
639573673dSchristos 	      ++p;
649573673dSchristos 	      total_width += abs (va_arg (ap, int));
659573673dSchristos 	    }
669573673dSchristos 	  else
679573673dSchristos 	    total_width += strtoul (p, (char **) &p, 10);
689573673dSchristos 	  if (*p == '.')
699573673dSchristos 	    {
709573673dSchristos 	      ++p;
719573673dSchristos 	      if (*p == '*')
729573673dSchristos 		{
739573673dSchristos 		  ++p;
749573673dSchristos 		  total_width += abs (va_arg (ap, int));
759573673dSchristos 		}
769573673dSchristos 	      else
779573673dSchristos 	      total_width += strtoul (p, (char **) &p, 10);
789573673dSchristos 	    }
799573673dSchristos 	  while (strchr ("hlL", *p))
809573673dSchristos 	    ++p;
819573673dSchristos 	  /* Should be big enough for any format specifier except %s and floats.  */
829573673dSchristos 	  total_width += 30;
839573673dSchristos 	  switch (*p)
849573673dSchristos 	    {
859573673dSchristos 	    case 'd':
869573673dSchristos 	    case 'i':
879573673dSchristos 	    case 'o':
889573673dSchristos 	    case 'u':
899573673dSchristos 	    case 'x':
909573673dSchristos 	    case 'X':
919573673dSchristos 	    case 'c':
929573673dSchristos 	      (void) va_arg (ap, int);
939573673dSchristos 	      break;
949573673dSchristos 	    case 'f':
959573673dSchristos 	    case 'e':
969573673dSchristos 	    case 'E':
979573673dSchristos 	    case 'g':
989573673dSchristos 	    case 'G':
999573673dSchristos 	      (void) va_arg (ap, double);
1009573673dSchristos 	      /* Since an ieee double can have an exponent of 307, we'll
1019573673dSchristos 		 make the buffer wide enough to cover the gross case. */
1029573673dSchristos 	      total_width += 307;
1039573673dSchristos 	      break;
1049573673dSchristos 	    case 's':
1059573673dSchristos 	      total_width += strlen (va_arg (ap, char *));
1069573673dSchristos 	      break;
1079573673dSchristos 	    case 'p':
1089573673dSchristos 	    case 'n':
1099573673dSchristos 	      (void) va_arg (ap, char *);
1109573673dSchristos 	      break;
1119573673dSchristos 	    }
1129573673dSchristos 	  p++;
1139573673dSchristos 	}
1149573673dSchristos     }
1159573673dSchristos #ifdef va_copy
1169573673dSchristos   va_end (ap);
1179573673dSchristos #endif
1189573673dSchristos   return total_width;
1199573673dSchristos }
120