Home | History | Annotate | Download | only in libiberty
      1 /* Provide a version of _doprnt in terms of fprintf.
      2    Copyright (C) 1998, 1999, 2000, 2001, 2002   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 	 continue; \
     59      } while (0)
     60 
     61 #define PRINT_TYPE(TYPE) \
     62   do { \
     63 	int result; \
     64 	TYPE value = va_arg (ap, TYPE); \
     65 	*sptr++ = *ptr++; /* Copy the type specifier.  */ \
     66 	*sptr = '\0'; /* NULL terminate sptr.  */ \
     67 	result = fprintf(stream, specifier, value); \
     68 	if (result == -1) \
     69 	  return -1; \
     70 	else \
     71 	  { \
     72 	    total_printed += result; \
     73 	    continue; \
     74 	  } \
     75       } while (0)
     76 
     77 int
     78 _doprnt (const char *format, va_list ap, FILE *stream)
     79 {
     80   const char * ptr = format;
     81   char specifier[128];
     82   int total_printed = 0;
     83 
     84   while (*ptr != '\0')
     85     {
     86       if (*ptr != '%') /* While we have regular characters, print them.  */
     87 	PRINT_CHAR(*ptr);
     88       else /* We got a format specifier! */
     89 	{
     90 	  char * sptr = specifier;
     91 	  int wide_width = 0, short_width = 0;
     92 
     93 	  *sptr++ = *ptr++; /* Copy the % and move forward.  */
     94 
     95 	  while (strchr ("-+ #0", *ptr)) /* Move past flags.  */
     96 	    *sptr++ = *ptr++;
     97 
     98 	  if (*ptr == '*')
     99 	    COPY_VA_INT;
    100 	  else
    101 	    while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
    102 	      *sptr++ = *ptr++;
    103 
    104 	  if (*ptr == '.')
    105 	    {
    106 	      *sptr++ = *ptr++; /* Copy and go past the period.  */
    107 	      if (*ptr == '*')
    108 		COPY_VA_INT;
    109 	      else
    110 		while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
    111 		  *sptr++ = *ptr++;
    112 	    }
    113 	  while (strchr ("hlL", *ptr))
    114 	    {
    115 	      switch (*ptr)
    116 		{
    117 		case 'h':
    118 		  short_width = 1;
    119 		  break;
    120 		case 'l':
    121 		  wide_width++;
    122 		  break;
    123 		case 'L':
    124 		  wide_width = 2;
    125 		  break;
    126 		default:
    127 		  abort();
    128 		}
    129 	      *sptr++ = *ptr++;
    130 	    }
    131 
    132 	  switch (*ptr)
    133 	    {
    134 	    case 'd':
    135 	    case 'i':
    136 	    case 'o':
    137 	    case 'u':
    138 	    case 'x':
    139 	    case 'X':
    140 	    case 'c':
    141 	      {
    142 		/* Short values are promoted to int, so just copy it
    143                    as an int and trust the C library printf to cast it
    144                    to the right width.  */
    145 		if (short_width)
    146 		  PRINT_TYPE(int);
    147 		else
    148 		  {
    149 		    switch (wide_width)
    150 		      {
    151 		      case 0:
    152 			PRINT_TYPE(int);
    153 			break;
    154 		      case 1:
    155 			PRINT_TYPE(long);
    156 			break;
    157 		      case 2:
    158 		      default:
    159 #if defined(__GNUC__) || defined(HAVE_LONG_LONG)
    160 			PRINT_TYPE(long long);
    161 #else
    162 			PRINT_TYPE(long); /* Fake it and hope for the best.  */
    163 #endif
    164 			break;
    165 		      } /* End of switch (wide_width) */
    166 		  } /* End of else statement */
    167 	      } /* End of integer case */
    168 	      break;
    169 	    case 'f':
    170 	    case 'e':
    171 	    case 'E':
    172 	    case 'g':
    173 	    case 'G':
    174 	      {
    175 		if (wide_width == 0)
    176 		  PRINT_TYPE(double);
    177 		else
    178 		  {
    179 #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
    180 		    PRINT_TYPE(long double);
    181 #else
    182 		    PRINT_TYPE(double); /* Fake it and hope for the best.  */
    183 #endif
    184 		  }
    185 	      }
    186 	      break;
    187 	    case 's':
    188 	      PRINT_TYPE(char *);
    189 	      break;
    190 	    case 'p':
    191 	      PRINT_TYPE(void *);
    192 	      break;
    193 	    case '%':
    194 	      PRINT_CHAR('%');
    195 	      break;
    196 	    default:
    197 	      abort();
    198 	    } /* End of switch (*ptr) */
    199 	} /* End of else statement */
    200     }
    201 
    202   return total_printed;
    203 }
    204 
    205 #ifdef TEST
    206 
    207 #include <math.h>
    208 #ifndef M_PI
    209 #define M_PI (3.1415926535897932385)
    210 #endif
    211 
    212 #define RESULT(x) do \
    213 { \
    214     int i = (x); \
    215     printf ("printed %d characters\n", i); \
    216     fflush(stdin); \
    217 } while (0)
    218 
    219 static int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1;
    220 
    221 static int
    222 checkit (const char* format, ...)
    223 {
    224   int result;
    225   va_list args;
    226   va_start (args, format);
    227 
    228   result = _doprnt (format, args, stdout);
    229   va_end (args);
    230 
    231   return result;
    232 }
    233 
    234 int
    235 main (void)
    236 {
    237   RESULT(checkit ("<%d>\n", 0x12345678));
    238   RESULT(printf ("<%d>\n", 0x12345678));
    239 
    240   RESULT(checkit ("<%200d>\n", 5));
    241   RESULT(printf ("<%200d>\n", 5));
    242 
    243   RESULT(checkit ("<%.300d>\n", 6));
    244   RESULT(printf ("<%.300d>\n", 6));
    245 
    246   RESULT(checkit ("<%100.150d>\n", 7));
    247   RESULT(printf ("<%100.150d>\n", 7));
    248 
    249   RESULT(checkit ("<%s>\n",
    250 		  "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
    251 777777777777777777333333333333366666666666622222222222777777777777733333"));
    252   RESULT(printf ("<%s>\n",
    253 		 "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
    254 777777777777777777333333333333366666666666622222222222777777777777733333"));
    255 
    256   RESULT(checkit ("<%f><%0+#f>%s%d%s>\n",
    257 		  1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
    258   RESULT(printf ("<%f><%0+#f>%s%d%s>\n",
    259 		 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
    260 
    261   RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
    262   RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
    263 
    264   RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
    265   RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
    266 
    267   RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
    268 		  75, 75, 75, 75, 75, 75, 75));
    269   RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
    270 		 75, 75, 75, 75, 75, 75, 75));
    271 
    272   RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
    273 		  75, 75, 75, 75, 75, 75, 75));
    274   RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
    275 		 75, 75, 75, 75, 75, 75, 75));
    276 
    277   RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
    278   RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
    279 
    280 #if defined(__GNUC__) || defined (HAVE_LONG_LONG)
    281   RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
    282   RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
    283   RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
    284   RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
    285 #endif
    286 
    287 #if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE)
    288   RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
    289 		  1.23456, 1.234567890123456789L, 1.23456));
    290   RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
    291 		 1.23456, 1.234567890123456789L, 1.23456));
    292 #endif
    293 
    294   return 0;
    295 }
    296 #endif /* TEST */
    297