Home | History | Annotate | Line # | Download | only in libiberty
_doprnt.c revision 1.1.1.10
      1 /* Provide a version of _doprnt in terms of fprintf.
      2    Copyright (C) 1998-2024 Free Software Foundation, Inc.
      3    Contributed by Kaveh Ghazi  (ghazi (at) 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 */
    296