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