quadmath-printf.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /* GCC Quad-Precision Math Library
  2. Copyright (C) 2011 Free Software Foundation, Inc.
  3. Written by Jakub Jelinek <jakub@redhat.com>
  4. This file is part of the libquadmath library.
  5. Libquadmath is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9. Libquadmath is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with libquadmath; see the file COPYING.LIB. If
  15. not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
  16. Boston, MA 02110-1301, USA. */
  17. #include <config.h>
  18. #include <stdarg.h>
  19. #include <string.h>
  20. #include <stdio.h>
  21. #include "quadmath-printf.h"
  22. /* Read a simple integer from a string and update the string pointer.
  23. It is assumed that the first character is a digit. */
  24. static unsigned int
  25. read_int (const char **pstr)
  26. {
  27. unsigned int retval = (unsigned char) **pstr - '0';
  28. while (isdigit ((unsigned char) *++(*pstr)))
  29. {
  30. retval *= 10;
  31. retval += (unsigned char) **pstr - '0';
  32. }
  33. return retval;
  34. }
  35. #define PADSIZE 16
  36. static char const blanks[PADSIZE] =
  37. {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  38. static char const zeroes[PADSIZE] =
  39. {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  40. static wchar_t const wblanks[PADSIZE] =
  41. {
  42. L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '),
  43. L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ')
  44. };
  45. static wchar_t const wzeroes[PADSIZE] =
  46. {
  47. L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'),
  48. L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0')
  49. };
  50. attribute_hidden size_t
  51. __quadmath_do_pad (struct __quadmath_printf_file *fp, int wide, int c,
  52. size_t n)
  53. {
  54. ssize_t i;
  55. char padbuf[PADSIZE];
  56. wchar_t wpadbuf[PADSIZE];
  57. const char *padstr;
  58. size_t w, written = 0;
  59. if (wide)
  60. {
  61. if (c == ' ')
  62. padstr = (const char *) wblanks;
  63. else if (c == '0')
  64. padstr = (const char *) wzeroes;
  65. else
  66. {
  67. padstr = (const char *) wpadbuf;
  68. for (i = 0; i < PADSIZE; i++)
  69. wpadbuf[i] = c;
  70. }
  71. }
  72. else
  73. {
  74. if (c == ' ')
  75. padstr = blanks;
  76. else if (c == '0')
  77. padstr = zeroes;
  78. else
  79. {
  80. padstr = (const char *) padbuf;
  81. for (i = 0; i < PADSIZE; i++)
  82. padbuf[i] = c;
  83. }
  84. }
  85. for (i = n; i >= PADSIZE; i -= PADSIZE)
  86. {
  87. w = PUT (fp, (char *) padstr, PADSIZE);
  88. written += w;
  89. if (w != PADSIZE)
  90. return written;
  91. }
  92. if (i > 0)
  93. {
  94. w = PUT (fp, (char *) padstr, i);
  95. written += w;
  96. }
  97. return written;
  98. }
  99. /* This is a stripped down version of snprintf, which just handles
  100. a single %eEfFgGaA format entry with Q modifier. % has to be
  101. the first character of the format string, no $ can be used. */
  102. int
  103. quadmath_snprintf (char *str, size_t size, const char *format, ...)
  104. {
  105. struct printf_info info;
  106. va_list ap;
  107. __float128 fpnum, *fpnum_addr = &fpnum, **fpnum_addr2 = &fpnum_addr;
  108. struct __quadmath_printf_file qfp;
  109. if (*format++ != '%')
  110. return -1;
  111. /* Clear information structure. */
  112. memset (&info, '\0', sizeof info);
  113. /* info.alt = 0;
  114. info.space = 0;
  115. info.left = 0;
  116. info.showsign = 0;
  117. info.group = 0;
  118. info.i18n = 0;
  119. info.extra = 0; */
  120. info.pad = ' ';
  121. /* info.wide = 0; */
  122. /* Check for spec modifiers. */
  123. do
  124. {
  125. switch (*format)
  126. {
  127. case ' ':
  128. /* Output a space in place of a sign, when there is no sign. */
  129. info.space = 1;
  130. continue;
  131. case '+':
  132. /* Always output + or - for numbers. */
  133. info.showsign = 1;
  134. continue;
  135. case '-':
  136. /* Left-justify things. */
  137. info.left = 1;
  138. continue;
  139. case '#':
  140. /* Use the "alternate form":
  141. Hex has 0x or 0X, FP always has a decimal point. */
  142. info.alt = 1;
  143. continue;
  144. case '0':
  145. /* Pad with 0s. */
  146. info.pad = '0';
  147. continue;
  148. case '\'':
  149. /* Show grouping in numbers if the locale information
  150. indicates any. */
  151. info.group = 1;
  152. continue;
  153. case 'I':
  154. /* Use the internationalized form of the output. Currently
  155. means to use the `outdigits' of the current locale. */
  156. info.i18n = 1;
  157. continue;
  158. default:
  159. break;
  160. }
  161. break;
  162. }
  163. while (*++format);
  164. if (info.left)
  165. info.pad = ' ';
  166. va_start (ap, format);
  167. /* Get the field width. */
  168. /* info.width = 0; */
  169. if (*format == '*')
  170. {
  171. /* The field width is given in an argument.
  172. A negative field width indicates left justification. */
  173. ++format;
  174. info.width = va_arg (ap, int);
  175. }
  176. else if (isdigit (*format))
  177. /* Constant width specification. */
  178. info.width = read_int (&format);
  179. /* Get the precision. */
  180. /* -1 means none given; 0 means explicit 0. */
  181. info.prec = -1;
  182. if (*format == '.')
  183. {
  184. ++format;
  185. if (*format == '*')
  186. {
  187. /* The precision is given in an argument. */
  188. ++format;
  189. info.prec = va_arg (ap, int);
  190. }
  191. else if (isdigit (*format))
  192. info.prec = read_int (&format);
  193. else
  194. /* "%.?" is treated like "%.0?". */
  195. info.prec = 0;
  196. }
  197. /* Check for type modifiers. */
  198. /* info.is_long_double = 0;
  199. info.is_short = 0;
  200. info.is_long = 0;
  201. info.is_char = 0;
  202. info.user = 0; */
  203. /* We require Q modifier. */
  204. if (*format++ != 'Q')
  205. {
  206. va_end (ap);
  207. return -1;
  208. }
  209. /* Get the format specification. */
  210. info.spec = (wchar_t) *format++;
  211. if (info.spec == L_('\0') || *format != '\0')
  212. {
  213. va_end (ap);
  214. return -1;
  215. }
  216. switch (info.spec)
  217. {
  218. case L_('e'):
  219. case L_('E'):
  220. case L_('f'):
  221. case L_('F'):
  222. case L_('g'):
  223. case L_('G'):
  224. case L_('a'):
  225. case L_('A'):
  226. break;
  227. default:
  228. va_end (ap);
  229. return -1;
  230. }
  231. fpnum = va_arg (ap, __float128);
  232. va_end (ap);
  233. qfp.fp = NULL;
  234. qfp.str = str;
  235. qfp.size = size ? size - 1 : 0;
  236. qfp.len = 0;
  237. qfp.file_p = 0;
  238. if (info.spec == L_('a') || info.spec == L_('A'))
  239. __quadmath_printf_fphex (&qfp, &info, (const void *const *)&fpnum_addr2);
  240. else
  241. __quadmath_printf_fp (&qfp, &info, (const void *const *)&fpnum_addr2);
  242. if (size)
  243. *qfp.str = '\0';
  244. return qfp.len;
  245. }
  246. #ifdef HAVE_PRINTF_HOOKS
  247. static int pa_flt128;
  248. int mod_Q attribute_hidden;
  249. static void
  250. flt128_va (void *mem, va_list *ap)
  251. {
  252. __float128 d = va_arg (*ap, __float128);
  253. memcpy (mem, &d, sizeof (d));
  254. }
  255. static int
  256. flt128_ais (const struct printf_info *info, size_t n __attribute__ ((unused)),
  257. int *argtype, int *size)
  258. {
  259. if (info->user & mod_Q)
  260. {
  261. argtype[0] = pa_flt128;
  262. size[0] = sizeof (__float128);
  263. return 1;
  264. }
  265. #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 13)
  266. /* Workaround bug in glibc printf hook handling. */
  267. size[0] = -1;
  268. switch (info->spec)
  269. {
  270. case L_('i'):
  271. case L_('d'):
  272. case L_('u'):
  273. case L_('o'):
  274. case L_('X'):
  275. case L_('x'):
  276. #if __LONG_MAX__ != __LONG_LONG_MAX__
  277. if (info->is_long_double)
  278. argtype[0] = PA_INT|PA_FLAG_LONG_LONG;
  279. else
  280. #endif
  281. if (info->is_long)
  282. argtype[0] = PA_INT|PA_FLAG_LONG;
  283. else if (info->is_short)
  284. argtype[0] = PA_INT|PA_FLAG_SHORT;
  285. else if (info->is_char)
  286. argtype[0] = PA_CHAR;
  287. else
  288. argtype[0] = PA_INT;
  289. return 1;
  290. case L_('e'):
  291. case L_('E'):
  292. case L_('f'):
  293. case L_('F'):
  294. case L_('g'):
  295. case L_('G'):
  296. case L_('a'):
  297. case L_('A'):
  298. if (info->is_long_double)
  299. argtype[0] = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;
  300. else
  301. argtype[0] = PA_DOUBLE;
  302. return 1;
  303. case L_('c'):
  304. argtype[0] = PA_CHAR;
  305. return 1;
  306. case L_('C'):
  307. argtype[0] = PA_WCHAR;
  308. return 1;
  309. case L_('s'):
  310. argtype[0] = PA_STRING;
  311. return 1;
  312. case L_('S'):
  313. argtype[0] = PA_WSTRING;
  314. return 1;
  315. case L_('p'):
  316. argtype[0] = PA_POINTER;
  317. return 1;
  318. case L_('n'):
  319. argtype[0] = PA_INT|PA_FLAG_PTR;
  320. return 1;
  321. case L_('m'):
  322. default:
  323. /* An unknown spec will consume no args. */
  324. return 0;
  325. }
  326. #endif
  327. return -1;
  328. }
  329. static int
  330. flt128_printf_fp (FILE *fp, const struct printf_info *info,
  331. const void *const *args)
  332. {
  333. struct __quadmath_printf_file qpf
  334. = { .fp = fp, .str = NULL, .size = 0, .len = 0, .file_p = 1 };
  335. if ((info->user & mod_Q) == 0)
  336. return -2;
  337. return __quadmath_printf_fp (&qpf, info, args);
  338. }
  339. static int
  340. flt128_printf_fphex (FILE *fp, const struct printf_info *info,
  341. const void *const *args)
  342. {
  343. struct __quadmath_printf_file qpf
  344. = { .fp = fp, .str = NULL, .size = 0, .len = 0, .file_p = 1 };
  345. if ((info->user & mod_Q) == 0)
  346. return -2;
  347. return __quadmath_printf_fphex (&qpf, info, args);
  348. }
  349. __attribute__((constructor)) static void
  350. register_printf_flt128 (void)
  351. {
  352. pa_flt128 = register_printf_type (flt128_va);
  353. if (pa_flt128 == -1)
  354. return;
  355. mod_Q = register_printf_modifier (L_("Q"));
  356. if (mod_Q == -1)
  357. return;
  358. register_printf_specifier ('f', flt128_printf_fp, flt128_ais);
  359. register_printf_specifier ('F', flt128_printf_fp, flt128_ais);
  360. register_printf_specifier ('e', flt128_printf_fp, flt128_ais);
  361. register_printf_specifier ('E', flt128_printf_fp, flt128_ais);
  362. register_printf_specifier ('g', flt128_printf_fp, flt128_ais);
  363. register_printf_specifier ('G', flt128_printf_fp, flt128_ais);
  364. register_printf_specifier ('a', flt128_printf_fphex, flt128_ais);
  365. register_printf_specifier ('A', flt128_printf_fphex, flt128_ais);
  366. }
  367. __attribute__((destructor)) static void
  368. unregister_printf_flt128 (void)
  369. {
  370. /* No way to unregister printf type and modifier currently,
  371. and only one printf specifier can be registered right now. */
  372. if (pa_flt128 == -1 || mod_Q == -1)
  373. return;
  374. register_printf_specifier ('f', NULL, NULL);
  375. register_printf_specifier ('F', NULL, NULL);
  376. register_printf_specifier ('e', NULL, NULL);
  377. register_printf_specifier ('E', NULL, NULL);
  378. register_printf_specifier ('g', NULL, NULL);
  379. register_printf_specifier ('G', NULL, NULL);
  380. register_printf_specifier ('a', NULL, NULL);
  381. register_printf_specifier ('A', NULL, NULL);
  382. }
  383. #endif