189857Sobrien/* Provide a version of _doprnt in terms of fprintf. 289857Sobrien Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 389857Sobrien Contributed by Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98 489857Sobrien 589857SobrienThis program is free software; you can redistribute it and/or modify it 689857Sobrienunder the terms of the GNU General Public License as published by the 789857SobrienFree Software Foundation; either version 2, or (at your option) any 889857Sobrienlater version. 989857Sobrien 1089857SobrienThis program is distributed in the hope that it will be useful, 1189857Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1289857SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1389857SobrienGNU General Public License for more details. 1489857Sobrien 1589857SobrienYou should have received a copy of the GNU General Public License 1689857Sobrienalong with this program; if not, write to the Free Software 17218822SdimFoundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 1889857Sobrien 1989857Sobrien#include "config.h" 2089857Sobrien#include "ansidecl.h" 2189857Sobrien#include "safe-ctype.h" 2289857Sobrien 2389857Sobrien#include <stdio.h> 2489857Sobrien#include <stdarg.h> 2589857Sobrien#ifdef HAVE_STRING_H 2689857Sobrien#include <string.h> 2789857Sobrien#endif 2889857Sobrien#ifdef HAVE_STDLIB_H 2989857Sobrien#include <stdlib.h> 3089857Sobrien#endif 3189857Sobrien 3289857Sobrien#undef _doprnt 3389857Sobrien 3489857Sobrien#ifdef HAVE__DOPRNT 3589857Sobrien#define TEST 3689857Sobrien#endif 3789857Sobrien 3889857Sobrien#ifdef TEST /* Make sure to use the internal one. */ 3989857Sobrien#define _doprnt my_doprnt 4089857Sobrien#endif 4189857Sobrien 4289857Sobrien#define COPY_VA_INT \ 4389857Sobrien do { \ 4489857Sobrien const int value = abs (va_arg (ap, int)); \ 4589857Sobrien char buf[32]; \ 4689857Sobrien ptr++; /* Go past the asterisk. */ \ 4789857Sobrien *sptr = '\0'; /* NULL terminate sptr. */ \ 4889857Sobrien sprintf(buf, "%d", value); \ 4989857Sobrien strcat(sptr, buf); \ 5089857Sobrien while (*sptr) sptr++; \ 5189857Sobrien } while (0) 5289857Sobrien 5389857Sobrien#define PRINT_CHAR(CHAR) \ 5489857Sobrien do { \ 5589857Sobrien putc(CHAR, stream); \ 5689857Sobrien ptr++; \ 5789857Sobrien total_printed++; \ 5889857Sobrien continue; \ 5989857Sobrien } while (0) 6089857Sobrien 6189857Sobrien#define PRINT_TYPE(TYPE) \ 6289857Sobrien do { \ 6389857Sobrien int result; \ 6489857Sobrien TYPE value = va_arg (ap, TYPE); \ 6589857Sobrien *sptr++ = *ptr++; /* Copy the type specifier. */ \ 6689857Sobrien *sptr = '\0'; /* NULL terminate sptr. */ \ 6789857Sobrien result = fprintf(stream, specifier, value); \ 6889857Sobrien if (result == -1) \ 6989857Sobrien return -1; \ 7089857Sobrien else \ 7189857Sobrien { \ 7289857Sobrien total_printed += result; \ 7389857Sobrien continue; \ 7489857Sobrien } \ 7589857Sobrien } while (0) 7689857Sobrien 7789857Sobrienint 78218822Sdim_doprnt (const char *format, va_list ap, FILE *stream) 7989857Sobrien{ 8089857Sobrien const char * ptr = format; 8189857Sobrien char specifier[128]; 8289857Sobrien int total_printed = 0; 8389857Sobrien 8489857Sobrien while (*ptr != '\0') 8589857Sobrien { 8689857Sobrien if (*ptr != '%') /* While we have regular characters, print them. */ 8789857Sobrien PRINT_CHAR(*ptr); 8889857Sobrien else /* We got a format specifier! */ 8989857Sobrien { 9089857Sobrien char * sptr = specifier; 9189857Sobrien int wide_width = 0, short_width = 0; 9289857Sobrien 9389857Sobrien *sptr++ = *ptr++; /* Copy the % and move forward. */ 9489857Sobrien 9589857Sobrien while (strchr ("-+ #0", *ptr)) /* Move past flags. */ 9689857Sobrien *sptr++ = *ptr++; 9789857Sobrien 9889857Sobrien if (*ptr == '*') 9989857Sobrien COPY_VA_INT; 10089857Sobrien else 10189857Sobrien while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ 10289857Sobrien *sptr++ = *ptr++; 10389857Sobrien 10489857Sobrien if (*ptr == '.') 10589857Sobrien { 10689857Sobrien *sptr++ = *ptr++; /* Copy and go past the period. */ 10789857Sobrien if (*ptr == '*') 10889857Sobrien COPY_VA_INT; 10989857Sobrien else 11089857Sobrien while (ISDIGIT(*ptr)) /* Handle explicit numeric value. */ 11189857Sobrien *sptr++ = *ptr++; 11289857Sobrien } 11389857Sobrien while (strchr ("hlL", *ptr)) 11489857Sobrien { 11589857Sobrien switch (*ptr) 11689857Sobrien { 11789857Sobrien case 'h': 11889857Sobrien short_width = 1; 11989857Sobrien break; 12089857Sobrien case 'l': 12189857Sobrien wide_width++; 12289857Sobrien break; 12389857Sobrien case 'L': 12489857Sobrien wide_width = 2; 12589857Sobrien break; 12689857Sobrien default: 12789857Sobrien abort(); 12889857Sobrien } 12989857Sobrien *sptr++ = *ptr++; 13089857Sobrien } 13189857Sobrien 13289857Sobrien switch (*ptr) 13389857Sobrien { 13489857Sobrien case 'd': 13589857Sobrien case 'i': 13689857Sobrien case 'o': 13789857Sobrien case 'u': 13889857Sobrien case 'x': 13989857Sobrien case 'X': 14089857Sobrien case 'c': 14189857Sobrien { 14289857Sobrien /* Short values are promoted to int, so just copy it 14389857Sobrien as an int and trust the C library printf to cast it 14489857Sobrien to the right width. */ 14589857Sobrien if (short_width) 14689857Sobrien PRINT_TYPE(int); 14789857Sobrien else 14889857Sobrien { 14989857Sobrien switch (wide_width) 15089857Sobrien { 15189857Sobrien case 0: 15289857Sobrien PRINT_TYPE(int); 15389857Sobrien break; 15489857Sobrien case 1: 15589857Sobrien PRINT_TYPE(long); 15689857Sobrien break; 15789857Sobrien case 2: 15889857Sobrien default: 15989857Sobrien#if defined(__GNUC__) || defined(HAVE_LONG_LONG) 16089857Sobrien PRINT_TYPE(long long); 16189857Sobrien#else 16289857Sobrien PRINT_TYPE(long); /* Fake it and hope for the best. */ 16389857Sobrien#endif 16489857Sobrien break; 16589857Sobrien } /* End of switch (wide_width) */ 16689857Sobrien } /* End of else statement */ 16789857Sobrien } /* End of integer case */ 16889857Sobrien break; 16989857Sobrien case 'f': 17089857Sobrien case 'e': 17189857Sobrien case 'E': 17289857Sobrien case 'g': 17389857Sobrien case 'G': 17489857Sobrien { 17589857Sobrien if (wide_width == 0) 17689857Sobrien PRINT_TYPE(double); 17789857Sobrien else 17889857Sobrien { 17989857Sobrien#if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE) 18089857Sobrien PRINT_TYPE(long double); 18189857Sobrien#else 18289857Sobrien PRINT_TYPE(double); /* Fake it and hope for the best. */ 18389857Sobrien#endif 18489857Sobrien } 18589857Sobrien } 18689857Sobrien break; 18789857Sobrien case 's': 18889857Sobrien PRINT_TYPE(char *); 18989857Sobrien break; 19089857Sobrien case 'p': 19189857Sobrien PRINT_TYPE(void *); 19289857Sobrien break; 19389857Sobrien case '%': 19489857Sobrien PRINT_CHAR('%'); 19589857Sobrien break; 19689857Sobrien default: 19789857Sobrien abort(); 19889857Sobrien } /* End of switch (*ptr) */ 19989857Sobrien } /* End of else statement */ 20089857Sobrien } 20189857Sobrien 20289857Sobrien return total_printed; 20389857Sobrien} 20489857Sobrien 20589857Sobrien#ifdef TEST 20689857Sobrien 20789857Sobrien#include <math.h> 20889857Sobrien#ifndef M_PI 20989857Sobrien#define M_PI (3.1415926535897932385) 21089857Sobrien#endif 21189857Sobrien 21289857Sobrien#define RESULT(x) do \ 21389857Sobrien{ \ 21489857Sobrien int i = (x); \ 21589857Sobrien printf ("printed %d characters\n", i); \ 21689857Sobrien fflush(stdin); \ 21789857Sobrien} while (0) 21889857Sobrien 219218822Sdimstatic int checkit (const char * format, ...) ATTRIBUTE_PRINTF_1; 22089857Sobrien 22189857Sobrienstatic int 222218822Sdimcheckit (const char* format, ...) 22389857Sobrien{ 22489857Sobrien int result; 22589857Sobrien VA_OPEN (args, format); 22689857Sobrien VA_FIXEDARG (args, char *, format); 22789857Sobrien 22889857Sobrien result = _doprnt (format, args, stdout); 22989857Sobrien VA_CLOSE (args); 23089857Sobrien 23189857Sobrien return result; 23289857Sobrien} 23389857Sobrien 23489857Sobrienint 235218822Sdimmain (void) 23689857Sobrien{ 23789857Sobrien RESULT(checkit ("<%d>\n", 0x12345678)); 23889857Sobrien RESULT(printf ("<%d>\n", 0x12345678)); 23989857Sobrien 24089857Sobrien RESULT(checkit ("<%200d>\n", 5)); 24189857Sobrien RESULT(printf ("<%200d>\n", 5)); 24289857Sobrien 24389857Sobrien RESULT(checkit ("<%.300d>\n", 6)); 24489857Sobrien RESULT(printf ("<%.300d>\n", 6)); 24589857Sobrien 24689857Sobrien RESULT(checkit ("<%100.150d>\n", 7)); 24789857Sobrien RESULT(printf ("<%100.150d>\n", 7)); 24889857Sobrien 24989857Sobrien RESULT(checkit ("<%s>\n", 25089857Sobrien "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 25189857Sobrien777777777777777777333333333333366666666666622222222222777777777777733333")); 25289857Sobrien RESULT(printf ("<%s>\n", 25389857Sobrien "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ 25489857Sobrien777777777777777777333333333333366666666666622222222222777777777777733333")); 25589857Sobrien 25689857Sobrien RESULT(checkit ("<%f><%0+#f>%s%d%s>\n", 25789857Sobrien 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); 25889857Sobrien RESULT(printf ("<%f><%0+#f>%s%d%s>\n", 25989857Sobrien 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx")); 26089857Sobrien 26189857Sobrien RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); 26289857Sobrien RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI)); 26389857Sobrien 26489857Sobrien RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); 26589857Sobrien RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI)); 26689857Sobrien 26789857Sobrien RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", 26889857Sobrien 75, 75, 75, 75, 75, 75, 75)); 26989857Sobrien RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", 27089857Sobrien 75, 75, 75, 75, 75, 75, 75)); 27189857Sobrien 27289857Sobrien RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n", 27389857Sobrien 75, 75, 75, 75, 75, 75, 75)); 27489857Sobrien RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n", 27589857Sobrien 75, 75, 75, 75, 75, 75, 75)); 27689857Sobrien 27789857Sobrien RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); 27889857Sobrien RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456)); 27989857Sobrien 28089857Sobrien#if defined(__GNUC__) || defined (HAVE_LONG_LONG) 28189857Sobrien RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); 28289857Sobrien RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345)); 28389857Sobrien RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); 28489857Sobrien RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345)); 28589857Sobrien#endif 28689857Sobrien 28789857Sobrien#if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE) 28889857Sobrien RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", 28989857Sobrien 1.23456, 1.234567890123456789L, 1.23456)); 29089857Sobrien RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n", 29189857Sobrien 1.23456, 1.234567890123456789L, 1.23456)); 29289857Sobrien#endif 29389857Sobrien 29489857Sobrien return 0; 29589857Sobrien} 29689857Sobrien#endif /* TEST */ 297