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