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