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