1/* Provide a version of _doprnt in terms of fprintf. 2 Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 3 Contributed by Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98 4 5This program is free software; you can redistribute it and/or modify it 6under the terms of the GNU General Public License as published by the 7Free Software Foundation; either version 2, or (at your option) any 8later version. 9 10This program is distributed in the hope that it will be useful, 11but WITHOUT ANY WARRANTY; without even the implied warranty of 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 18 19#include "config.h" 20#include "ansidecl.h" 21#include "safe-ctype.h" 22 23#include <stdio.h> 24#ifdef ANSI_PROTOTYPES 25#include <stdarg.h> 26#else 27#include <varargs.h> 28#endif 29#ifdef HAVE_STRING_H 30#include <string.h> 31#endif 32#ifdef HAVE_STDLIB_H 33#include <stdlib.h> 34#endif 35 36#undef _doprnt 37 38#ifdef HAVE__DOPRNT 39#define TEST 40#endif 41 42#ifdef TEST /* Make sure to use the internal one. */ 43#define _doprnt my_doprnt 44#endif 45 46#define COPY_VA_INT \ 47 do { \ 48 const int value = abs (va_arg (ap, int)); \ 49 char buf[32]; \ 50 ptr++; /* Go past the asterisk. */ \ 51 *sptr = '\0'; /* NULL terminate sptr. */ \ 52 sprintf(buf, "%d", value); \ 53 strcat(sptr, buf); \ 54 while (*sptr) sptr++; \ 55 } while (0) 56 57#define PRINT_CHAR(CHAR) \ 58 do { \ 59 putc(CHAR, stream); \ 60 ptr++; \ 61 total_printed++; \ 62 continue; \ 63 } while (0) 64 65#define PRINT_TYPE(TYPE) \ 66 do { \ 67 int result; \ 68 TYPE value = va_arg (ap, TYPE); \ 69 *sptr++ = *ptr++; /* Copy the type specifier. */ \ 70 *sptr = '\0'; /* NULL terminate sptr. */ \ 71 result = fprintf(stream, specifier, value); \ 72 if (result == -1) \ 73 return -1; \ 74 else \ 75 { \ 76 total_printed += result; \ 77 continue; \ 78 } \ 79 } while (0) 80 81int 82_doprnt (format, ap, stream) 83 const char * format; 84 va_list ap; 85 FILE * stream; 86{ 87 const char * ptr = format; 88 char specifier[128]; 89 int total_printed = 0; 90 91 while (*ptr != '\0') 92 { 93 if (*ptr != '%') /* While we have regular characters, print them. */ 94 PRINT_CHAR(*ptr); 95 else /* We got a format specifier! */ 96 { 97 char * sptr = specifier; 98 int wide_width = 0, short_width = 0; 99 100 *sptr++ = *ptr++; /* Copy the % and move forward. */ 101 102 while (strchr ("-+ #0", *ptr)) /* Move past flags. */ 103 *sptr++ = *ptr++; 104 105 if (*ptr == '*') 106 COPY_VA_INT; 107 else 108 while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ 109 *sptr++ = *ptr++; 110 111 if (*ptr == '.') 112 { 113 *sptr++ = *ptr++; /* Copy and go past the period. */ 114 if (*ptr == '*') 115 COPY_VA_INT; 116 else 117 while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ 118 *sptr++ = *ptr++; 119 } 120 while (strchr ("hlL", *ptr)) 121 { 122 switch (*ptr) 123 { 124 case 'h': 125 short_width = 1; 126 break; 127 case 'l': 128 wide_width++; 129 break; 130 case 'L': 131 wide_width = 2; 132 break; 133 default: 134 abort(); 135 } 136 *sptr++ = *ptr++; 137 } 138 139 switch (*ptr) 140 { 141 case 'd': 142 case 'i': 143 case 'o': 144 case 'u': 145 case 'x': 146 case 'X': 147 case 'c': 148 { 149 /* Short values are promoted to int, so just copy it 150 as an int and trust the C library printf to cast it 151 to the right width. */ 152 if (short_width) 153 PRINT_TYPE(int); 154 else 155 { 156 switch (wide_width) 157 { 158 case 0: 159 PRINT_TYPE(int); 160 break; 161 case 1: 162 PRINT_TYPE(long); 163 break; 164 case 2: 165 default: 166#if defined(__GNUC__) || defined(HAVE_LONG_LONG) 167 PRINT_TYPE(long long); 168#else 169 PRINT_TYPE(long); /* Fake it and hope for the best. */ 170#endif 171 break; 172 } /* End of switch (wide_width) */ 173 } /* End of else statement */ 174 } /* End of integer case */ 175 break; 176 case 'f': 177 case 'e': 178 case 'E': 179 case 'g': 180 case 'G': 181 { 182 if (wide_width == 0) 183 PRINT_TYPE(double); 184 else 185 { 186#if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE) 187 PRINT_TYPE(long double); 188#else 189 PRINT_TYPE(double); /* Fake it and hope for the best. */ 190#endif 191 } 192 } 193 break; 194 case 's': 195 PRINT_TYPE(char *); 196 break; 197 case 'p': 198 PRINT_TYPE(void *); 199 break; 200 case '%': 201 PRINT_CHAR('%'); 202 break; 203 default: 204 abort(); 205 } /* End of switch (*ptr) */ 206 } /* End of else statement */ 207 } 208 209 return total_printed; 210} 211 212#ifdef TEST 213 214#include <math.h> 215#ifndef M_PI 216#define M_PI (3.1415926535897932385) 217#endif 218 219#define RESULT(x) do \ 220{ \ 221 int i = (x); \ 222 printf ("printed %d characters\n", i); \ 223 fflush(stdin); \ 224} while (0) 225 226static int checkit PARAMS ((const char * format, ...)) ATTRIBUTE_PRINTF_1; 227 228static int 229checkit VPARAMS ((const char* format, ...)) 230{ 231 int result; 232 VA_OPEN (args, format); 233 VA_FIXEDARG (args, char *, format); 234 235 result = _doprnt (format, args, stdout); 236 VA_CLOSE (args); 237 238 return result; 239} 240 241int 242main () 243{ 244 RESULT(checkit ("<%d>\n", 0x12345678)); 245 RESULT(printf ("<%d>\n", 0x12345678)); 246 247 RESULT(checkit ("<%200d>\n", 5)); 248 RESULT(printf ("<%200d>\n", 5)); 249 250 RESULT(checkit ("<%.300d>\n", 6)); 251 RESULT(printf ("<%.300d>\n", 6)); 252 253 RESULT(checkit ("<%100.150d>\n", 7)); 254 RESULT(printf ("<%100.150d>\n", 7)); 255 256 RESULT(checkit ("<%s>\n", 257 "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 258777777777777777777333333333333366666666666622222222222777777777777733333")); 259 RESULT(printf ("<%s>\n", 260 "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 261777777777777777777333333333333366666666666622222222222777777777777733333")); 262 263 RESULT(checkit ("<%f><%0+#f>%s%d%s>\n", 264 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); 265 RESULT(printf ("<%f><%0+#f>%s%d%s>\n", 266 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); 267 268 RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); 269 RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); 270 271 RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); 272 RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); 273 274 RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", 275 75, 75, 75, 75, 75, 75, 75)); 276 RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", 277 75, 75, 75, 75, 75, 75, 75)); 278 279 RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", 280 75, 75, 75, 75, 75, 75, 75)); 281 RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", 282 75, 75, 75, 75, 75, 75, 75)); 283 284 RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); 285 RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); 286 287#if defined(__GNUC__) || defined (HAVE_LONG_LONG) 288 RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); 289 RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); 290 RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); 291 RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); 292#endif 293 294#if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE) 295 RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", 296 1.23456, 1.234567890123456789L, 1.23456)); 297 RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", 298 1.23456, 1.234567890123456789L, 1.23456)); 299#endif 300 301 return 0; 302} 303#endif /* TEST */ 304