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