198b9484cSchristos /* Provide a version of _doprnt in terms of fprintf. 2*7e120ff0Schristos Copyright (C) 1998-2024 Free Software Foundation, Inc. 398b9484cSchristos Contributed by Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98 498b9484cSchristos 598b9484cSchristos This program is free software; you can redistribute it and/or modify it 698b9484cSchristos under the terms of the GNU General Public License as published by the 798b9484cSchristos Free Software Foundation; either version 2, or (at your option) any 898b9484cSchristos later version. 998b9484cSchristos 1098b9484cSchristos This program is distributed in the hope that it will be useful, 1198b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1298b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1398b9484cSchristos GNU General Public License for more details. 1498b9484cSchristos 1598b9484cSchristos You should have received a copy of the GNU General Public License 1698b9484cSchristos along with this program; if not, write to the Free Software 1798b9484cSchristos Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 1898b9484cSchristos 1998b9484cSchristos #include "config.h" 2098b9484cSchristos #include "ansidecl.h" 2198b9484cSchristos #include "safe-ctype.h" 2298b9484cSchristos 2398b9484cSchristos #include <stdio.h> 2498b9484cSchristos #include <stdarg.h> 2598b9484cSchristos #ifdef HAVE_STRING_H 2698b9484cSchristos #include <string.h> 2798b9484cSchristos #endif 2898b9484cSchristos #ifdef HAVE_STDLIB_H 2998b9484cSchristos #include <stdlib.h> 3098b9484cSchristos #endif 3198b9484cSchristos 3298b9484cSchristos #undef _doprnt 3398b9484cSchristos 3498b9484cSchristos #ifdef HAVE__DOPRNT 3598b9484cSchristos #define TEST 3698b9484cSchristos #endif 3798b9484cSchristos 3898b9484cSchristos #ifdef TEST /* Make sure to use the internal one. */ 3998b9484cSchristos #define _doprnt my_doprnt 4098b9484cSchristos #endif 4198b9484cSchristos 4298b9484cSchristos #define COPY_VA_INT \ 4398b9484cSchristos do { \ 4498b9484cSchristos const int value = abs (va_arg (ap, int)); \ 4598b9484cSchristos char buf[32]; \ 4698b9484cSchristos ptr++; /* Go past the asterisk. */ \ 4798b9484cSchristos *sptr = '\0'; /* NULL terminate sptr. */ \ 4898b9484cSchristos sprintf(buf, "%d", value); \ 4998b9484cSchristos strcat(sptr, buf); \ 5098b9484cSchristos while (*sptr) sptr++; \ 5198b9484cSchristos } while (0) 5298b9484cSchristos 5398b9484cSchristos #define PRINT_CHAR(CHAR) \ 5498b9484cSchristos do { \ 5598b9484cSchristos putc(CHAR, stream); \ 5698b9484cSchristos ptr++; \ 5798b9484cSchristos total_printed++; \ 5898b9484cSchristos } while (0) 5998b9484cSchristos 6098b9484cSchristos #define PRINT_TYPE(TYPE) \ 6198b9484cSchristos do { \ 6298b9484cSchristos int result; \ 6398b9484cSchristos TYPE value = va_arg (ap, TYPE); \ 6498b9484cSchristos *sptr++ = *ptr++; /* Copy the type specifier. */ \ 6598b9484cSchristos *sptr = '\0'; /* NULL terminate sptr. */ \ 6698b9484cSchristos result = fprintf(stream, specifier, value); \ 6798b9484cSchristos if (result == -1) \ 6898b9484cSchristos return -1; \ 6998b9484cSchristos else \ 7098b9484cSchristos { \ 7198b9484cSchristos total_printed += result; \ 7298b9484cSchristos continue; \ 7398b9484cSchristos } \ 7498b9484cSchristos } while (0) 7598b9484cSchristos 7698b9484cSchristos int 7798b9484cSchristos _doprnt (const char *format, va_list ap, FILE *stream) 7898b9484cSchristos { 7998b9484cSchristos const char * ptr = format; 8098b9484cSchristos char specifier[128]; 8198b9484cSchristos int total_printed = 0; 8298b9484cSchristos 8398b9484cSchristos while (*ptr != '\0') 8498b9484cSchristos { 8598b9484cSchristos if (*ptr != '%') /* While we have regular characters, print them. */ 8698b9484cSchristos PRINT_CHAR(*ptr); 8798b9484cSchristos else /* We got a format specifier! */ 8898b9484cSchristos { 8998b9484cSchristos char * sptr = specifier; 9098b9484cSchristos int wide_width = 0, short_width = 0; 9198b9484cSchristos 9298b9484cSchristos *sptr++ = *ptr++; /* Copy the % and move forward. */ 9398b9484cSchristos 9498b9484cSchristos while (strchr ("-+ #0", *ptr)) /* Move past flags. */ 9598b9484cSchristos *sptr++ = *ptr++; 9698b9484cSchristos 9798b9484cSchristos if (*ptr == '*') 9898b9484cSchristos COPY_VA_INT; 9998b9484cSchristos else 10098b9484cSchristos while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ 10198b9484cSchristos *sptr++ = *ptr++; 10298b9484cSchristos 10398b9484cSchristos if (*ptr == '.') 10498b9484cSchristos { 10598b9484cSchristos *sptr++ = *ptr++; /* Copy and go past the period. */ 10698b9484cSchristos if (*ptr == '*') 10798b9484cSchristos COPY_VA_INT; 10898b9484cSchristos else 10998b9484cSchristos while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ 11098b9484cSchristos *sptr++ = *ptr++; 11198b9484cSchristos } 11298b9484cSchristos while (strchr ("hlL", *ptr)) 11398b9484cSchristos { 11498b9484cSchristos switch (*ptr) 11598b9484cSchristos { 11698b9484cSchristos case 'h': 11798b9484cSchristos short_width = 1; 11898b9484cSchristos break; 11998b9484cSchristos case 'l': 12098b9484cSchristos wide_width++; 12198b9484cSchristos break; 12298b9484cSchristos case 'L': 12398b9484cSchristos wide_width = 2; 12498b9484cSchristos break; 12598b9484cSchristos default: 12698b9484cSchristos abort(); 12798b9484cSchristos } 12898b9484cSchristos *sptr++ = *ptr++; 12998b9484cSchristos } 13098b9484cSchristos 13198b9484cSchristos switch (*ptr) 13298b9484cSchristos { 13398b9484cSchristos case 'd': 13498b9484cSchristos case 'i': 13598b9484cSchristos case 'o': 13698b9484cSchristos case 'u': 13798b9484cSchristos case 'x': 13898b9484cSchristos case 'X': 13998b9484cSchristos case 'c': 14098b9484cSchristos { 14198b9484cSchristos /* Short values are promoted to int, so just copy it 14298b9484cSchristos as an int and trust the C library printf to cast it 14398b9484cSchristos to the right width. */ 14498b9484cSchristos if (short_width) 14598b9484cSchristos PRINT_TYPE(int); 14698b9484cSchristos else 14798b9484cSchristos { 14898b9484cSchristos switch (wide_width) 14998b9484cSchristos { 15098b9484cSchristos case 0: 15198b9484cSchristos PRINT_TYPE(int); 15298b9484cSchristos break; 15398b9484cSchristos case 1: 15498b9484cSchristos PRINT_TYPE(long); 15598b9484cSchristos break; 15698b9484cSchristos case 2: 15798b9484cSchristos default: 15898b9484cSchristos #if defined(__GNUC__) || defined(HAVE_LONG_LONG) 15998b9484cSchristos PRINT_TYPE(long long); 16098b9484cSchristos #else 16198b9484cSchristos PRINT_TYPE(long); /* Fake it and hope for the best. */ 16298b9484cSchristos #endif 16398b9484cSchristos break; 16498b9484cSchristos } /* End of switch (wide_width) */ 16598b9484cSchristos } /* End of else statement */ 16698b9484cSchristos } /* End of integer case */ 16798b9484cSchristos break; 16898b9484cSchristos case 'f': 16998b9484cSchristos case 'e': 17098b9484cSchristos case 'E': 17198b9484cSchristos case 'g': 17298b9484cSchristos case 'G': 17398b9484cSchristos { 17498b9484cSchristos if (wide_width == 0) 17598b9484cSchristos PRINT_TYPE(double); 17698b9484cSchristos else 17798b9484cSchristos { 17898b9484cSchristos #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE) 17998b9484cSchristos PRINT_TYPE(long double); 18098b9484cSchristos #else 18198b9484cSchristos PRINT_TYPE(double); /* Fake it and hope for the best. */ 18298b9484cSchristos #endif 18398b9484cSchristos } 18498b9484cSchristos } 18598b9484cSchristos break; 18698b9484cSchristos case 's': 18798b9484cSchristos PRINT_TYPE(char *); 18898b9484cSchristos break; 18998b9484cSchristos case 'p': 19098b9484cSchristos PRINT_TYPE(void *); 19198b9484cSchristos break; 19298b9484cSchristos case '%': 19398b9484cSchristos PRINT_CHAR('%'); 19498b9484cSchristos break; 19598b9484cSchristos default: 19698b9484cSchristos abort(); 19798b9484cSchristos } /* End of switch (*ptr) */ 19898b9484cSchristos } /* End of else statement */ 19998b9484cSchristos } 20098b9484cSchristos 20198b9484cSchristos return total_printed; 20298b9484cSchristos } 20398b9484cSchristos 20498b9484cSchristos #ifdef TEST 20598b9484cSchristos 20698b9484cSchristos #include <math.h> 20798b9484cSchristos #ifndef M_PI 20898b9484cSchristos #define M_PI (3.1415926535897932385) 20998b9484cSchristos #endif 21098b9484cSchristos 21198b9484cSchristos #define RESULT(x) do \ 21298b9484cSchristos { \ 21398b9484cSchristos int i = (x); \ 21498b9484cSchristos printf ("printed %d characters\n", i); \ 21598b9484cSchristos fflush(stdin); \ 21698b9484cSchristos } while (0) 21798b9484cSchristos 21898b9484cSchristos static int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1; 21998b9484cSchristos 22098b9484cSchristos static int 22198b9484cSchristos checkit (const char* format, ...) 22298b9484cSchristos { 22398b9484cSchristos int result; 224837edd6bSchristos va_list args; 225837edd6bSchristos va_start (args, format); 22698b9484cSchristos 22798b9484cSchristos result = _doprnt (format, args, stdout); 228837edd6bSchristos va_end (args); 22998b9484cSchristos 23098b9484cSchristos return result; 23198b9484cSchristos } 23298b9484cSchristos 23398b9484cSchristos int 23498b9484cSchristos main (void) 23598b9484cSchristos { 23698b9484cSchristos RESULT(checkit ("<%d>\n", 0x12345678)); 23798b9484cSchristos RESULT(printf ("<%d>\n", 0x12345678)); 23898b9484cSchristos 23998b9484cSchristos RESULT(checkit ("<%200d>\n", 5)); 24098b9484cSchristos RESULT(printf ("<%200d>\n", 5)); 24198b9484cSchristos 24298b9484cSchristos RESULT(checkit ("<%.300d>\n", 6)); 24398b9484cSchristos RESULT(printf ("<%.300d>\n", 6)); 24498b9484cSchristos 24598b9484cSchristos RESULT(checkit ("<%100.150d>\n", 7)); 24698b9484cSchristos RESULT(printf ("<%100.150d>\n", 7)); 24798b9484cSchristos 24898b9484cSchristos RESULT(checkit ("<%s>\n", 24998b9484cSchristos "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 25098b9484cSchristos 777777777777777777333333333333366666666666622222222222777777777777733333")); 25198b9484cSchristos RESULT(printf ("<%s>\n", 25298b9484cSchristos "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 25398b9484cSchristos 777777777777777777333333333333366666666666622222222222777777777777733333")); 25498b9484cSchristos 25598b9484cSchristos RESULT(checkit ("<%f><%0+#f>%s%d%s>\n", 25698b9484cSchristos 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); 25798b9484cSchristos RESULT(printf ("<%f><%0+#f>%s%d%s>\n", 25898b9484cSchristos 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); 25998b9484cSchristos 26098b9484cSchristos RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); 26198b9484cSchristos RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); 26298b9484cSchristos 26398b9484cSchristos RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); 26498b9484cSchristos RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); 26598b9484cSchristos 26698b9484cSchristos RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", 26798b9484cSchristos 75, 75, 75, 75, 75, 75, 75)); 26898b9484cSchristos RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", 26998b9484cSchristos 75, 75, 75, 75, 75, 75, 75)); 27098b9484cSchristos 27198b9484cSchristos RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", 27298b9484cSchristos 75, 75, 75, 75, 75, 75, 75)); 27398b9484cSchristos RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", 27498b9484cSchristos 75, 75, 75, 75, 75, 75, 75)); 27598b9484cSchristos 27698b9484cSchristos RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); 27798b9484cSchristos RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); 27898b9484cSchristos 27998b9484cSchristos #if defined(__GNUC__) || defined (HAVE_LONG_LONG) 28098b9484cSchristos RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); 28198b9484cSchristos RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); 28298b9484cSchristos RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); 28398b9484cSchristos RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); 28498b9484cSchristos #endif 28598b9484cSchristos 28698b9484cSchristos #if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE) 28798b9484cSchristos RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", 28898b9484cSchristos 1.23456, 1.234567890123456789L, 1.23456)); 28998b9484cSchristos RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", 29098b9484cSchristos 1.23456, 1.234567890123456789L, 1.23456)); 29198b9484cSchristos #endif 29298b9484cSchristos 29398b9484cSchristos return 0; 29498b9484cSchristos } 29598b9484cSchristos #endif /* TEST */ 296