12a6b7db3Sskrll /* Provide a version of _doprnt in terms of fprintf.
2*f22f0ef4Schristos    Copyright (C) 1998-2022 Free Software Foundation, Inc.
32a6b7db3Sskrll    Contributed by Kaveh Ghazi  (ghazi@caip.rutgers.edu)  3/29/98
42a6b7db3Sskrll 
52a6b7db3Sskrll This program is free software; you can redistribute it and/or modify it
62a6b7db3Sskrll under the terms of the GNU General Public License as published by the
72a6b7db3Sskrll Free Software Foundation; either version 2, or (at your option) any
82a6b7db3Sskrll later version.
92a6b7db3Sskrll 
102a6b7db3Sskrll This program is distributed in the hope that it will be useful,
112a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
122a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
132a6b7db3Sskrll GNU General Public License for more details.
142a6b7db3Sskrll 
152a6b7db3Sskrll You should have received a copy of the GNU General Public License
162a6b7db3Sskrll along with this program; if not, write to the Free Software
172a6b7db3Sskrll Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
182a6b7db3Sskrll 
192a6b7db3Sskrll #include "config.h"
202a6b7db3Sskrll #include "ansidecl.h"
212a6b7db3Sskrll #include "safe-ctype.h"
222a6b7db3Sskrll 
232a6b7db3Sskrll #include <stdio.h>
242a6b7db3Sskrll #include <stdarg.h>
252a6b7db3Sskrll #ifdef HAVE_STRING_H
262a6b7db3Sskrll #include <string.h>
272a6b7db3Sskrll #endif
282a6b7db3Sskrll #ifdef HAVE_STDLIB_H
292a6b7db3Sskrll #include <stdlib.h>
302a6b7db3Sskrll #endif
312a6b7db3Sskrll 
322a6b7db3Sskrll #undef _doprnt
332a6b7db3Sskrll 
342a6b7db3Sskrll #ifdef HAVE__DOPRNT
352a6b7db3Sskrll #define TEST
362a6b7db3Sskrll #endif
372a6b7db3Sskrll 
382a6b7db3Sskrll #ifdef TEST /* Make sure to use the internal one.  */
392a6b7db3Sskrll #define _doprnt my_doprnt
402a6b7db3Sskrll #endif
412a6b7db3Sskrll 
422a6b7db3Sskrll #define COPY_VA_INT \
432a6b7db3Sskrll   do { \
442a6b7db3Sskrll 	 const int value = abs (va_arg (ap, int)); \
452a6b7db3Sskrll 	 char buf[32]; \
462a6b7db3Sskrll 	 ptr++; /* Go past the asterisk.  */ \
472a6b7db3Sskrll 	 *sptr = '\0'; /* NULL terminate sptr.  */ \
482a6b7db3Sskrll 	 sprintf(buf, "%d", value); \
492a6b7db3Sskrll 	 strcat(sptr, buf); \
502a6b7db3Sskrll 	 while (*sptr) sptr++; \
512a6b7db3Sskrll      } while (0)
522a6b7db3Sskrll 
532a6b7db3Sskrll #define PRINT_CHAR(CHAR) \
542a6b7db3Sskrll   do { \
552a6b7db3Sskrll 	 putc(CHAR, stream); \
562a6b7db3Sskrll 	 ptr++; \
572a6b7db3Sskrll 	 total_printed++; \
582a6b7db3Sskrll 	 continue; \
592a6b7db3Sskrll      } while (0)
602a6b7db3Sskrll 
612a6b7db3Sskrll #define PRINT_TYPE(TYPE) \
622a6b7db3Sskrll   do { \
632a6b7db3Sskrll 	int result; \
642a6b7db3Sskrll 	TYPE value = va_arg (ap, TYPE); \
652a6b7db3Sskrll 	*sptr++ = *ptr++; /* Copy the type specifier.  */ \
662a6b7db3Sskrll 	*sptr = '\0'; /* NULL terminate sptr.  */ \
672a6b7db3Sskrll 	result = fprintf(stream, specifier, value); \
682a6b7db3Sskrll 	if (result == -1) \
692a6b7db3Sskrll 	  return -1; \
702a6b7db3Sskrll 	else \
712a6b7db3Sskrll 	  { \
722a6b7db3Sskrll 	    total_printed += result; \
732a6b7db3Sskrll 	    continue; \
742a6b7db3Sskrll 	  } \
752a6b7db3Sskrll       } while (0)
762a6b7db3Sskrll 
772a6b7db3Sskrll int
_doprnt(const char * format,va_list ap,FILE * stream)782a6b7db3Sskrll _doprnt (const char *format, va_list ap, FILE *stream)
792a6b7db3Sskrll {
802a6b7db3Sskrll   const char * ptr = format;
812a6b7db3Sskrll   char specifier[128];
822a6b7db3Sskrll   int total_printed = 0;
832a6b7db3Sskrll 
842a6b7db3Sskrll   while (*ptr != '\0')
852a6b7db3Sskrll     {
862a6b7db3Sskrll       if (*ptr != '%') /* While we have regular characters, print them.  */
872a6b7db3Sskrll 	PRINT_CHAR(*ptr);
882a6b7db3Sskrll       else /* We got a format specifier! */
892a6b7db3Sskrll 	{
902a6b7db3Sskrll 	  char * sptr = specifier;
912a6b7db3Sskrll 	  int wide_width = 0, short_width = 0;
922a6b7db3Sskrll 
932a6b7db3Sskrll 	  *sptr++ = *ptr++; /* Copy the % and move forward.  */
942a6b7db3Sskrll 
952a6b7db3Sskrll 	  while (strchr ("-+ #0", *ptr)) /* Move past flags.  */
962a6b7db3Sskrll 	    *sptr++ = *ptr++;
972a6b7db3Sskrll 
982a6b7db3Sskrll 	  if (*ptr == '*')
992a6b7db3Sskrll 	    COPY_VA_INT;
1002a6b7db3Sskrll 	  else
1012a6b7db3Sskrll 	    while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
1022a6b7db3Sskrll 	      *sptr++ = *ptr++;
1032a6b7db3Sskrll 
1042a6b7db3Sskrll 	  if (*ptr == '.')
1052a6b7db3Sskrll 	    {
1062a6b7db3Sskrll 	      *sptr++ = *ptr++; /* Copy and go past the period.  */
1072a6b7db3Sskrll 	      if (*ptr == '*')
1082a6b7db3Sskrll 		COPY_VA_INT;
1092a6b7db3Sskrll 	      else
1102a6b7db3Sskrll 		while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
1112a6b7db3Sskrll 		  *sptr++ = *ptr++;
1122a6b7db3Sskrll 	    }
1132a6b7db3Sskrll 	  while (strchr ("hlL", *ptr))
1142a6b7db3Sskrll 	    {
1152a6b7db3Sskrll 	      switch (*ptr)
1162a6b7db3Sskrll 		{
1172a6b7db3Sskrll 		case 'h':
1182a6b7db3Sskrll 		  short_width = 1;
1192a6b7db3Sskrll 		  break;
1202a6b7db3Sskrll 		case 'l':
1212a6b7db3Sskrll 		  wide_width++;
1222a6b7db3Sskrll 		  break;
1232a6b7db3Sskrll 		case 'L':
1242a6b7db3Sskrll 		  wide_width = 2;
1252a6b7db3Sskrll 		  break;
1262a6b7db3Sskrll 		default:
1272a6b7db3Sskrll 		  abort();
1282a6b7db3Sskrll 		}
1292a6b7db3Sskrll 	      *sptr++ = *ptr++;
1302a6b7db3Sskrll 	    }
1312a6b7db3Sskrll 
1322a6b7db3Sskrll 	  switch (*ptr)
1332a6b7db3Sskrll 	    {
1342a6b7db3Sskrll 	    case 'd':
1352a6b7db3Sskrll 	    case 'i':
1362a6b7db3Sskrll 	    case 'o':
1372a6b7db3Sskrll 	    case 'u':
1382a6b7db3Sskrll 	    case 'x':
1392a6b7db3Sskrll 	    case 'X':
1402a6b7db3Sskrll 	    case 'c':
1412a6b7db3Sskrll 	      {
1422a6b7db3Sskrll 		/* Short values are promoted to int, so just copy it
1432a6b7db3Sskrll                    as an int and trust the C library printf to cast it
1442a6b7db3Sskrll                    to the right width.  */
1452a6b7db3Sskrll 		if (short_width)
1462a6b7db3Sskrll 		  PRINT_TYPE(int);
1472a6b7db3Sskrll 		else
1482a6b7db3Sskrll 		  {
1492a6b7db3Sskrll 		    switch (wide_width)
1502a6b7db3Sskrll 		      {
1512a6b7db3Sskrll 		      case 0:
1522a6b7db3Sskrll 			PRINT_TYPE(int);
1532a6b7db3Sskrll 			break;
1542a6b7db3Sskrll 		      case 1:
1552a6b7db3Sskrll 			PRINT_TYPE(long);
1562a6b7db3Sskrll 			break;
1572a6b7db3Sskrll 		      case 2:
1582a6b7db3Sskrll 		      default:
1592a6b7db3Sskrll #if defined(__GNUC__) || defined(HAVE_LONG_LONG)
1602a6b7db3Sskrll 			PRINT_TYPE(long long);
1612a6b7db3Sskrll #else
1622a6b7db3Sskrll 			PRINT_TYPE(long); /* Fake it and hope for the best.  */
1632a6b7db3Sskrll #endif
1642a6b7db3Sskrll 			break;
1652a6b7db3Sskrll 		      } /* End of switch (wide_width) */
1662a6b7db3Sskrll 		  } /* End of else statement */
1672a6b7db3Sskrll 	      } /* End of integer case */
1682a6b7db3Sskrll 	      break;
1692a6b7db3Sskrll 	    case 'f':
1702a6b7db3Sskrll 	    case 'e':
1712a6b7db3Sskrll 	    case 'E':
1722a6b7db3Sskrll 	    case 'g':
1732a6b7db3Sskrll 	    case 'G':
1742a6b7db3Sskrll 	      {
1752a6b7db3Sskrll 		if (wide_width == 0)
1762a6b7db3Sskrll 		  PRINT_TYPE(double);
1772a6b7db3Sskrll 		else
1782a6b7db3Sskrll 		  {
1792a6b7db3Sskrll #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
1802a6b7db3Sskrll 		    PRINT_TYPE(long double);
1812a6b7db3Sskrll #else
1822a6b7db3Sskrll 		    PRINT_TYPE(double); /* Fake it and hope for the best.  */
1832a6b7db3Sskrll #endif
1842a6b7db3Sskrll 		  }
1852a6b7db3Sskrll 	      }
1862a6b7db3Sskrll 	      break;
1872a6b7db3Sskrll 	    case 's':
1882a6b7db3Sskrll 	      PRINT_TYPE(char *);
1892a6b7db3Sskrll 	      break;
1902a6b7db3Sskrll 	    case 'p':
1912a6b7db3Sskrll 	      PRINT_TYPE(void *);
1922a6b7db3Sskrll 	      break;
1932a6b7db3Sskrll 	    case '%':
1942a6b7db3Sskrll 	      PRINT_CHAR('%');
1952a6b7db3Sskrll 	      break;
1962a6b7db3Sskrll 	    default:
1972a6b7db3Sskrll 	      abort();
1982a6b7db3Sskrll 	    } /* End of switch (*ptr) */
1992a6b7db3Sskrll 	} /* End of else statement */
2002a6b7db3Sskrll     }
2012a6b7db3Sskrll 
2022a6b7db3Sskrll   return total_printed;
2032a6b7db3Sskrll }
2042a6b7db3Sskrll 
2052a6b7db3Sskrll #ifdef TEST
2062a6b7db3Sskrll 
2072a6b7db3Sskrll #include <math.h>
2082a6b7db3Sskrll #ifndef M_PI
2092a6b7db3Sskrll #define M_PI (3.1415926535897932385)
2102a6b7db3Sskrll #endif
2112a6b7db3Sskrll 
2122a6b7db3Sskrll #define RESULT(x) do \
2132a6b7db3Sskrll { \
2142a6b7db3Sskrll     int i = (x); \
2152a6b7db3Sskrll     printf ("printed %d characters\n", i); \
2162a6b7db3Sskrll     fflush(stdin); \
2172a6b7db3Sskrll } while (0)
2182a6b7db3Sskrll 
2192a6b7db3Sskrll static int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1;
2202a6b7db3Sskrll 
2212a6b7db3Sskrll static int
checkit(const char * format,...)2222a6b7db3Sskrll checkit (const char* format, ...)
2232a6b7db3Sskrll {
2242a6b7db3Sskrll   int result;
2255ba6b03cSchristos   va_list args;
2265ba6b03cSchristos   va_start (args, format);
2272a6b7db3Sskrll 
2282a6b7db3Sskrll   result = _doprnt (format, args, stdout);
2295ba6b03cSchristos   va_end (args);
2302a6b7db3Sskrll 
2312a6b7db3Sskrll   return result;
2322a6b7db3Sskrll }
2332a6b7db3Sskrll 
2342a6b7db3Sskrll int
main(void)2352a6b7db3Sskrll main (void)
2362a6b7db3Sskrll {
2372a6b7db3Sskrll   RESULT(checkit ("<%d>\n", 0x12345678));
2382a6b7db3Sskrll   RESULT(printf ("<%d>\n", 0x12345678));
2392a6b7db3Sskrll 
2402a6b7db3Sskrll   RESULT(checkit ("<%200d>\n", 5));
2412a6b7db3Sskrll   RESULT(printf ("<%200d>\n", 5));
2422a6b7db3Sskrll 
2432a6b7db3Sskrll   RESULT(checkit ("<%.300d>\n", 6));
2442a6b7db3Sskrll   RESULT(printf ("<%.300d>\n", 6));
2452a6b7db3Sskrll 
2462a6b7db3Sskrll   RESULT(checkit ("<%100.150d>\n", 7));
2472a6b7db3Sskrll   RESULT(printf ("<%100.150d>\n", 7));
2482a6b7db3Sskrll 
2492a6b7db3Sskrll   RESULT(checkit ("<%s>\n",
2502a6b7db3Sskrll 		  "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
2512a6b7db3Sskrll 777777777777777777333333333333366666666666622222222222777777777777733333"));
2522a6b7db3Sskrll   RESULT(printf ("<%s>\n",
2532a6b7db3Sskrll 		 "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
2542a6b7db3Sskrll 777777777777777777333333333333366666666666622222222222777777777777733333"));
2552a6b7db3Sskrll 
2562a6b7db3Sskrll   RESULT(checkit ("<%f><%0+#f>%s%d%s>\n",
2572a6b7db3Sskrll 		  1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
2582a6b7db3Sskrll   RESULT(printf ("<%f><%0+#f>%s%d%s>\n",
2592a6b7db3Sskrll 		 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
2602a6b7db3Sskrll 
2612a6b7db3Sskrll   RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
2622a6b7db3Sskrll   RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
2632a6b7db3Sskrll 
2642a6b7db3Sskrll   RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
2652a6b7db3Sskrll   RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
2662a6b7db3Sskrll 
2672a6b7db3Sskrll   RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
2682a6b7db3Sskrll 		  75, 75, 75, 75, 75, 75, 75));
2692a6b7db3Sskrll   RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
2702a6b7db3Sskrll 		 75, 75, 75, 75, 75, 75, 75));
2712a6b7db3Sskrll 
2722a6b7db3Sskrll   RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
2732a6b7db3Sskrll 		  75, 75, 75, 75, 75, 75, 75));
2742a6b7db3Sskrll   RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
2752a6b7db3Sskrll 		 75, 75, 75, 75, 75, 75, 75));
2762a6b7db3Sskrll 
2772a6b7db3Sskrll   RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
2782a6b7db3Sskrll   RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
2792a6b7db3Sskrll 
2802a6b7db3Sskrll #if defined(__GNUC__) || defined (HAVE_LONG_LONG)
2812a6b7db3Sskrll   RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
2822a6b7db3Sskrll   RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
2832a6b7db3Sskrll   RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
2842a6b7db3Sskrll   RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
2852a6b7db3Sskrll #endif
2862a6b7db3Sskrll 
2872a6b7db3Sskrll #if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE)
2882a6b7db3Sskrll   RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
2892a6b7db3Sskrll 		  1.23456, 1.234567890123456789L, 1.23456));
2902a6b7db3Sskrll   RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
2912a6b7db3Sskrll 		 1.23456, 1.234567890123456789L, 1.23456));
2922a6b7db3Sskrll #endif
2932a6b7db3Sskrll 
2942a6b7db3Sskrll   return 0;
2952a6b7db3Sskrll }
2962a6b7db3Sskrll #endif /* TEST */
297