1169695Skan/* Provide a version of _doprnt in terms of fprintf. 2169695Skan Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 3169695Skan Contributed by Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98 4169695Skan 5169695SkanThis program is free software; you can redistribute it and/or modify it 6169695Skanunder the terms of the GNU General Public License as published by the 7169695SkanFree Software Foundation; either version 2, or (at your option) any 8169695Skanlater version. 9169695Skan 10169695SkanThis program is distributed in the hope that it will be useful, 11169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of 12169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13169695SkanGNU General Public License for more details. 14169695Skan 15169695SkanYou should have received a copy of the GNU General Public License 16169695Skanalong with this program; if not, write to the Free Software 17169695SkanFoundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 18169695Skan 19169695Skan#include "config.h" 20169695Skan#include "ansidecl.h" 21169695Skan#include "safe-ctype.h" 22169695Skan 23169695Skan#include <stdio.h> 24169695Skan#include <stdarg.h> 25169695Skan#ifdef HAVE_STRING_H 26169695Skan#include <string.h> 27169695Skan#endif 28169695Skan#ifdef HAVE_STDLIB_H 29169695Skan#include <stdlib.h> 30169695Skan#endif 31169695Skan 32169695Skan#undef _doprnt 33169695Skan 34169695Skan#ifdef HAVE__DOPRNT 35169695Skan#define TEST 36169695Skan#endif 37169695Skan 38169695Skan#ifdef TEST /* Make sure to use the internal one. */ 39169695Skan#define _doprnt my_doprnt 40169695Skan#endif 41169695Skan 42169695Skan#define COPY_VA_INT \ 43169695Skan do { \ 44169695Skan const int value = abs (va_arg (ap, int)); \ 45169695Skan char buf[32]; \ 46169695Skan ptr++; /* Go past the asterisk. */ \ 47169695Skan *sptr = '\0'; /* NULL terminate sptr. */ \ 48169695Skan sprintf(buf, "%d", value); \ 49169695Skan strcat(sptr, buf); \ 50169695Skan while (*sptr) sptr++; \ 51169695Skan } while (0) 52169695Skan 53169695Skan#define PRINT_CHAR(CHAR) \ 54169695Skan do { \ 55169695Skan putc(CHAR, stream); \ 56169695Skan ptr++; \ 57169695Skan total_printed++; \ 58169695Skan continue; \ 59169695Skan } while (0) 60169695Skan 61169695Skan#define PRINT_TYPE(TYPE) \ 62169695Skan do { \ 63169695Skan int result; \ 64169695Skan TYPE value = va_arg (ap, TYPE); \ 65169695Skan *sptr++ = *ptr++; /* Copy the type specifier. */ \ 66169695Skan *sptr = '\0'; /* NULL terminate sptr. */ \ 67169695Skan result = fprintf(stream, specifier, value); \ 68169695Skan if (result == -1) \ 69169695Skan return -1; \ 70169695Skan else \ 71169695Skan { \ 72169695Skan total_printed += result; \ 73169695Skan continue; \ 74169695Skan } \ 75169695Skan } while (0) 76169695Skan 77169695Skanint 78169695Skan_doprnt (const char *format, va_list ap, FILE *stream) 79169695Skan{ 80169695Skan const char * ptr = format; 81169695Skan char specifier[128]; 82169695Skan int total_printed = 0; 83169695Skan 84169695Skan while (*ptr != '\0') 85169695Skan { 86169695Skan if (*ptr != '%') /* While we have regular characters, print them. */ 87169695Skan PRINT_CHAR(*ptr); 88169695Skan else /* We got a format specifier! */ 89169695Skan { 90169695Skan char * sptr = specifier; 91169695Skan int wide_width = 0, short_width = 0; 92169695Skan 93169695Skan *sptr++ = *ptr++; /* Copy the % and move forward. */ 94169695Skan 95169695Skan while (strchr ("-+ #0", *ptr)) /* Move past flags. */ 96169695Skan *sptr++ = *ptr++; 97169695Skan 98169695Skan if (*ptr == '*') 99169695Skan COPY_VA_INT; 100169695Skan else 101169695Skan while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ 102169695Skan *sptr++ = *ptr++; 103169695Skan 104169695Skan if (*ptr == '.') 105169695Skan { 106169695Skan *sptr++ = *ptr++; /* Copy and go past the period. */ 107169695Skan if (*ptr == '*') 108169695Skan COPY_VA_INT; 109169695Skan else 110169695Skan while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ 111169695Skan *sptr++ = *ptr++; 112169695Skan } 113169695Skan while (strchr ("hlL", *ptr)) 114169695Skan { 115169695Skan switch (*ptr) 116169695Skan { 117169695Skan case 'h': 118169695Skan short_width = 1; 119169695Skan break; 120169695Skan case 'l': 121169695Skan wide_width++; 122169695Skan break; 123169695Skan case 'L': 124169695Skan wide_width = 2; 125169695Skan break; 126169695Skan default: 127169695Skan abort(); 128169695Skan } 129169695Skan *sptr++ = *ptr++; 130169695Skan } 131169695Skan 132169695Skan switch (*ptr) 133169695Skan { 134169695Skan case 'd': 135169695Skan case 'i': 136169695Skan case 'o': 137169695Skan case 'u': 138169695Skan case 'x': 139169695Skan case 'X': 140169695Skan case 'c': 141169695Skan { 142169695Skan /* Short values are promoted to int, so just copy it 143169695Skan as an int and trust the C library printf to cast it 144169695Skan to the right width. */ 145169695Skan if (short_width) 146169695Skan PRINT_TYPE(int); 147169695Skan else 148169695Skan { 149169695Skan switch (wide_width) 150169695Skan { 151169695Skan case 0: 152169695Skan PRINT_TYPE(int); 153169695Skan break; 154169695Skan case 1: 155169695Skan PRINT_TYPE(long); 156169695Skan break; 157169695Skan case 2: 158169695Skan default: 159169695Skan#if defined(__GNUC__) || defined(HAVE_LONG_LONG) 160169695Skan PRINT_TYPE(long long); 161169695Skan#else 162169695Skan PRINT_TYPE(long); /* Fake it and hope for the best. */ 163169695Skan#endif 164169695Skan break; 165169695Skan } /* End of switch (wide_width) */ 166169695Skan } /* End of else statement */ 167169695Skan } /* End of integer case */ 168169695Skan break; 169169695Skan case 'f': 170169695Skan case 'e': 171169695Skan case 'E': 172169695Skan case 'g': 173169695Skan case 'G': 174169695Skan { 175169695Skan if (wide_width == 0) 176169695Skan PRINT_TYPE(double); 177169695Skan else 178169695Skan { 179169695Skan#if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE) 180169695Skan PRINT_TYPE(long double); 181169695Skan#else 182169695Skan PRINT_TYPE(double); /* Fake it and hope for the best. */ 183169695Skan#endif 184169695Skan } 185169695Skan } 186169695Skan break; 187169695Skan case 's': 188169695Skan PRINT_TYPE(char *); 189169695Skan break; 190169695Skan case 'p': 191169695Skan PRINT_TYPE(void *); 192169695Skan break; 193169695Skan case '%': 194169695Skan PRINT_CHAR('%'); 195169695Skan break; 196169695Skan default: 197169695Skan abort(); 198169695Skan } /* End of switch (*ptr) */ 199169695Skan } /* End of else statement */ 200169695Skan } 201169695Skan 202169695Skan return total_printed; 203169695Skan} 204169695Skan 205169695Skan#ifdef TEST 206169695Skan 207169695Skan#include <math.h> 208169695Skan#ifndef M_PI 209169695Skan#define M_PI (3.1415926535897932385) 210169695Skan#endif 211169695Skan 212169695Skan#define RESULT(x) do \ 213169695Skan{ \ 214169695Skan int i = (x); \ 215169695Skan printf ("printed %d characters\n", i); \ 216169695Skan fflush(stdin); \ 217169695Skan} while (0) 218169695Skan 219169695Skanstatic int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1; 220169695Skan 221169695Skanstatic int 222169695Skancheckit (const char* format, ...) 223169695Skan{ 224169695Skan int result; 225169695Skan VA_OPEN (args, format); 226169695Skan VA_FIXEDARG (args, char *, format); 227169695Skan 228169695Skan result = _doprnt (format, args, stdout); 229169695Skan VA_CLOSE (args); 230169695Skan 231169695Skan return result; 232169695Skan} 233169695Skan 234169695Skanint 235169695Skanmain (void) 236169695Skan{ 237169695Skan RESULT(checkit ("<%d>\n", 0x12345678)); 238169695Skan RESULT(printf ("<%d>\n", 0x12345678)); 239169695Skan 240169695Skan RESULT(checkit ("<%200d>\n", 5)); 241169695Skan RESULT(printf ("<%200d>\n", 5)); 242169695Skan 243169695Skan RESULT(checkit ("<%.300d>\n", 6)); 244169695Skan RESULT(printf ("<%.300d>\n", 6)); 245169695Skan 246169695Skan RESULT(checkit ("<%100.150d>\n", 7)); 247169695Skan RESULT(printf ("<%100.150d>\n", 7)); 248169695Skan 249169695Skan RESULT(checkit ("<%s>\n", 250169695Skan "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 251169695Skan777777777777777777333333333333366666666666622222222222777777777777733333")); 252169695Skan RESULT(printf ("<%s>\n", 253169695Skan "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 254169695Skan777777777777777777333333333333366666666666622222222222777777777777733333")); 255169695Skan 256169695Skan RESULT(checkit ("<%f><%0+#f>%s%d%s>\n", 257169695Skan 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); 258169695Skan RESULT(printf ("<%f><%0+#f>%s%d%s>\n", 259169695Skan 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); 260169695Skan 261169695Skan RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); 262169695Skan RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); 263169695Skan 264169695Skan RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); 265169695Skan RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); 266169695Skan 267169695Skan RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", 268169695Skan 75, 75, 75, 75, 75, 75, 75)); 269169695Skan RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", 270169695Skan 75, 75, 75, 75, 75, 75, 75)); 271169695Skan 272169695Skan RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", 273169695Skan 75, 75, 75, 75, 75, 75, 75)); 274169695Skan RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", 275169695Skan 75, 75, 75, 75, 75, 75, 75)); 276169695Skan 277169695Skan RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); 278169695Skan RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); 279169695Skan 280169695Skan#if defined(__GNUC__) || defined (HAVE_LONG_LONG) 281169695Skan RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); 282169695Skan RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); 283169695Skan RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); 284169695Skan RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); 285169695Skan#endif 286169695Skan 287169695Skan#if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE) 288169695Skan RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", 289169695Skan 1.23456, 1.234567890123456789L, 1.23456)); 290169695Skan RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", 291169695Skan 1.23456, 1.234567890123456789L, 1.23456)); 292169695Skan#endif 293169695Skan 294169695Skan return 0; 295169695Skan} 296169695Skan#endif /* TEST */ 297