_doprnt.c 7.3 KB

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