(root)/
gcc-13.2.0/
libiberty/
_doprnt.c
       1  /* Provide a version of _doprnt in terms of fprintf.
       2     Copyright (C) 1998-2023 Free Software Foundation, Inc.
       3     Contributed by Kaveh Ghazi  (ghazi@caip.rutgers.edu)  3/29/98
       4  
       5  This program is free software; you can redistribute it and/or modify it
       6  under the terms of the GNU General Public License as published by the
       7  Free Software Foundation; either version 2, or (at your option) any
       8  later version.
       9  
      10  This program is distributed in the hope that it will be useful,
      11  but WITHOUT ANY WARRANTY; without even the implied warranty of
      12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13  GNU General Public License for more details.
      14  
      15  You should have received a copy of the GNU General Public License
      16  along with this program; if not, write to the Free Software
      17  Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
      18  
      19  #include "config.h"
      20  #include "ansidecl.h"
      21  #include "safe-ctype.h"
      22  
      23  #include <stdio.h>
      24  #include <stdarg.h>
      25  #ifdef HAVE_STRING_H
      26  #include <string.h>
      27  #endif
      28  #ifdef HAVE_STDLIB_H
      29  #include <stdlib.h>
      30  #endif
      31  
      32  #undef _doprnt
      33  
      34  #ifdef HAVE__DOPRNT
      35  #define TEST
      36  #endif
      37  
      38  #ifdef TEST /* Make sure to use the internal one.  */
      39  #define _doprnt my_doprnt
      40  #endif
      41  
      42  #define COPY_VA_INT \
      43    do { \
      44  	 const int value = abs (va_arg (ap, int)); \
      45  	 char buf[32]; \
      46  	 ptr++; /* Go past the asterisk.  */ \
      47  	 *sptr = '\0'; /* NULL terminate sptr.  */ \
      48  	 sprintf(buf, "%d", value); \
      49  	 strcat(sptr, buf); \
      50  	 while (*sptr) sptr++; \
      51       } while (0)
      52  
      53  #define PRINT_CHAR(CHAR) \
      54    do { \
      55  	 putc(CHAR, stream); \
      56  	 ptr++; \
      57  	 total_printed++; \
      58       } while (0)
      59  
      60  #define PRINT_TYPE(TYPE) \
      61    do { \
      62  	int result; \
      63  	TYPE value = va_arg (ap, TYPE); \
      64  	*sptr++ = *ptr++; /* Copy the type specifier.  */ \
      65  	*sptr = '\0'; /* NULL terminate sptr.  */ \
      66  	result = fprintf(stream, specifier, value); \
      67  	if (result == -1) \
      68  	  return -1; \
      69  	else \
      70  	  { \
      71  	    total_printed += result; \
      72  	    continue; \
      73  	  } \
      74        } while (0)
      75  
      76  int
      77  _doprnt (const char *format, va_list ap, FILE *stream)
      78  {
      79    const char * ptr = format;
      80    char specifier[128];
      81    int total_printed = 0;
      82    
      83    while (*ptr != '\0')
      84      {
      85        if (*ptr != '%') /* While we have regular characters, print them.  */
      86  	PRINT_CHAR(*ptr);
      87        else /* We got a format specifier! */
      88  	{
      89  	  char * sptr = specifier;
      90  	  int wide_width = 0, short_width = 0;
      91  	  
      92  	  *sptr++ = *ptr++; /* Copy the % and move forward.  */
      93  
      94  	  while (strchr ("-+ #0", *ptr)) /* Move past flags.  */
      95  	    *sptr++ = *ptr++;
      96  
      97  	  if (*ptr == '*')
      98  	    COPY_VA_INT;
      99  	  else
     100  	    while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
     101  	      *sptr++ = *ptr++;
     102  	  
     103  	  if (*ptr == '.')
     104  	    {
     105  	      *sptr++ = *ptr++; /* Copy and go past the period.  */
     106  	      if (*ptr == '*')
     107  		COPY_VA_INT;
     108  	      else
     109  		while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
     110  		  *sptr++ = *ptr++;
     111  	    }
     112  	  while (strchr ("hlL", *ptr))
     113  	    {
     114  	      switch (*ptr)
     115  		{
     116  		case 'h':
     117  		  short_width = 1;
     118  		  break;
     119  		case 'l':
     120  		  wide_width++;
     121  		  break;
     122  		case 'L':
     123  		  wide_width = 2;
     124  		  break;
     125  		default:
     126  		  abort();
     127  		}
     128  	      *sptr++ = *ptr++;
     129  	    }
     130  
     131  	  switch (*ptr)
     132  	    {
     133  	    case 'd':
     134  	    case 'i':
     135  	    case 'o':
     136  	    case 'u':
     137  	    case 'x':
     138  	    case 'X':
     139  	    case 'c':
     140  	      {
     141  		/* Short values are promoted to int, so just copy it
     142                     as an int and trust the C library printf to cast it
     143                     to the right width.  */
     144  		if (short_width)
     145  		  PRINT_TYPE(int);
     146  		else
     147  		  {
     148  		    switch (wide_width)
     149  		      {
     150  		      case 0:
     151  			PRINT_TYPE(int);
     152  			break;
     153  		      case 1:
     154  			PRINT_TYPE(long);
     155  			break;
     156  		      case 2:
     157  		      default:
     158  #if defined(__GNUC__) || defined(HAVE_LONG_LONG)
     159  			PRINT_TYPE(long long);
     160  #else
     161  			PRINT_TYPE(long); /* Fake it and hope for the best.  */
     162  #endif
     163  			break;
     164  		      } /* End of switch (wide_width) */
     165  		  } /* End of else statement */
     166  	      } /* End of integer case */
     167  	      break;
     168  	    case 'f':
     169  	    case 'e':
     170  	    case 'E':
     171  	    case 'g':
     172  	    case 'G':
     173  	      {
     174  		if (wide_width == 0)
     175  		  PRINT_TYPE(double);
     176  		else
     177  		  {
     178  #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
     179  		    PRINT_TYPE(long double);
     180  #else
     181  		    PRINT_TYPE(double); /* Fake it and hope for the best.  */
     182  #endif
     183  		  }
     184  	      }
     185  	      break;
     186  	    case 's':
     187  	      PRINT_TYPE(char *);
     188  	      break;
     189  	    case 'p':
     190  	      PRINT_TYPE(void *);
     191  	      break;
     192  	    case '%':
     193  	      PRINT_CHAR('%');
     194  	      break;
     195  	    default:
     196  	      abort();
     197  	    } /* End of switch (*ptr) */
     198  	} /* End of else statement */
     199      }
     200  
     201    return total_printed;
     202  }
     203  
     204  #ifdef TEST
     205  
     206  #include <math.h>
     207  #ifndef M_PI
     208  #define M_PI (3.1415926535897932385)
     209  #endif
     210  
     211  #define RESULT(x) do \
     212  { \
     213      int i = (x); \
     214      printf ("printed %d characters\n", i); \
     215      fflush(stdin); \
     216  } while (0)
     217  
     218  static int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1;
     219  
     220  static int
     221  checkit (const char* format, ...)
     222  {
     223    int result;
     224    va_list args;
     225    va_start (args, format);
     226  
     227    result = _doprnt (format, args, stdout);
     228    va_end (args);
     229  
     230    return result;
     231  }
     232  
     233  int
     234  main (void)
     235  {
     236    RESULT(checkit ("<%d>\n", 0x12345678));
     237    RESULT(printf ("<%d>\n", 0x12345678));
     238  
     239    RESULT(checkit ("<%200d>\n", 5));
     240    RESULT(printf ("<%200d>\n", 5));
     241  
     242    RESULT(checkit ("<%.300d>\n", 6));
     243    RESULT(printf ("<%.300d>\n", 6));
     244  
     245    RESULT(checkit ("<%100.150d>\n", 7));
     246    RESULT(printf ("<%100.150d>\n", 7));
     247  
     248    RESULT(checkit ("<%s>\n",
     249  		  "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
     250  777777777777777777333333333333366666666666622222222222777777777777733333"));
     251    RESULT(printf ("<%s>\n",
     252  		 "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
     253  777777777777777777333333333333366666666666622222222222777777777777733333"));
     254  
     255    RESULT(checkit ("<%f><%0+#f>%s%d%s>\n",
     256  		  1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
     257    RESULT(printf ("<%f><%0+#f>%s%d%s>\n",
     258  		 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
     259  
     260    RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
     261    RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
     262  
     263    RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
     264    RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
     265  
     266    RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
     267  		  75, 75, 75, 75, 75, 75, 75));
     268    RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
     269  		 75, 75, 75, 75, 75, 75, 75));
     270  
     271    RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
     272  		  75, 75, 75, 75, 75, 75, 75));
     273    RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
     274  		 75, 75, 75, 75, 75, 75, 75));
     275  
     276    RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
     277    RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
     278  
     279  #if defined(__GNUC__) || defined (HAVE_LONG_LONG)
     280    RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
     281    RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
     282    RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
     283    RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
     284  #endif
     285  
     286  #if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE)
     287    RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
     288  		  1.23456, 1.234567890123456789L, 1.23456));
     289    RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
     290  		 1.23456, 1.234567890123456789L, 1.23456));
     291  #endif
     292  
     293    return 0;
     294  }
     295  #endif /* TEST */