xref: /openbsd-src/gnu/lib/libiberty/src/_doprnt.c (revision 20fce977aadac3358da45d5027d7d19cdc03b0fe)
19588ddcfSespie /* Provide a version of _doprnt in terms of fprintf.
29588ddcfSespie    Copyright (C) 1998, 1999, 2000, 2001, 2002   Free Software Foundation, Inc.
39588ddcfSespie    Contributed by Kaveh Ghazi  (ghazi@caip.rutgers.edu)  3/29/98
49588ddcfSespie 
59588ddcfSespie This program is free software; you can redistribute it and/or modify it
69588ddcfSespie under the terms of the GNU General Public License as published by the
79588ddcfSespie Free Software Foundation; either version 2, or (at your option) any
89588ddcfSespie later version.
99588ddcfSespie 
109588ddcfSespie This program is distributed in the hope that it will be useful,
119588ddcfSespie but WITHOUT ANY WARRANTY; without even the implied warranty of
129588ddcfSespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
139588ddcfSespie GNU General Public License for more details.
149588ddcfSespie 
159588ddcfSespie You should have received a copy of the GNU General Public License
169588ddcfSespie along with this program; if not, write to the Free Software
17*20fce977Smiod Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
189588ddcfSespie 
199588ddcfSespie #include "config.h"
209588ddcfSespie #include "ansidecl.h"
219588ddcfSespie #include "safe-ctype.h"
229588ddcfSespie 
239588ddcfSespie #include <stdio.h>
249588ddcfSespie #include <stdarg.h>
259588ddcfSespie #ifdef HAVE_STRING_H
269588ddcfSespie #include <string.h>
279588ddcfSespie #endif
289588ddcfSespie #ifdef HAVE_STDLIB_H
299588ddcfSespie #include <stdlib.h>
309588ddcfSespie #endif
319588ddcfSespie 
329588ddcfSespie #undef _doprnt
339588ddcfSespie 
349588ddcfSespie #ifdef HAVE__DOPRNT
359588ddcfSespie #define TEST
369588ddcfSespie #endif
379588ddcfSespie 
389588ddcfSespie #ifdef TEST /* Make sure to use the internal one.  */
399588ddcfSespie #define _doprnt my_doprnt
409588ddcfSespie #endif
419588ddcfSespie 
429588ddcfSespie #define COPY_VA_INT \
439588ddcfSespie   do { \
449588ddcfSespie 	 const int value = abs (va_arg (ap, int)); \
459588ddcfSespie 	 char buf[32]; \
469588ddcfSespie 	 ptr++; /* Go past the asterisk.  */ \
479588ddcfSespie 	 *sptr = '\0'; /* NULL terminate sptr.  */ \
489588ddcfSespie 	 sprintf(buf, "%d", value); \
499588ddcfSespie 	 strcat(sptr, buf); \
509588ddcfSespie 	 while (*sptr) sptr++; \
519588ddcfSespie      } while (0)
529588ddcfSespie 
539588ddcfSespie #define PRINT_CHAR(CHAR) \
549588ddcfSespie   do { \
559588ddcfSespie 	 putc(CHAR, stream); \
569588ddcfSespie 	 ptr++; \
579588ddcfSespie 	 total_printed++; \
589588ddcfSespie 	 continue; \
599588ddcfSespie      } while (0)
609588ddcfSespie 
619588ddcfSespie #define PRINT_TYPE(TYPE) \
629588ddcfSespie   do { \
639588ddcfSespie 	int result; \
649588ddcfSespie 	TYPE value = va_arg (ap, TYPE); \
659588ddcfSespie 	*sptr++ = *ptr++; /* Copy the type specifier.  */ \
669588ddcfSespie 	*sptr = '\0'; /* NULL terminate sptr.  */ \
679588ddcfSespie 	result = fprintf(stream, specifier, value); \
689588ddcfSespie 	if (result == -1) \
699588ddcfSespie 	  return -1; \
709588ddcfSespie 	else \
719588ddcfSespie 	  { \
729588ddcfSespie 	    total_printed += result; \
739588ddcfSespie 	    continue; \
749588ddcfSespie 	  } \
759588ddcfSespie       } while (0)
769588ddcfSespie 
779588ddcfSespie int
_doprnt(const char * format,va_list ap,FILE * stream)78*20fce977Smiod _doprnt (const char *format, va_list ap, FILE *stream)
799588ddcfSespie {
809588ddcfSespie   const char * ptr = format;
819588ddcfSespie   char specifier[128];
829588ddcfSespie   int total_printed = 0;
839588ddcfSespie 
849588ddcfSespie   while (*ptr != '\0')
859588ddcfSespie     {
869588ddcfSespie       if (*ptr != '%') /* While we have regular characters, print them.  */
879588ddcfSespie 	PRINT_CHAR(*ptr);
889588ddcfSespie       else /* We got a format specifier! */
899588ddcfSespie 	{
909588ddcfSespie 	  char * sptr = specifier;
919588ddcfSespie 	  int wide_width = 0, short_width = 0;
929588ddcfSespie 
939588ddcfSespie 	  *sptr++ = *ptr++; /* Copy the % and move forward.  */
949588ddcfSespie 
959588ddcfSespie 	  while (strchr ("-+ #0", *ptr)) /* Move past flags.  */
969588ddcfSespie 	    *sptr++ = *ptr++;
979588ddcfSespie 
989588ddcfSespie 	  if (*ptr == '*')
999588ddcfSespie 	    COPY_VA_INT;
1009588ddcfSespie 	  else
1019588ddcfSespie 	    while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
1029588ddcfSespie 	      *sptr++ = *ptr++;
1039588ddcfSespie 
1049588ddcfSespie 	  if (*ptr == '.')
1059588ddcfSespie 	    {
1069588ddcfSespie 	      *sptr++ = *ptr++; /* Copy and go past the period.  */
1079588ddcfSespie 	      if (*ptr == '*')
1089588ddcfSespie 		COPY_VA_INT;
1099588ddcfSespie 	      else
1109588ddcfSespie 		while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
1119588ddcfSespie 		  *sptr++ = *ptr++;
1129588ddcfSespie 	    }
1139588ddcfSespie 	  while (strchr ("hlL", *ptr))
1149588ddcfSespie 	    {
1159588ddcfSespie 	      switch (*ptr)
1169588ddcfSespie 		{
1179588ddcfSespie 		case 'h':
1189588ddcfSespie 		  short_width = 1;
1199588ddcfSespie 		  break;
1209588ddcfSespie 		case 'l':
1219588ddcfSespie 		  wide_width++;
1229588ddcfSespie 		  break;
1239588ddcfSespie 		case 'L':
1249588ddcfSespie 		  wide_width = 2;
1259588ddcfSespie 		  break;
1269588ddcfSespie 		default:
1279588ddcfSespie 		  abort();
1289588ddcfSespie 		}
1299588ddcfSespie 	      *sptr++ = *ptr++;
1309588ddcfSespie 	    }
1319588ddcfSespie 
1329588ddcfSespie 	  switch (*ptr)
1339588ddcfSespie 	    {
1349588ddcfSespie 	    case 'd':
1359588ddcfSespie 	    case 'i':
1369588ddcfSespie 	    case 'o':
1379588ddcfSespie 	    case 'u':
1389588ddcfSespie 	    case 'x':
1399588ddcfSespie 	    case 'X':
1409588ddcfSespie 	    case 'c':
1419588ddcfSespie 	      {
1429588ddcfSespie 		/* Short values are promoted to int, so just copy it
1439588ddcfSespie                    as an int and trust the C library printf to cast it
1449588ddcfSespie                    to the right width.  */
1459588ddcfSespie 		if (short_width)
1469588ddcfSespie 		  PRINT_TYPE(int);
1479588ddcfSespie 		else
1489588ddcfSespie 		  {
1499588ddcfSespie 		    switch (wide_width)
1509588ddcfSespie 		      {
1519588ddcfSespie 		      case 0:
1529588ddcfSespie 			PRINT_TYPE(int);
1539588ddcfSespie 			break;
1549588ddcfSespie 		      case 1:
1559588ddcfSespie 			PRINT_TYPE(long);
1569588ddcfSespie 			break;
1579588ddcfSespie 		      case 2:
1589588ddcfSespie 		      default:
1599588ddcfSespie #if defined(__GNUC__) || defined(HAVE_LONG_LONG)
1609588ddcfSespie 			PRINT_TYPE(long long);
1619588ddcfSespie #else
1629588ddcfSespie 			PRINT_TYPE(long); /* Fake it and hope for the best.  */
1639588ddcfSespie #endif
1649588ddcfSespie 			break;
1659588ddcfSespie 		      } /* End of switch (wide_width) */
1669588ddcfSespie 		  } /* End of else statement */
1679588ddcfSespie 	      } /* End of integer case */
1689588ddcfSespie 	      break;
1699588ddcfSespie 	    case 'f':
1709588ddcfSespie 	    case 'e':
1719588ddcfSespie 	    case 'E':
1729588ddcfSespie 	    case 'g':
1739588ddcfSespie 	    case 'G':
1749588ddcfSespie 	      {
1759588ddcfSespie 		if (wide_width == 0)
1769588ddcfSespie 		  PRINT_TYPE(double);
1779588ddcfSespie 		else
1789588ddcfSespie 		  {
1799588ddcfSespie #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
1809588ddcfSespie 		    PRINT_TYPE(long double);
1819588ddcfSespie #else
1829588ddcfSespie 		    PRINT_TYPE(double); /* Fake it and hope for the best.  */
1839588ddcfSespie #endif
1849588ddcfSespie 		  }
1859588ddcfSespie 	      }
1869588ddcfSespie 	      break;
1879588ddcfSespie 	    case 's':
1889588ddcfSespie 	      PRINT_TYPE(char *);
1899588ddcfSespie 	      break;
1909588ddcfSespie 	    case 'p':
1919588ddcfSespie 	      PRINT_TYPE(void *);
1929588ddcfSespie 	      break;
1939588ddcfSespie 	    case '%':
1949588ddcfSespie 	      PRINT_CHAR('%');
1959588ddcfSespie 	      break;
1969588ddcfSespie 	    default:
1979588ddcfSespie 	      abort();
1989588ddcfSespie 	    } /* End of switch (*ptr) */
1999588ddcfSespie 	} /* End of else statement */
2009588ddcfSespie     }
2019588ddcfSespie 
2029588ddcfSespie   return total_printed;
2039588ddcfSespie }
2049588ddcfSespie 
2059588ddcfSespie #ifdef TEST
2069588ddcfSespie 
2079588ddcfSespie #include <math.h>
2089588ddcfSespie #ifndef M_PI
2099588ddcfSespie #define M_PI (3.1415926535897932385)
2109588ddcfSespie #endif
2119588ddcfSespie 
2129588ddcfSespie #define RESULT(x) do \
2139588ddcfSespie { \
2149588ddcfSespie     int i = (x); \
2159588ddcfSespie     printf ("printed %d characters\n", i); \
2169588ddcfSespie     fflush(stdin); \
2179588ddcfSespie } while (0)
2189588ddcfSespie 
219*20fce977Smiod static int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1;
2209588ddcfSespie 
2219588ddcfSespie static int
checkit(const char * format,...)222*20fce977Smiod checkit (const char* format, ...)
2239588ddcfSespie {
2249588ddcfSespie   int result;
2259588ddcfSespie   VA_OPEN (args, format);
2269588ddcfSespie   VA_FIXEDARG (args, char *, format);
2279588ddcfSespie 
2289588ddcfSespie   result = _doprnt (format, args, stdout);
2299588ddcfSespie   VA_CLOSE (args);
2309588ddcfSespie 
2319588ddcfSespie   return result;
2329588ddcfSespie }
2339588ddcfSespie 
2349588ddcfSespie int
main(void)235*20fce977Smiod main (void)
2369588ddcfSespie {
2379588ddcfSespie   RESULT(checkit ("<%d>\n", 0x12345678));
2389588ddcfSespie   RESULT(printf ("<%d>\n", 0x12345678));
2399588ddcfSespie 
2409588ddcfSespie   RESULT(checkit ("<%200d>\n", 5));
2419588ddcfSespie   RESULT(printf ("<%200d>\n", 5));
2429588ddcfSespie 
2439588ddcfSespie   RESULT(checkit ("<%.300d>\n", 6));
2449588ddcfSespie   RESULT(printf ("<%.300d>\n", 6));
2459588ddcfSespie 
2469588ddcfSespie   RESULT(checkit ("<%100.150d>\n", 7));
2479588ddcfSespie   RESULT(printf ("<%100.150d>\n", 7));
2489588ddcfSespie 
2499588ddcfSespie   RESULT(checkit ("<%s>\n",
2509588ddcfSespie 		  "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
2519588ddcfSespie 777777777777777777333333333333366666666666622222222222777777777777733333"));
2529588ddcfSespie   RESULT(printf ("<%s>\n",
2539588ddcfSespie 		 "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
2549588ddcfSespie 777777777777777777333333333333366666666666622222222222777777777777733333"));
2559588ddcfSespie 
2569588ddcfSespie   RESULT(checkit ("<%f><%0+#f>%s%d%s>\n",
2579588ddcfSespie 		  1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
2589588ddcfSespie   RESULT(printf ("<%f><%0+#f>%s%d%s>\n",
2599588ddcfSespie 		 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
2609588ddcfSespie 
2619588ddcfSespie   RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
2629588ddcfSespie   RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
2639588ddcfSespie 
2649588ddcfSespie   RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
2659588ddcfSespie   RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
2669588ddcfSespie 
2679588ddcfSespie   RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
2689588ddcfSespie 		  75, 75, 75, 75, 75, 75, 75));
2699588ddcfSespie   RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
2709588ddcfSespie 		 75, 75, 75, 75, 75, 75, 75));
2719588ddcfSespie 
2729588ddcfSespie   RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
2739588ddcfSespie 		  75, 75, 75, 75, 75, 75, 75));
2749588ddcfSespie   RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
2759588ddcfSespie 		 75, 75, 75, 75, 75, 75, 75));
2769588ddcfSespie 
2779588ddcfSespie   RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
2789588ddcfSespie   RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
2799588ddcfSespie 
2809588ddcfSespie #if defined(__GNUC__) || defined (HAVE_LONG_LONG)
2819588ddcfSespie   RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
2829588ddcfSespie   RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
2839588ddcfSespie   RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
2849588ddcfSespie   RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
2859588ddcfSespie #endif
2869588ddcfSespie 
2879588ddcfSespie #if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE)
2889588ddcfSespie   RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
2899588ddcfSespie 		  1.23456, 1.234567890123456789L, 1.23456));
2909588ddcfSespie   RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
2919588ddcfSespie 		 1.23456, 1.234567890123456789L, 1.23456));
2929588ddcfSespie #endif
2939588ddcfSespie 
2949588ddcfSespie   return 0;
2959588ddcfSespie }
2969588ddcfSespie #endif /* TEST */
297