xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/_doprnt.c (revision 7e120ff03ede3fe64e2c8620c01465d528502ddb)
198b9484cSchristos /* Provide a version of _doprnt in terms of fprintf.
2*7e120ff0Schristos    Copyright (C) 1998-2024 Free Software Foundation, Inc.
398b9484cSchristos    Contributed by Kaveh Ghazi  (ghazi@caip.rutgers.edu)  3/29/98
498b9484cSchristos 
598b9484cSchristos This program is free software; you can redistribute it and/or modify it
698b9484cSchristos under the terms of the GNU General Public License as published by the
798b9484cSchristos Free Software Foundation; either version 2, or (at your option) any
898b9484cSchristos later version.
998b9484cSchristos 
1098b9484cSchristos This program is distributed in the hope that it will be useful,
1198b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1298b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1398b9484cSchristos GNU General Public License for more details.
1498b9484cSchristos 
1598b9484cSchristos You should have received a copy of the GNU General Public License
1698b9484cSchristos along with this program; if not, write to the Free Software
1798b9484cSchristos Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
1898b9484cSchristos 
1998b9484cSchristos #include "config.h"
2098b9484cSchristos #include "ansidecl.h"
2198b9484cSchristos #include "safe-ctype.h"
2298b9484cSchristos 
2398b9484cSchristos #include <stdio.h>
2498b9484cSchristos #include <stdarg.h>
2598b9484cSchristos #ifdef HAVE_STRING_H
2698b9484cSchristos #include <string.h>
2798b9484cSchristos #endif
2898b9484cSchristos #ifdef HAVE_STDLIB_H
2998b9484cSchristos #include <stdlib.h>
3098b9484cSchristos #endif
3198b9484cSchristos 
3298b9484cSchristos #undef _doprnt
3398b9484cSchristos 
3498b9484cSchristos #ifdef HAVE__DOPRNT
3598b9484cSchristos #define TEST
3698b9484cSchristos #endif
3798b9484cSchristos 
3898b9484cSchristos #ifdef TEST /* Make sure to use the internal one.  */
3998b9484cSchristos #define _doprnt my_doprnt
4098b9484cSchristos #endif
4198b9484cSchristos 
4298b9484cSchristos #define COPY_VA_INT \
4398b9484cSchristos   do { \
4498b9484cSchristos 	 const int value = abs (va_arg (ap, int)); \
4598b9484cSchristos 	 char buf[32]; \
4698b9484cSchristos 	 ptr++; /* Go past the asterisk.  */ \
4798b9484cSchristos 	 *sptr = '\0'; /* NULL terminate sptr.  */ \
4898b9484cSchristos 	 sprintf(buf, "%d", value); \
4998b9484cSchristos 	 strcat(sptr, buf); \
5098b9484cSchristos 	 while (*sptr) sptr++; \
5198b9484cSchristos      } while (0)
5298b9484cSchristos 
5398b9484cSchristos #define PRINT_CHAR(CHAR) \
5498b9484cSchristos   do { \
5598b9484cSchristos 	 putc(CHAR, stream); \
5698b9484cSchristos 	 ptr++; \
5798b9484cSchristos 	 total_printed++; \
5898b9484cSchristos      } while (0)
5998b9484cSchristos 
6098b9484cSchristos #define PRINT_TYPE(TYPE) \
6198b9484cSchristos   do { \
6298b9484cSchristos 	int result; \
6398b9484cSchristos 	TYPE value = va_arg (ap, TYPE); \
6498b9484cSchristos 	*sptr++ = *ptr++; /* Copy the type specifier.  */ \
6598b9484cSchristos 	*sptr = '\0'; /* NULL terminate sptr.  */ \
6698b9484cSchristos 	result = fprintf(stream, specifier, value); \
6798b9484cSchristos 	if (result == -1) \
6898b9484cSchristos 	  return -1; \
6998b9484cSchristos 	else \
7098b9484cSchristos 	  { \
7198b9484cSchristos 	    total_printed += result; \
7298b9484cSchristos 	    continue; \
7398b9484cSchristos 	  } \
7498b9484cSchristos       } while (0)
7598b9484cSchristos 
7698b9484cSchristos int
7798b9484cSchristos _doprnt (const char *format, va_list ap, FILE *stream)
7898b9484cSchristos {
7998b9484cSchristos   const char * ptr = format;
8098b9484cSchristos   char specifier[128];
8198b9484cSchristos   int total_printed = 0;
8298b9484cSchristos 
8398b9484cSchristos   while (*ptr != '\0')
8498b9484cSchristos     {
8598b9484cSchristos       if (*ptr != '%') /* While we have regular characters, print them.  */
8698b9484cSchristos 	PRINT_CHAR(*ptr);
8798b9484cSchristos       else /* We got a format specifier! */
8898b9484cSchristos 	{
8998b9484cSchristos 	  char * sptr = specifier;
9098b9484cSchristos 	  int wide_width = 0, short_width = 0;
9198b9484cSchristos 
9298b9484cSchristos 	  *sptr++ = *ptr++; /* Copy the % and move forward.  */
9398b9484cSchristos 
9498b9484cSchristos 	  while (strchr ("-+ #0", *ptr)) /* Move past flags.  */
9598b9484cSchristos 	    *sptr++ = *ptr++;
9698b9484cSchristos 
9798b9484cSchristos 	  if (*ptr == '*')
9898b9484cSchristos 	    COPY_VA_INT;
9998b9484cSchristos 	  else
10098b9484cSchristos 	    while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
10198b9484cSchristos 	      *sptr++ = *ptr++;
10298b9484cSchristos 
10398b9484cSchristos 	  if (*ptr == '.')
10498b9484cSchristos 	    {
10598b9484cSchristos 	      *sptr++ = *ptr++; /* Copy and go past the period.  */
10698b9484cSchristos 	      if (*ptr == '*')
10798b9484cSchristos 		COPY_VA_INT;
10898b9484cSchristos 	      else
10998b9484cSchristos 		while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
11098b9484cSchristos 		  *sptr++ = *ptr++;
11198b9484cSchristos 	    }
11298b9484cSchristos 	  while (strchr ("hlL", *ptr))
11398b9484cSchristos 	    {
11498b9484cSchristos 	      switch (*ptr)
11598b9484cSchristos 		{
11698b9484cSchristos 		case 'h':
11798b9484cSchristos 		  short_width = 1;
11898b9484cSchristos 		  break;
11998b9484cSchristos 		case 'l':
12098b9484cSchristos 		  wide_width++;
12198b9484cSchristos 		  break;
12298b9484cSchristos 		case 'L':
12398b9484cSchristos 		  wide_width = 2;
12498b9484cSchristos 		  break;
12598b9484cSchristos 		default:
12698b9484cSchristos 		  abort();
12798b9484cSchristos 		}
12898b9484cSchristos 	      *sptr++ = *ptr++;
12998b9484cSchristos 	    }
13098b9484cSchristos 
13198b9484cSchristos 	  switch (*ptr)
13298b9484cSchristos 	    {
13398b9484cSchristos 	    case 'd':
13498b9484cSchristos 	    case 'i':
13598b9484cSchristos 	    case 'o':
13698b9484cSchristos 	    case 'u':
13798b9484cSchristos 	    case 'x':
13898b9484cSchristos 	    case 'X':
13998b9484cSchristos 	    case 'c':
14098b9484cSchristos 	      {
14198b9484cSchristos 		/* Short values are promoted to int, so just copy it
14298b9484cSchristos                    as an int and trust the C library printf to cast it
14398b9484cSchristos                    to the right width.  */
14498b9484cSchristos 		if (short_width)
14598b9484cSchristos 		  PRINT_TYPE(int);
14698b9484cSchristos 		else
14798b9484cSchristos 		  {
14898b9484cSchristos 		    switch (wide_width)
14998b9484cSchristos 		      {
15098b9484cSchristos 		      case 0:
15198b9484cSchristos 			PRINT_TYPE(int);
15298b9484cSchristos 			break;
15398b9484cSchristos 		      case 1:
15498b9484cSchristos 			PRINT_TYPE(long);
15598b9484cSchristos 			break;
15698b9484cSchristos 		      case 2:
15798b9484cSchristos 		      default:
15898b9484cSchristos #if defined(__GNUC__) || defined(HAVE_LONG_LONG)
15998b9484cSchristos 			PRINT_TYPE(long long);
16098b9484cSchristos #else
16198b9484cSchristos 			PRINT_TYPE(long); /* Fake it and hope for the best.  */
16298b9484cSchristos #endif
16398b9484cSchristos 			break;
16498b9484cSchristos 		      } /* End of switch (wide_width) */
16598b9484cSchristos 		  } /* End of else statement */
16698b9484cSchristos 	      } /* End of integer case */
16798b9484cSchristos 	      break;
16898b9484cSchristos 	    case 'f':
16998b9484cSchristos 	    case 'e':
17098b9484cSchristos 	    case 'E':
17198b9484cSchristos 	    case 'g':
17298b9484cSchristos 	    case 'G':
17398b9484cSchristos 	      {
17498b9484cSchristos 		if (wide_width == 0)
17598b9484cSchristos 		  PRINT_TYPE(double);
17698b9484cSchristos 		else
17798b9484cSchristos 		  {
17898b9484cSchristos #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
17998b9484cSchristos 		    PRINT_TYPE(long double);
18098b9484cSchristos #else
18198b9484cSchristos 		    PRINT_TYPE(double); /* Fake it and hope for the best.  */
18298b9484cSchristos #endif
18398b9484cSchristos 		  }
18498b9484cSchristos 	      }
18598b9484cSchristos 	      break;
18698b9484cSchristos 	    case 's':
18798b9484cSchristos 	      PRINT_TYPE(char *);
18898b9484cSchristos 	      break;
18998b9484cSchristos 	    case 'p':
19098b9484cSchristos 	      PRINT_TYPE(void *);
19198b9484cSchristos 	      break;
19298b9484cSchristos 	    case '%':
19398b9484cSchristos 	      PRINT_CHAR('%');
19498b9484cSchristos 	      break;
19598b9484cSchristos 	    default:
19698b9484cSchristos 	      abort();
19798b9484cSchristos 	    } /* End of switch (*ptr) */
19898b9484cSchristos 	} /* End of else statement */
19998b9484cSchristos     }
20098b9484cSchristos 
20198b9484cSchristos   return total_printed;
20298b9484cSchristos }
20398b9484cSchristos 
20498b9484cSchristos #ifdef TEST
20598b9484cSchristos 
20698b9484cSchristos #include <math.h>
20798b9484cSchristos #ifndef M_PI
20898b9484cSchristos #define M_PI (3.1415926535897932385)
20998b9484cSchristos #endif
21098b9484cSchristos 
21198b9484cSchristos #define RESULT(x) do \
21298b9484cSchristos { \
21398b9484cSchristos     int i = (x); \
21498b9484cSchristos     printf ("printed %d characters\n", i); \
21598b9484cSchristos     fflush(stdin); \
21698b9484cSchristos } while (0)
21798b9484cSchristos 
21898b9484cSchristos static int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1;
21998b9484cSchristos 
22098b9484cSchristos static int
22198b9484cSchristos checkit (const char* format, ...)
22298b9484cSchristos {
22398b9484cSchristos   int result;
224837edd6bSchristos   va_list args;
225837edd6bSchristos   va_start (args, format);
22698b9484cSchristos 
22798b9484cSchristos   result = _doprnt (format, args, stdout);
228837edd6bSchristos   va_end (args);
22998b9484cSchristos 
23098b9484cSchristos   return result;
23198b9484cSchristos }
23298b9484cSchristos 
23398b9484cSchristos int
23498b9484cSchristos main (void)
23598b9484cSchristos {
23698b9484cSchristos   RESULT(checkit ("<%d>\n", 0x12345678));
23798b9484cSchristos   RESULT(printf ("<%d>\n", 0x12345678));
23898b9484cSchristos 
23998b9484cSchristos   RESULT(checkit ("<%200d>\n", 5));
24098b9484cSchristos   RESULT(printf ("<%200d>\n", 5));
24198b9484cSchristos 
24298b9484cSchristos   RESULT(checkit ("<%.300d>\n", 6));
24398b9484cSchristos   RESULT(printf ("<%.300d>\n", 6));
24498b9484cSchristos 
24598b9484cSchristos   RESULT(checkit ("<%100.150d>\n", 7));
24698b9484cSchristos   RESULT(printf ("<%100.150d>\n", 7));
24798b9484cSchristos 
24898b9484cSchristos   RESULT(checkit ("<%s>\n",
24998b9484cSchristos 		  "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
25098b9484cSchristos 777777777777777777333333333333366666666666622222222222777777777777733333"));
25198b9484cSchristos   RESULT(printf ("<%s>\n",
25298b9484cSchristos 		 "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
25398b9484cSchristos 777777777777777777333333333333366666666666622222222222777777777777733333"));
25498b9484cSchristos 
25598b9484cSchristos   RESULT(checkit ("<%f><%0+#f>%s%d%s>\n",
25698b9484cSchristos 		  1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
25798b9484cSchristos   RESULT(printf ("<%f><%0+#f>%s%d%s>\n",
25898b9484cSchristos 		 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
25998b9484cSchristos 
26098b9484cSchristos   RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
26198b9484cSchristos   RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
26298b9484cSchristos 
26398b9484cSchristos   RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
26498b9484cSchristos   RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
26598b9484cSchristos 
26698b9484cSchristos   RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
26798b9484cSchristos 		  75, 75, 75, 75, 75, 75, 75));
26898b9484cSchristos   RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
26998b9484cSchristos 		 75, 75, 75, 75, 75, 75, 75));
27098b9484cSchristos 
27198b9484cSchristos   RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
27298b9484cSchristos 		  75, 75, 75, 75, 75, 75, 75));
27398b9484cSchristos   RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
27498b9484cSchristos 		 75, 75, 75, 75, 75, 75, 75));
27598b9484cSchristos 
27698b9484cSchristos   RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
27798b9484cSchristos   RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
27898b9484cSchristos 
27998b9484cSchristos #if defined(__GNUC__) || defined (HAVE_LONG_LONG)
28098b9484cSchristos   RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
28198b9484cSchristos   RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
28298b9484cSchristos   RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
28398b9484cSchristos   RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
28498b9484cSchristos #endif
28598b9484cSchristos 
28698b9484cSchristos #if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE)
28798b9484cSchristos   RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
28898b9484cSchristos 		  1.23456, 1.234567890123456789L, 1.23456));
28998b9484cSchristos   RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
29098b9484cSchristos 		 1.23456, 1.234567890123456789L, 1.23456));
29198b9484cSchristos #endif
29298b9484cSchristos 
29398b9484cSchristos   return 0;
29498b9484cSchristos }
29598b9484cSchristos #endif /* TEST */
296