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