1 /* Copyright (C) 1991-1999, 2000, 2001, 2002 Free Software Foundation, Inc. 2 This file is part of the GNU C Library. 3 4 The GNU C Library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Lesser General Public 6 License as published by the Free Software Foundation; either 7 version 2.1 of the License, or (at your option) any later version. 8 9 The GNU C Library 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 Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with the GNU C Library; if not, write to the Free 16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 17 02111-1307 USA. */ 18 19 #include <ctype.h> 20 #include <limits.h> 21 #include <printf.h> 22 #include <stdarg.h> 23 #include <stdint.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <errno.h> 27 #include <wchar.h> 28 #include <bits/libc-lock.h> 29 #include <sys/param.h> 30 #include "_itoa.h" 31 #include <locale/localeinfo.h> 32 #include <stdio_private.h> 33 34 /* This code is shared between the standard stdio implementation found 35 in GNU C library and the libio implementation originally found in 36 GNU libg++. 37 38 Beside this it is also shared between the normal and wide character 39 implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995. */ 40 41 42 #ifdef USE_IN_LIBIO 43 /* This code is for use in libio. */ 44 # include <libioP.h> 45 # define FILE _IO_FILE 46 # undef va_list 47 # define va_list _IO_va_list 48 # undef BUFSIZ 49 # define BUFSIZ _IO_BUFSIZ 50 # define ARGCHECK(S, Format) \ 51 do \ 52 { \ 53 /* Check file argument for consistence. */ \ 54 CHECK_FILE (S, -1); \ 55 if (S->_flags & _IO_NO_WRITES) \ 56 { \ 57 __set_errno (EBADF); \ 58 return -1; \ 59 } \ 60 if (Format == NULL) \ 61 { \ 62 MAYBE_SET_EINVAL; \ 63 return -1; \ 64 } \ 65 } while (0) 66 # define UNBUFFERED_P(S) ((S)->_IO_file_flags & _IO_UNBUFFERED) 67 68 # ifndef COMPILE_WPRINTF 69 # define vfprintf _IO_vfprintf 70 # define CHAR_T char 71 # define UCHAR_T unsigned char 72 # define INT_T int 73 # define L_(Str) Str 74 # define ISDIGIT(Ch) ((unsigned int) ((Ch) - '0') < 10) 75 76 # define PUT(F, S, N) _IO_sputn ((F), (S), (N)) 77 # define PAD(Padchar) \ 78 if (width > 0) \ 79 done += INTUSE(_IO_padn) (s, (Padchar), width) 80 # define PUTC(C, F) _IO_putc_unlocked (C, F) 81 # define ORIENT if (s->_vtable_offset == 0 && _IO_fwide (s, -1) != -1)\ 82 return -1 83 # else 84 # define vfprintf _IO_vfwprintf 85 # define CHAR_T wchar_t 86 /* This is a hack!!! There should be a type uwchar_t. */ 87 # define UCHAR_T unsigned int /* uwchar_t */ 88 # define INT_T wint_t 89 # define L_(Str) L##Str 90 # define ISDIGIT(Ch) ((unsigned int) ((Ch) - L'0') < 10) 91 92 # include "_itowa.h" 93 94 # define PUT(F, S, N) _IO_sputn ((F), (S), (N)) 95 # define PAD(Padchar) \ 96 if (width > 0) \ 97 done += _IO_wpadn (s, (Padchar), width) 98 # define PUTC(C, F) _IO_putwc_unlocked (C, F) 99 # define ORIENT if (_IO_fwide (s, 1) != 1) return -1 100 101 # define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case) 102 # define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case) 103 # undef EOF 104 # define EOF WEOF 105 # endif 106 #else /* ! USE_IN_LIBIO */ 107 /* This code is for use in the GNU C library. */ 108 # define ARGCHECK(S, Format) \ 109 do \ 110 { \ 111 /* Check file argument for consistence. */ \ 112 if (!__validfp (S) || !S->__mode.__write) \ 113 { \ 114 __set_errno (EBADF); \ 115 return -1; \ 116 } \ 117 if (Format == NULL) \ 118 { \ 119 __set_errno (EINVAL); \ 120 return -1; \ 121 } \ 122 if (!S->__seen) \ 123 { \ 124 if (__flshfp (S, EOF) == EOF) \ 125 return -1; \ 126 } \ 127 } \ 128 while (0) 129 # define UNBUFFERED_P(s) ((s)->__buffer == NULL) 130 131 # define CHAR_T char 132 # define UCHAR_T unsigned char 133 # define INT_T int 134 # define L_(Str) Str 135 # define ISDIGIT(Ch) isdigit (Ch) 136 137 # define PUT(F, S, N) fwrite (S, 1, N, F) 138 ssize_t __printf_pad __P ((FILE *, char pad, size_t n)); 139 # define PAD(Padchar) \ 140 if (width > 0) \ 141 { ssize_t __res = __printf_pad (s, (Padchar), width); \ 142 if (__res == -1) \ 143 { \ 144 done = -1; \ 145 goto all_done; \ 146 } \ 147 done += __res; } 148 # define PUTC(C, F) putc (C, F) 149 150 /* XXX These declarations should go as soon as the stdio header files 151 have these prototypes. */ 152 extern void __flockfile (FILE *); 153 extern void __funlockfile (FILE *); 154 #endif /* USE_IN_LIBIO */ 155 156 #include "_i18n_number.h" 157 158 /* Include the shared code for parsing the format string. */ 159 #include "printf-parse.h" 160 161 162 #define outchar(Ch) \ 163 do \ 164 { \ 165 register const INT_T outc = (Ch); \ 166 if (PUTC (outc, s) == EOF) \ 167 { \ 168 done = -1; \ 169 goto all_done; \ 170 } \ 171 else \ 172 ++done; \ 173 } \ 174 while (0) 175 176 #define outstring(String, Len) \ 177 do \ 178 { \ 179 if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \ 180 { \ 181 done = -1; \ 182 goto all_done; \ 183 } \ 184 done += (Len); \ 185 } \ 186 while (0) 187 188 /* For handling long_double and longlong we use the same flag. If 189 `long' and `long long' are effectively the same type define it to 190 zero. */ 191 #if LONG_MAX == LONG_LONG_MAX 192 # define is_longlong 0 193 #else 194 # define is_longlong is_long_double 195 #endif 196 197 /* If `long' and `int' is effectively the same type we don't have to 198 handle `long separately. */ 199 #if INT_MAX == LONG_MAX 200 # define is_long_num 0 201 #else 202 # define is_long_num is_long 203 #endif 204 205 206 /* Global variables. */ 207 static const CHAR_T null[] = L_("(null)"); 208 209 210 /* Helper function to provide temporary buffering for unbuffered streams. */ 211 static int buffered_vfprintf __P ((FILE *stream, const CHAR_T *fmt, va_list)) 212 internal_function; 213 214 /* Handle unknown format specifier. */ 215 static int printf_unknown __P ((FILE *, const struct printf_info *, 216 const void *const *)); 217 218 /* Group digits of number string. */ 219 #ifdef COMPILE_WPRINTF 220 static CHAR_T *group_number __P ((CHAR_T *, CHAR_T *, const char *, wchar_t)) 221 internal_function; 222 #else 223 static CHAR_T *group_number __P ((CHAR_T *, CHAR_T *, const char *, 224 const char *)) internal_function; 225 #endif 226 227 228 /* The function itself. */ 229 int 230 vfprintf (FILE *s, const CHAR_T *format, va_list ap) 231 { 232 /* The character used as thousands separator. */ 233 #ifdef COMPILE_WPRINTF 234 wchar_t thousands_sep = L'\0'; 235 #else 236 const char *thousands_sep = NULL; 237 #endif 238 239 /* The string describing the size of groups of digits. */ 240 const char *grouping; 241 242 /* Place to accumulate the result. */ 243 int done; 244 245 /* Current character in format string. */ 246 const UCHAR_T *f; 247 248 /* End of leading constant string. */ 249 const UCHAR_T *lead_str_end; 250 251 /* Points to next format specifier. */ 252 const UCHAR_T *end_of_spec; 253 254 /* Buffer intermediate results. */ 255 CHAR_T work_buffer[1000]; 256 CHAR_T *workstart = NULL; 257 CHAR_T *workend; 258 259 /* State for restartable multibyte character handling functions. */ 260 #ifndef COMPILE_WPRINTF 261 mbstate_t mbstate; 262 #endif 263 264 /* We have to save the original argument pointer. */ 265 va_list ap_save; 266 267 /* Count number of specifiers we already processed. */ 268 int nspecs_done; 269 270 /* For the %m format we may need the current `errno' value. */ 271 int save_errno = errno; 272 273 274 /* This table maps a character into a number representing a 275 class. In each step there is a destination label for each 276 class. */ 277 static const int jump_table[] = 278 { 279 /* ' ' */ 1, 0, 0, /* '#' */ 4, 280 0, /* '%' */ 14, 0, /* '\''*/ 6, 281 0, 0, /* '*' */ 7, /* '+' */ 2, 282 0, /* '-' */ 3, /* '.' */ 9, 0, 283 /* '0' */ 5, /* '1' */ 8, /* '2' */ 8, /* '3' */ 8, 284 /* '4' */ 8, /* '5' */ 8, /* '6' */ 8, /* '7' */ 8, 285 /* '8' */ 8, /* '9' */ 8, 0, 0, 286 0, 0, 0, 0, 287 0, /* 'A' */ 26, 0, /* 'C' */ 25, 288 0, /* 'E' */ 19, /* F */ 19, /* 'G' */ 19, 289 0, /* 'I' */ 29, 0, 0, 290 /* 'L' */ 12, 0, 0, 0, 291 0, 0, 0, /* 'S' */ 21, 292 0, 0, 0, 0, 293 /* 'X' */ 18, 0, /* 'Z' */ 13, 0, 294 0, 0, 0, 0, 295 0, /* 'a' */ 26, 0, /* 'c' */ 20, 296 /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19, 297 /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28, 0, 298 /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17, 299 /* 'p' */ 22, /* 'q' */ 12, 0, /* 's' */ 21, 300 /* 't' */ 27, /* 'u' */ 16, 0, 0, 301 /* 'x' */ 18, 0, /* 'z' */ 13 302 }; 303 304 #define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z')) 305 #define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')]) 306 #if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED 307 /* 'int' is enough and it saves some space on 64 bit systems. */ 308 # define JUMP_TABLE_TYPE const int 309 # define JUMP(ChExpr, table) \ 310 do \ 311 { \ 312 int offset; \ 313 void *__unbounded ptr; \ 314 spec = (ChExpr); \ 315 offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \ 316 : table[CHAR_CLASS (spec)]; \ 317 ptr = &&do_form_unknown + offset; \ 318 goto *ptr; \ 319 } \ 320 while (0) 321 #else 322 # define JUMP_TABLE_TYPE const void *const 323 # define JUMP(ChExpr, table) \ 324 do \ 325 { \ 326 const void *__unbounded ptr; \ 327 spec = (ChExpr); \ 328 ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \ 329 : table[CHAR_CLASS (spec)]; \ 330 goto *ptr; \ 331 } \ 332 while (0) 333 #endif 334 335 #define STEP0_3_TABLE \ 336 /* Step 0: at the beginning. */ \ 337 static JUMP_TABLE_TYPE step0_jumps[30] = \ 338 { \ 339 REF (form_unknown), \ 340 REF (flag_space), /* for ' ' */ \ 341 REF (flag_plus), /* for '+' */ \ 342 REF (flag_minus), /* for '-' */ \ 343 REF (flag_hash), /* for '<hash>' */ \ 344 REF (flag_zero), /* for '0' */ \ 345 REF (flag_quote), /* for '\'' */ \ 346 REF (width_asterics), /* for '*' */ \ 347 REF (width), /* for '1'...'9' */ \ 348 REF (precision), /* for '.' */ \ 349 REF (mod_half), /* for 'h' */ \ 350 REF (mod_long), /* for 'l' */ \ 351 REF (mod_longlong), /* for 'L', 'q' */ \ 352 REF (mod_size_t), /* for 'z', 'Z' */ \ 353 REF (form_percent), /* for '%' */ \ 354 REF (form_integer), /* for 'd', 'i' */ \ 355 REF (form_unsigned), /* for 'u' */ \ 356 REF (form_octal), /* for 'o' */ \ 357 REF (form_hexa), /* for 'X', 'x' */ \ 358 REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ 359 REF (form_character), /* for 'c' */ \ 360 REF (form_string), /* for 's', 'S' */ \ 361 REF (form_pointer), /* for 'p' */ \ 362 REF (form_number), /* for 'n' */ \ 363 REF (form_strerror), /* for 'm' */ \ 364 REF (form_wcharacter), /* for 'C' */ \ 365 REF (form_floathex), /* for 'A', 'a' */ \ 366 REF (mod_ptrdiff_t), /* for 't' */ \ 367 REF (mod_intmax_t), /* for 'j' */ \ 368 REF (flag_i18n), /* for 'I' */ \ 369 }; \ 370 /* Step 1: after processing width. */ \ 371 static JUMP_TABLE_TYPE step1_jumps[30] = \ 372 { \ 373 REF (form_unknown), \ 374 REF (form_unknown), /* for ' ' */ \ 375 REF (form_unknown), /* for '+' */ \ 376 REF (form_unknown), /* for '-' */ \ 377 REF (form_unknown), /* for '<hash>' */ \ 378 REF (form_unknown), /* for '0' */ \ 379 REF (form_unknown), /* for '\'' */ \ 380 REF (form_unknown), /* for '*' */ \ 381 REF (form_unknown), /* for '1'...'9' */ \ 382 REF (precision), /* for '.' */ \ 383 REF (mod_half), /* for 'h' */ \ 384 REF (mod_long), /* for 'l' */ \ 385 REF (mod_longlong), /* for 'L', 'q' */ \ 386 REF (mod_size_t), /* for 'z', 'Z' */ \ 387 REF (form_percent), /* for '%' */ \ 388 REF (form_integer), /* for 'd', 'i' */ \ 389 REF (form_unsigned), /* for 'u' */ \ 390 REF (form_octal), /* for 'o' */ \ 391 REF (form_hexa), /* for 'X', 'x' */ \ 392 REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ 393 REF (form_character), /* for 'c' */ \ 394 REF (form_string), /* for 's', 'S' */ \ 395 REF (form_pointer), /* for 'p' */ \ 396 REF (form_number), /* for 'n' */ \ 397 REF (form_strerror), /* for 'm' */ \ 398 REF (form_wcharacter), /* for 'C' */ \ 399 REF (form_floathex), /* for 'A', 'a' */ \ 400 REF (mod_ptrdiff_t), /* for 't' */ \ 401 REF (mod_intmax_t), /* for 'j' */ \ 402 REF (flag_i18n) /* for 'I' */ \ 403 }; \ 404 /* Step 2: after processing precision. */ \ 405 static JUMP_TABLE_TYPE step2_jumps[30] = \ 406 { \ 407 REF (form_unknown), \ 408 REF (form_unknown), /* for ' ' */ \ 409 REF (form_unknown), /* for '+' */ \ 410 REF (form_unknown), /* for '-' */ \ 411 REF (form_unknown), /* for '<hash>' */ \ 412 REF (form_unknown), /* for '0' */ \ 413 REF (form_unknown), /* for '\'' */ \ 414 REF (form_unknown), /* for '*' */ \ 415 REF (form_unknown), /* for '1'...'9' */ \ 416 REF (form_unknown), /* for '.' */ \ 417 REF (mod_half), /* for 'h' */ \ 418 REF (mod_long), /* for 'l' */ \ 419 REF (mod_longlong), /* for 'L', 'q' */ \ 420 REF (mod_size_t), /* for 'z', 'Z' */ \ 421 REF (form_percent), /* for '%' */ \ 422 REF (form_integer), /* for 'd', 'i' */ \ 423 REF (form_unsigned), /* for 'u' */ \ 424 REF (form_octal), /* for 'o' */ \ 425 REF (form_hexa), /* for 'X', 'x' */ \ 426 REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ 427 REF (form_character), /* for 'c' */ \ 428 REF (form_string), /* for 's', 'S' */ \ 429 REF (form_pointer), /* for 'p' */ \ 430 REF (form_number), /* for 'n' */ \ 431 REF (form_strerror), /* for 'm' */ \ 432 REF (form_wcharacter), /* for 'C' */ \ 433 REF (form_floathex), /* for 'A', 'a' */ \ 434 REF (mod_ptrdiff_t), /* for 't' */ \ 435 REF (mod_intmax_t), /* for 'j' */ \ 436 REF (flag_i18n) /* for 'I' */ \ 437 }; \ 438 /* Step 3a: after processing first 'h' modifier. */ \ 439 static JUMP_TABLE_TYPE step3a_jumps[30] = \ 440 { \ 441 REF (form_unknown), \ 442 REF (form_unknown), /* for ' ' */ \ 443 REF (form_unknown), /* for '+' */ \ 444 REF (form_unknown), /* for '-' */ \ 445 REF (form_unknown), /* for '<hash>' */ \ 446 REF (form_unknown), /* for '0' */ \ 447 REF (form_unknown), /* for '\'' */ \ 448 REF (form_unknown), /* for '*' */ \ 449 REF (form_unknown), /* for '1'...'9' */ \ 450 REF (form_unknown), /* for '.' */ \ 451 REF (mod_halfhalf), /* for 'h' */ \ 452 REF (form_unknown), /* for 'l' */ \ 453 REF (form_unknown), /* for 'L', 'q' */ \ 454 REF (form_unknown), /* for 'z', 'Z' */ \ 455 REF (form_percent), /* for '%' */ \ 456 REF (form_integer), /* for 'd', 'i' */ \ 457 REF (form_unsigned), /* for 'u' */ \ 458 REF (form_octal), /* for 'o' */ \ 459 REF (form_hexa), /* for 'X', 'x' */ \ 460 REF (form_unknown), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ 461 REF (form_unknown), /* for 'c' */ \ 462 REF (form_unknown), /* for 's', 'S' */ \ 463 REF (form_unknown), /* for 'p' */ \ 464 REF (form_number), /* for 'n' */ \ 465 REF (form_unknown), /* for 'm' */ \ 466 REF (form_unknown), /* for 'C' */ \ 467 REF (form_unknown), /* for 'A', 'a' */ \ 468 REF (form_unknown), /* for 't' */ \ 469 REF (form_unknown), /* for 'j' */ \ 470 REF (form_unknown) /* for 'I' */ \ 471 }; \ 472 /* Step 3b: after processing first 'l' modifier. */ \ 473 static JUMP_TABLE_TYPE step3b_jumps[30] = \ 474 { \ 475 REF (form_unknown), \ 476 REF (form_unknown), /* for ' ' */ \ 477 REF (form_unknown), /* for '+' */ \ 478 REF (form_unknown), /* for '-' */ \ 479 REF (form_unknown), /* for '<hash>' */ \ 480 REF (form_unknown), /* for '0' */ \ 481 REF (form_unknown), /* for '\'' */ \ 482 REF (form_unknown), /* for '*' */ \ 483 REF (form_unknown), /* for '1'...'9' */ \ 484 REF (form_unknown), /* for '.' */ \ 485 REF (form_unknown), /* for 'h' */ \ 486 REF (mod_longlong), /* for 'l' */ \ 487 REF (form_unknown), /* for 'L', 'q' */ \ 488 REF (form_unknown), /* for 'z', 'Z' */ \ 489 REF (form_percent), /* for '%' */ \ 490 REF (form_integer), /* for 'd', 'i' */ \ 491 REF (form_unsigned), /* for 'u' */ \ 492 REF (form_octal), /* for 'o' */ \ 493 REF (form_hexa), /* for 'X', 'x' */ \ 494 REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ 495 REF (form_character), /* for 'c' */ \ 496 REF (form_string), /* for 's', 'S' */ \ 497 REF (form_pointer), /* for 'p' */ \ 498 REF (form_number), /* for 'n' */ \ 499 REF (form_strerror), /* for 'm' */ \ 500 REF (form_wcharacter), /* for 'C' */ \ 501 REF (form_floathex), /* for 'A', 'a' */ \ 502 REF (form_unknown), /* for 't' */ \ 503 REF (form_unknown), /* for 'j' */ \ 504 REF (form_unknown) /* for 'I' */ \ 505 } 506 507 #define STEP4_TABLE \ 508 /* Step 4: processing format specifier. */ \ 509 static JUMP_TABLE_TYPE step4_jumps[30] = \ 510 { \ 511 REF (form_unknown), \ 512 REF (form_unknown), /* for ' ' */ \ 513 REF (form_unknown), /* for '+' */ \ 514 REF (form_unknown), /* for '-' */ \ 515 REF (form_unknown), /* for '<hash>' */ \ 516 REF (form_unknown), /* for '0' */ \ 517 REF (form_unknown), /* for '\'' */ \ 518 REF (form_unknown), /* for '*' */ \ 519 REF (form_unknown), /* for '1'...'9' */ \ 520 REF (form_unknown), /* for '.' */ \ 521 REF (form_unknown), /* for 'h' */ \ 522 REF (form_unknown), /* for 'l' */ \ 523 REF (form_unknown), /* for 'L', 'q' */ \ 524 REF (form_unknown), /* for 'z', 'Z' */ \ 525 REF (form_percent), /* for '%' */ \ 526 REF (form_integer), /* for 'd', 'i' */ \ 527 REF (form_unsigned), /* for 'u' */ \ 528 REF (form_octal), /* for 'o' */ \ 529 REF (form_hexa), /* for 'X', 'x' */ \ 530 REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \ 531 REF (form_character), /* for 'c' */ \ 532 REF (form_string), /* for 's', 'S' */ \ 533 REF (form_pointer), /* for 'p' */ \ 534 REF (form_number), /* for 'n' */ \ 535 REF (form_strerror), /* for 'm' */ \ 536 REF (form_wcharacter), /* for 'C' */ \ 537 REF (form_floathex), /* for 'A', 'a' */ \ 538 REF (form_unknown), /* for 't' */ \ 539 REF (form_unknown), /* for 'j' */ \ 540 REF (form_unknown) /* for 'I' */ \ 541 } 542 543 544 #define process_arg(fspec) \ 545 /* Start real work. We know about all flags and modifiers and \ 546 now process the wanted format specifier. */ \ 547 LABEL (form_percent): \ 548 /* Write a literal "%". */ \ 549 outchar (L_('%')); \ 550 break; \ 551 \ 552 LABEL (form_integer): \ 553 /* Signed decimal integer. */ \ 554 base = 10; \ 555 \ 556 if (is_longlong) \ 557 { \ 558 long long int signed_number; \ 559 \ 560 if (fspec == NULL) \ 561 signed_number = va_arg (ap, long long int); \ 562 else \ 563 signed_number = args_value[fspec->data_arg].pa_long_long_int; \ 564 \ 565 is_negative = signed_number < 0; \ 566 number.longlong = is_negative ? (- signed_number) : signed_number; \ 567 \ 568 goto LABEL (longlong_number); \ 569 } \ 570 else \ 571 { \ 572 long int signed_number; \ 573 \ 574 if (fspec == NULL) \ 575 { \ 576 if (is_long_num) \ 577 signed_number = va_arg (ap, long int); \ 578 else /* `char' and `short int' will be promoted to `int'. */ \ 579 signed_number = va_arg (ap, int); \ 580 } \ 581 else \ 582 if (is_long_num) \ 583 signed_number = args_value[fspec->data_arg].pa_long_int; \ 584 else if (!is_short) \ 585 signed_number = args_value[fspec->data_arg].pa_int; \ 586 else \ 587 signed_number = args_value[fspec->data_arg].pa_short_int; \ 588 \ 589 is_negative = signed_number < 0; \ 590 number.word = is_negative ? (- signed_number) : signed_number; \ 591 \ 592 goto LABEL (number); \ 593 } \ 594 /* NOTREACHED */ \ 595 \ 596 LABEL (form_unsigned): \ 597 /* Unsigned decimal integer. */ \ 598 base = 10; \ 599 goto LABEL (unsigned_number); \ 600 /* NOTREACHED */ \ 601 \ 602 LABEL (form_octal): \ 603 /* Unsigned octal integer. */ \ 604 base = 8; \ 605 goto LABEL (unsigned_number); \ 606 /* NOTREACHED */ \ 607 \ 608 LABEL (form_hexa): \ 609 /* Unsigned hexadecimal integer. */ \ 610 base = 16; \ 611 \ 612 LABEL (unsigned_number): /* Unsigned number of base BASE. */ \ 613 \ 614 /* ISO specifies the `+' and ` ' flags only for signed \ 615 conversions. */ \ 616 is_negative = 0; \ 617 showsign = 0; \ 618 space = 0; \ 619 \ 620 if (is_longlong) \ 621 { \ 622 if (fspec == NULL) \ 623 number.longlong = va_arg (ap, unsigned long long int); \ 624 else \ 625 number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \ 626 \ 627 LABEL (longlong_number): \ 628 if (prec < 0) \ 629 /* Supply a default precision if none was given. */ \ 630 prec = 1; \ 631 else \ 632 /* We have to take care for the '0' flag. If a precision \ 633 is given it must be ignored. */ \ 634 pad = L_(' '); \ 635 \ 636 /* If the precision is 0 and the number is 0 nothing has to \ 637 be written for the number, except for the 'o' format in \ 638 alternate form. */ \ 639 if (prec == 0 && number.longlong == 0) \ 640 { \ 641 string = workend; \ 642 if (base == 8 && alt) \ 643 *--string = L_('0'); \ 644 } \ 645 else \ 646 { \ 647 /* Put the number in WORK. */ \ 648 string = _itoa (number.longlong, workend, base, \ 649 spec == L_('X')); \ 650 if (group && grouping) \ 651 string = group_number (string, workend, grouping, \ 652 thousands_sep); \ 653 \ 654 if (use_outdigits && base == 10) \ 655 string = _i18n_number_rewrite (string, workend); \ 656 } \ 657 /* Simplify further test for num != 0. */ \ 658 number.word = number.longlong != 0; \ 659 } \ 660 else \ 661 { \ 662 if (fspec == NULL) \ 663 { \ 664 if (is_long_num) \ 665 number.word = va_arg (ap, unsigned long int); \ 666 else if (is_char) \ 667 number.word = (unsigned char) va_arg (ap, unsigned int); \ 668 else if (!is_short) \ 669 number.word = va_arg (ap, unsigned int); \ 670 else \ 671 number.word = (unsigned short int) va_arg (ap, unsigned int); \ 672 } \ 673 else \ 674 if (is_long_num) \ 675 number.word = args_value[fspec->data_arg].pa_u_long_int; \ 676 else if (is_char) \ 677 number.word = (unsigned char) \ 678 args_value[fspec->data_arg].pa_char; \ 679 else if (!is_short) \ 680 number.word = args_value[fspec->data_arg].pa_u_int; \ 681 else \ 682 number.word = (unsigned short int) \ 683 args_value[fspec->data_arg].pa_u_short_int; \ 684 \ 685 LABEL (number): \ 686 if (prec < 0) \ 687 /* Supply a default precision if none was given. */ \ 688 prec = 1; \ 689 else \ 690 /* We have to take care for the '0' flag. If a precision \ 691 is given it must be ignored. */ \ 692 pad = L_(' '); \ 693 \ 694 /* If the precision is 0 and the number is 0 nothing has to \ 695 be written for the number, except for the 'o' format in \ 696 alternate form. */ \ 697 if (prec == 0 && number.word == 0) \ 698 { \ 699 string = workend; \ 700 if (base == 8 && alt) \ 701 *--string = L_('0'); \ 702 } \ 703 else \ 704 { \ 705 /* Put the number in WORK. */ \ 706 string = _itoa_word (number.word, workend, base, \ 707 spec == L_('X')); \ 708 if (group && grouping) \ 709 string = group_number (string, workend, grouping, \ 710 thousands_sep); \ 711 \ 712 if (use_outdigits && base == 10) \ 713 string = _i18n_number_rewrite (string, workend); \ 714 } \ 715 } \ 716 \ 717 if (prec <= workend - string && number.word != 0 && alt && base == 8) \ 718 /* Add octal marker. */ \ 719 *--string = L_('0'); \ 720 \ 721 prec = MAX (0, prec - (workend - string)); \ 722 \ 723 if (!left) \ 724 { \ 725 width -= workend - string + prec; \ 726 \ 727 if (number.word != 0 && alt && base == 16) \ 728 /* Account for 0X hex marker. */ \ 729 width -= 2; \ 730 \ 731 if (is_negative || showsign || space) \ 732 --width; \ 733 \ 734 if (pad == L_(' ')) \ 735 { \ 736 PAD (L_(' ')); \ 737 width = 0; \ 738 } \ 739 \ 740 if (is_negative) \ 741 outchar (L_('-')); \ 742 else if (showsign) \ 743 outchar (L_('+')); \ 744 else if (space) \ 745 outchar (L_(' ')); \ 746 \ 747 if (number.word != 0 && alt && base == 16) \ 748 { \ 749 outchar (L_('0')); \ 750 outchar (spec); \ 751 } \ 752 \ 753 width += prec; \ 754 PAD (L_('0')); \ 755 \ 756 outstring (string, workend - string); \ 757 \ 758 break; \ 759 } \ 760 else \ 761 { \ 762 if (is_negative) \ 763 { \ 764 outchar (L_('-')); \ 765 --width; \ 766 } \ 767 else if (showsign) \ 768 { \ 769 outchar (L_('+')); \ 770 --width; \ 771 } \ 772 else if (space) \ 773 { \ 774 outchar (L_(' ')); \ 775 --width; \ 776 } \ 777 \ 778 if (number.word != 0 && alt && base == 16) \ 779 { \ 780 outchar (L_('0')); \ 781 outchar (spec); \ 782 width -= 2; \ 783 } \ 784 \ 785 width -= workend - string + prec; \ 786 \ 787 if (prec > 0) \ 788 { \ 789 int temp = width; \ 790 width = prec; \ 791 PAD (L_('0'));; \ 792 width = temp; \ 793 } \ 794 \ 795 outstring (string, workend - string); \ 796 \ 797 PAD (L_(' ')); \ 798 break; \ 799 } \ 800 \ 801 LABEL (form_float): \ 802 { \ 803 /* Floating-point number. This is handled by printf_fp.c. */ \ 804 const void *ptr; \ 805 int function_done; \ 806 \ 807 if (fspec == NULL) \ 808 { \ 809 struct printf_info info = { prec: prec, \ 810 width: width, \ 811 spec: spec, \ 812 is_long_double: is_long_double, \ 813 is_short: is_short, \ 814 is_long: is_long, \ 815 alt: alt, \ 816 space: space, \ 817 left: left, \ 818 showsign: showsign, \ 819 group: group, \ 820 pad: pad, \ 821 extra: 0, \ 822 wide: sizeof (CHAR_T) != 1 }; \ 823 \ 824 if (is_long_double) \ 825 the_arg.pa_long_double = va_arg (ap, long double); \ 826 else \ 827 the_arg.pa_double = va_arg (ap, double); \ 828 ptr = (const void *) &the_arg; \ 829 \ 830 function_done = __printf_fp (s, &info, &ptr); \ 831 } \ 832 else \ 833 { \ 834 ptr = (const void *) &args_value[fspec->data_arg]; \ 835 \ 836 function_done = __printf_fp (s, &fspec->info, &ptr); \ 837 } \ 838 \ 839 if (function_done < 0) \ 840 { \ 841 /* Error in print handler. */ \ 842 done = -1; \ 843 goto all_done; \ 844 } \ 845 \ 846 done += function_done; \ 847 } \ 848 break; \ 849 \ 850 LABEL (form_floathex): \ 851 { \ 852 /* Floating point number printed as hexadecimal number. */ \ 853 const void *ptr; \ 854 int function_done; \ 855 \ 856 if (fspec == NULL) \ 857 { \ 858 struct printf_info info = { prec: prec, \ 859 width: width, \ 860 spec: spec, \ 861 is_long_double: is_long_double, \ 862 is_short: is_short, \ 863 is_long: is_long, \ 864 alt: alt, \ 865 space: space, \ 866 left: left, \ 867 showsign: showsign, \ 868 group: group, \ 869 pad: pad, \ 870 extra: 0, \ 871 wide: sizeof (CHAR_T) != 1 }; \ 872 \ 873 if (is_long_double) \ 874 the_arg.pa_long_double = va_arg (ap, long double); \ 875 else \ 876 the_arg.pa_double = va_arg (ap, double); \ 877 ptr = (const void *) &the_arg; \ 878 \ 879 function_done = __printf_fphex (s, &info, &ptr); \ 880 } \ 881 else \ 882 { \ 883 ptr = (const void *) &args_value[fspec->data_arg]; \ 884 \ 885 function_done = __printf_fphex (s, &fspec->info, &ptr); \ 886 } \ 887 \ 888 if (function_done < 0) \ 889 { \ 890 /* Error in print handler. */ \ 891 done = -1; \ 892 goto all_done; \ 893 } \ 894 \ 895 done += function_done; \ 896 } \ 897 break; \ 898 \ 899 LABEL (form_pointer): \ 900 /* Generic pointer. */ \ 901 { \ 902 const void *ptr; \ 903 if (fspec == NULL) \ 904 ptr = va_arg (ap, void *); \ 905 else \ 906 ptr = args_value[fspec->data_arg].pa_pointer; \ 907 if (ptr != NULL) \ 908 { \ 909 /* If the pointer is not NULL, write it as a %#x spec. */ \ 910 base = 16; \ 911 number.word = (unsigned long int) ptr; \ 912 is_negative = 0; \ 913 alt = 1; \ 914 group = 0; \ 915 spec = L_('x'); \ 916 goto LABEL (number); \ 917 } \ 918 else \ 919 { \ 920 /* Write "(nil)" for a nil pointer. */ \ 921 string = (CHAR_T *) L_("(nil)"); \ 922 /* Make sure the full string "(nil)" is printed. */ \ 923 if (prec < 5) \ 924 prec = 5; \ 925 is_long = 0; /* This is no wide-char string. */ \ 926 goto LABEL (print_string); \ 927 } \ 928 } \ 929 /* NOTREACHED */ \ 930 \ 931 LABEL (form_number): \ 932 /* Answer the count of characters written. */ \ 933 if (fspec == NULL) \ 934 { \ 935 if (is_longlong) \ 936 *(long long int *) va_arg (ap, void *) = done; \ 937 else if (is_long_num) \ 938 *(long int *) va_arg (ap, void *) = done; \ 939 else if (is_char) \ 940 *(char *) va_arg (ap, void *) = done; \ 941 else if (!is_short) \ 942 *(int *) va_arg (ap, void *) = done; \ 943 else \ 944 *(short int *) va_arg (ap, void *) = done; \ 945 } \ 946 else \ 947 if (is_longlong) \ 948 *(long long int *) args_value[fspec->data_arg].pa_pointer = done; \ 949 else if (is_long_num) \ 950 *(long int *) args_value[fspec->data_arg].pa_pointer = done; \ 951 else if (is_char) \ 952 *(char *) args_value[fspec->data_arg].pa_pointer = done; \ 953 else if (!is_short) \ 954 *(int *) args_value[fspec->data_arg].pa_pointer = done; \ 955 else \ 956 *(short int *) args_value[fspec->data_arg].pa_pointer = done; \ 957 break; \ 958 \ 959 LABEL (form_strerror): \ 960 /* Print description of error ERRNO. */ \ 961 string = \ 962 (CHAR_T *) __strerror_r (save_errno, (char *) work_buffer, \ 963 sizeof work_buffer); \ 964 is_long = 0; /* This is no wide-char string. */ \ 965 goto LABEL (print_string) 966 967 #ifdef COMPILE_WPRINTF 968 # define process_string_arg(fspec) \ 969 LABEL (form_character): \ 970 /* Character. */ \ 971 if (is_long) \ 972 goto LABEL (form_wcharacter); \ 973 --width; /* Account for the character itself. */ \ 974 if (!left) \ 975 PAD (L' '); \ 976 if (fspec == NULL) \ 977 outchar (__btowc ((unsigned char) va_arg (ap, int))); /* Promoted. */ \ 978 else \ 979 outchar (__btowc ((unsigned char) \ 980 args_value[fspec->data_arg].pa_char)); \ 981 if (left) \ 982 PAD (L' '); \ 983 break; \ 984 \ 985 LABEL (form_wcharacter): \ 986 { \ 987 /* Wide character. */ \ 988 --width; \ 989 if (!left) \ 990 PAD (L' '); \ 991 if (fspec == NULL) \ 992 outchar (va_arg (ap, wchar_t)); \ 993 else \ 994 outchar (args_value[fspec->data_arg].pa_wchar); \ 995 if (left) \ 996 PAD (L' '); \ 997 } \ 998 break; \ 999 \ 1000 LABEL (form_string): \ 1001 { \ 1002 size_t len; \ 1003 int string_malloced; \ 1004 \ 1005 /* The string argument could in fact be `char *' or `wchar_t *'. \ 1006 But this should not make a difference here. */ \ 1007 if (fspec == NULL) \ 1008 string = (CHAR_T *) va_arg (ap, const wchar_t *); \ 1009 else \ 1010 string = (CHAR_T *) args_value[fspec->data_arg].pa_wstring; \ 1011 \ 1012 /* Entry point for printing other strings. */ \ 1013 LABEL (print_string): \ 1014 \ 1015 string_malloced = 0; \ 1016 if (string == NULL) \ 1017 { \ 1018 /* Write "(null)" if there's space. */ \ 1019 if (prec == -1 \ 1020 || prec >= (int) (sizeof (null) / sizeof (null[0])) - 1) \ 1021 { \ 1022 string = (CHAR_T *) null; \ 1023 len = (sizeof (null) / sizeof (null[0])) - 1; \ 1024 } \ 1025 else \ 1026 { \ 1027 string = (CHAR_T *) L""; \ 1028 len = 0; \ 1029 } \ 1030 } \ 1031 else if (!is_long && spec != L_('S')) \ 1032 { \ 1033 /* This is complicated. We have to transform the multibyte \ 1034 string into a wide character string. */ \ 1035 const char *mbs = (const char *) string; \ 1036 mbstate_t mbstate; \ 1037 \ 1038 len = prec != -1 ? (size_t) prec : strlen (mbs); \ 1039 \ 1040 /* Allocate dynamically an array which definitely is long \ 1041 enough for the wide character version. */ \ 1042 if (len < 8192) \ 1043 string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \ 1044 else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \ 1045 == NULL) \ 1046 { \ 1047 done = -1; \ 1048 goto all_done; \ 1049 } \ 1050 else \ 1051 string_malloced = 1; \ 1052 \ 1053 memset (&mbstate, '\0', sizeof (mbstate_t)); \ 1054 len = __mbsrtowcs (string, &mbs, len, &mbstate); \ 1055 if (len == (size_t) -1) \ 1056 { \ 1057 /* Illegal multibyte character. */ \ 1058 done = -1; \ 1059 goto all_done; \ 1060 } \ 1061 } \ 1062 else \ 1063 { \ 1064 if (prec != -1) \ 1065 /* Search for the end of the string, but don't search past \ 1066 the length specified by the precision. */ \ 1067 len = __wcsnlen (string, prec); \ 1068 else \ 1069 len = __wcslen (string); \ 1070 } \ 1071 \ 1072 if ((width -= len) < 0) \ 1073 { \ 1074 outstring (string, len); \ 1075 break; \ 1076 } \ 1077 \ 1078 if (!left) \ 1079 PAD (L' '); \ 1080 outstring (string, len); \ 1081 if (left) \ 1082 PAD (L' '); \ 1083 if (__builtin_expect (string_malloced, 0)) \ 1084 free (string); \ 1085 } \ 1086 break; 1087 #else 1088 # define process_string_arg(fspec) \ 1089 LABEL (form_character): \ 1090 /* Character. */ \ 1091 if (is_long) \ 1092 goto LABEL (form_wcharacter); \ 1093 --width; /* Account for the character itself. */ \ 1094 if (!left) \ 1095 PAD (' '); \ 1096 if (fspec == NULL) \ 1097 outchar ((unsigned char) va_arg (ap, int)); /* Promoted. */ \ 1098 else \ 1099 outchar ((unsigned char) args_value[fspec->data_arg].pa_char); \ 1100 if (left) \ 1101 PAD (' '); \ 1102 break; \ 1103 \ 1104 LABEL (form_wcharacter): \ 1105 { \ 1106 /* Wide character. */ \ 1107 char buf[MB_CUR_MAX]; \ 1108 mbstate_t mbstate; \ 1109 size_t len; \ 1110 \ 1111 memset (&mbstate, '\0', sizeof (mbstate_t)); \ 1112 len = __wcrtomb (buf, (fspec == NULL ? va_arg (ap, wchar_t) \ 1113 : args_value[fspec->data_arg].pa_wchar), \ 1114 &mbstate); \ 1115 if (len == (size_t) -1) \ 1116 { \ 1117 /* Something went wron gduring the conversion. Bail out. */ \ 1118 done = -1; \ 1119 goto all_done; \ 1120 } \ 1121 width -= len; \ 1122 if (!left) \ 1123 PAD (' '); \ 1124 outstring (buf, len); \ 1125 if (left) \ 1126 PAD (' '); \ 1127 } \ 1128 break; \ 1129 \ 1130 LABEL (form_string): \ 1131 { \ 1132 size_t len; \ 1133 int string_malloced; \ 1134 \ 1135 /* The string argument could in fact be `char *' or `wchar_t *'. \ 1136 But this should not make a difference here. */ \ 1137 if (fspec == NULL) \ 1138 string = (char *) va_arg (ap, const char *); \ 1139 else \ 1140 string = (char *) args_value[fspec->data_arg].pa_string; \ 1141 \ 1142 /* Entry point for printing other strings. */ \ 1143 LABEL (print_string): \ 1144 \ 1145 string_malloced = 0; \ 1146 if (string == NULL) \ 1147 { \ 1148 /* Write "(null)" if there's space. */ \ 1149 if (prec == -1 || prec >= (int) sizeof (null) - 1) \ 1150 { \ 1151 string = (char *) null; \ 1152 len = sizeof (null) - 1; \ 1153 } \ 1154 else \ 1155 { \ 1156 string = (char *) ""; \ 1157 len = 0; \ 1158 } \ 1159 } \ 1160 else if (!is_long && spec != L_('S')) \ 1161 { \ 1162 if (prec != -1) \ 1163 { \ 1164 /* Search for the end of the string, but don't search past \ 1165 the length (in bytes) specified by the precision. Also \ 1166 don't use incomplete characters. */ \ 1167 if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX) == 1) \ 1168 len = __strnlen (string, prec); \ 1169 else \ 1170 { \ 1171 /* In case we have a multibyte character set the \ 1172 situation is more compilcated. We must not copy \ 1173 bytes at the end which form an incomplete character. */\ 1174 wchar_t ignore[prec]; \ 1175 const char *str2 = string; \ 1176 mbstate_t ps; \ 1177 \ 1178 memset (&ps, '\0', sizeof (ps)); \ 1179 if (__mbsnrtowcs (ignore, &str2, prec, prec, &ps) \ 1180 == (size_t) -1) \ 1181 { \ 1182 done = -1; \ 1183 goto all_done; \ 1184 } \ 1185 if (str2 == NULL) \ 1186 len = strlen (string); \ 1187 else \ 1188 len = str2 - string - (ps.__count); \ 1189 } \ 1190 } \ 1191 else \ 1192 len = strlen (string); \ 1193 } \ 1194 else \ 1195 { \ 1196 const wchar_t *s2 = (const wchar_t *) string; \ 1197 mbstate_t mbstate; \ 1198 \ 1199 memset (&mbstate, '\0', sizeof (mbstate_t)); \ 1200 \ 1201 if (prec >= 0) \ 1202 { \ 1203 /* The string `s2' might not be NUL terminated. */ \ 1204 if (prec < 32768) \ 1205 string = (char *) alloca (prec); \ 1206 else if ((string = (char *) malloc (prec)) == NULL) \ 1207 { \ 1208 done = -1; \ 1209 goto all_done; \ 1210 } \ 1211 else \ 1212 string_malloced = 1; \ 1213 len = __wcsrtombs (string, &s2, prec, &mbstate); \ 1214 } \ 1215 else \ 1216 { \ 1217 len = __wcsrtombs (NULL, &s2, 0, &mbstate); \ 1218 if (len != (size_t) -1) \ 1219 { \ 1220 assert (__mbsinit (&mbstate)); \ 1221 s2 = (const wchar_t *) string; \ 1222 if (len + 1 < 32768) \ 1223 string = (char *) alloca (len + 1); \ 1224 else if ((string = (char *) malloc (len + 1)) == NULL) \ 1225 { \ 1226 done = -1; \ 1227 goto all_done; \ 1228 } \ 1229 else \ 1230 string_malloced = 1; \ 1231 (void) __wcsrtombs (string, &s2, len + 1, &mbstate); \ 1232 } \ 1233 } \ 1234 \ 1235 if (len == (size_t) -1) \ 1236 { \ 1237 /* Illegal wide-character string. */ \ 1238 done = -1; \ 1239 goto all_done; \ 1240 } \ 1241 } \ 1242 \ 1243 if ((width -= len) < 0) \ 1244 { \ 1245 outstring (string, len); \ 1246 break; \ 1247 } \ 1248 \ 1249 if (!left) \ 1250 PAD (' '); \ 1251 outstring (string, len); \ 1252 if (left) \ 1253 PAD (' '); \ 1254 if (__builtin_expect (string_malloced, 0)) \ 1255 free (string); \ 1256 } \ 1257 break; 1258 #endif 1259 1260 /* Orient the stream. */ 1261 #ifdef ORIENT 1262 ORIENT; 1263 #endif 1264 1265 /* Sanity check of arguments. */ 1266 ARGCHECK (s, format); 1267 1268 #ifdef ORIENT 1269 /* Check for correct orientation. */ 1270 if ( 1271 # ifdef USE_IN_LIBIO 1272 s->_vtable_offset == 0 && 1273 # endif 1274 _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1) 1275 != (sizeof (CHAR_T) == 1 ? -1 : 1)) 1276 /* The stream is already oriented otherwise. */ 1277 return EOF; 1278 #endif 1279 1280 if (UNBUFFERED_P (s)) 1281 /* Use a helper function which will allocate a local temporary buffer 1282 for the stream and then call us again. */ 1283 return buffered_vfprintf (s, format, ap); 1284 1285 /* Initialize local variables. */ 1286 done = 0; 1287 grouping = (const char *) -1; 1288 #ifdef __va_copy 1289 /* This macro will be available soon in gcc's <stdarg.h>. We need it 1290 since on some systems `va_list' is not an integral type. */ 1291 __va_copy (ap_save, ap); 1292 #else 1293 ap_save = ap; 1294 #endif 1295 nspecs_done = 0; 1296 1297 #ifdef COMPILE_WPRINTF 1298 /* Find the first format specifier. */ 1299 f = lead_str_end = find_spec ((const UCHAR_T *) format); 1300 #else 1301 /* Put state for processing format string in initial state. */ 1302 memset (&mbstate, '\0', sizeof (mbstate_t)); 1303 1304 /* Find the first format specifier. */ 1305 f = lead_str_end = find_spec (format, &mbstate); 1306 #endif 1307 1308 /* Lock stream. */ 1309 #ifdef USE_IN_LIBIO 1310 __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s); 1311 _IO_flockfile (s); 1312 #else 1313 __libc_cleanup_region_start (1, (void (*) (void *)) &__funlockfile, s); 1314 __flockfile (s); 1315 #endif 1316 1317 /* Write the literal text before the first format. */ 1318 outstring ((const UCHAR_T *) format, 1319 lead_str_end - (const UCHAR_T *) format); 1320 1321 /* If we only have to print a simple string, return now. */ 1322 if (*f == L_('\0')) 1323 goto all_done; 1324 1325 /* Process whole format string. */ 1326 do 1327 { 1328 #if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED 1329 # define REF(Name) &&do_##Name - &&do_form_unknown 1330 #else 1331 # define REF(Name) &&do_##Name 1332 #endif 1333 #define LABEL(Name) do_##Name 1334 STEP0_3_TABLE; 1335 STEP4_TABLE; 1336 1337 union printf_arg *args_value; /* This is not used here but ... */ 1338 int is_negative; /* Flag for negative number. */ 1339 union 1340 { 1341 unsigned long long int longlong; 1342 unsigned long int word; 1343 } number; 1344 int base; 1345 union printf_arg the_arg; 1346 CHAR_T *string; /* Pointer to argument string. */ 1347 int alt = 0; /* Alternate format. */ 1348 int space = 0; /* Use space prefix if no sign is needed. */ 1349 int left = 0; /* Left-justify output. */ 1350 int showsign = 0; /* Always begin with plus or minus sign. */ 1351 int group = 0; /* Print numbers according grouping rules. */ 1352 int is_long_double = 0; /* Argument is long double/ long long int. */ 1353 int is_short = 0; /* Argument is short int. */ 1354 int is_long = 0; /* Argument is long int. */ 1355 int is_char = 0; /* Argument is promoted (unsigned) char. */ 1356 int width = 0; /* Width of output; 0 means none specified. */ 1357 int prec = -1; /* Precision of output; -1 means none specified. */ 1358 /* This flag is set by the 'I' modifier and selects the use of the 1359 `outdigits' as determined by the current locale. */ 1360 int use_outdigits = 0; 1361 UCHAR_T pad = L_(' ');/* Padding character. */ 1362 CHAR_T spec; 1363 1364 workstart = NULL; 1365 workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)]; 1366 1367 /* Get current character in format string. */ 1368 JUMP (*++f, step0_jumps); 1369 1370 /* ' ' flag. */ 1371 LABEL (flag_space): 1372 space = 1; 1373 JUMP (*++f, step0_jumps); 1374 1375 /* '+' flag. */ 1376 LABEL (flag_plus): 1377 showsign = 1; 1378 JUMP (*++f, step0_jumps); 1379 1380 /* The '-' flag. */ 1381 LABEL (flag_minus): 1382 left = 1; 1383 pad = L_(' '); 1384 JUMP (*++f, step0_jumps); 1385 1386 /* The '#' flag. */ 1387 LABEL (flag_hash): 1388 alt = 1; 1389 JUMP (*++f, step0_jumps); 1390 1391 /* The '0' flag. */ 1392 LABEL (flag_zero): 1393 if (!left) 1394 pad = L_('0'); 1395 JUMP (*++f, step0_jumps); 1396 1397 /* The '\'' flag. */ 1398 LABEL (flag_quote): 1399 group = 1; 1400 1401 if (grouping == (const char *) -1) 1402 { 1403 #ifdef COMPILE_WPRINTF 1404 thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC, 1405 _NL_NUMERIC_THOUSANDS_SEP_WC); 1406 #else 1407 thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); 1408 #endif 1409 1410 grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); 1411 if (*grouping == '\0' || *grouping == CHAR_MAX 1412 #ifdef COMPILE_WPRINTF 1413 || thousands_sep == L'\0' 1414 #else 1415 || *thousands_sep == '\0' 1416 #endif 1417 ) 1418 grouping = NULL; 1419 } 1420 JUMP (*++f, step0_jumps); 1421 1422 LABEL (flag_i18n): 1423 use_outdigits = 1; 1424 JUMP (*++f, step0_jumps); 1425 1426 /* Get width from argument. */ 1427 LABEL (width_asterics): 1428 { 1429 const UCHAR_T *tmp; /* Temporary value. */ 1430 1431 tmp = ++f; 1432 if (ISDIGIT (*tmp) && read_int (&tmp) && *tmp == L_('$')) 1433 /* The width comes from a positional parameter. */ 1434 goto do_positional; 1435 1436 width = va_arg (ap, int); 1437 1438 /* Negative width means left justified. */ 1439 if (width < 0) 1440 { 1441 width = -width; 1442 pad = L_(' '); 1443 left = 1; 1444 } 1445 1446 if (width + 32 >= (int) (sizeof (work_buffer) 1447 / sizeof (work_buffer[0]))) 1448 { 1449 /* We have to use a special buffer. The "32" is just a safe 1450 bet for all the output which is not counted in the width. */ 1451 if (width < (int) (32768 / sizeof (CHAR_T))) 1452 workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T)) 1453 + (width + 32)); 1454 else 1455 { 1456 workstart = (CHAR_T *) malloc ((width + 32) * sizeof (CHAR_T)); 1457 if (workstart == NULL) 1458 { 1459 done = -1; 1460 goto all_done; 1461 } 1462 workend = workstart + (width + 32); 1463 } 1464 } 1465 } 1466 JUMP (*f, step1_jumps); 1467 1468 /* Given width in format string. */ 1469 LABEL (width): 1470 width = read_int (&f); 1471 1472 if (width + 32 >= (int) (sizeof (work_buffer) / sizeof (work_buffer[0]))) 1473 { 1474 /* We have to use a special buffer. The "32" is just a safe 1475 bet for all the output which is not counted in the width. */ 1476 if (width < (int) (32768 / sizeof (CHAR_T))) 1477 workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T)) 1478 + (width + 32)); 1479 else 1480 { 1481 workstart = (CHAR_T *) malloc ((width + 32) * sizeof (CHAR_T)); 1482 if (workstart == NULL) 1483 { 1484 done = -1; 1485 goto all_done; 1486 } 1487 workend = workstart + (width + 32); 1488 } 1489 } 1490 if (*f == L_('$')) 1491 /* Oh, oh. The argument comes from a positional parameter. */ 1492 goto do_positional; 1493 JUMP (*f, step1_jumps); 1494 1495 LABEL (precision): 1496 ++f; 1497 if (*f == L_('*')) 1498 { 1499 const UCHAR_T *tmp; /* Temporary value. */ 1500 1501 tmp = ++f; 1502 if (ISDIGIT (*tmp) && read_int (&tmp) > 0 && *tmp == L_('$')) 1503 /* The precision comes from a positional parameter. */ 1504 goto do_positional; 1505 1506 prec = va_arg (ap, int); 1507 1508 /* If the precision is negative the precision is omitted. */ 1509 if (prec < 0) 1510 prec = -1; 1511 } 1512 else if (ISDIGIT (*f)) 1513 prec = read_int (&f); 1514 else 1515 prec = 0; 1516 if (prec > width 1517 && prec + 32 > (int)(sizeof (work_buffer) / sizeof (work_buffer[0]))) 1518 { 1519 if (prec < (int) (32768 / sizeof (CHAR_T))) 1520 workend = alloca (prec + 32) + (prec + 32); 1521 else 1522 { 1523 workstart = (CHAR_T *) malloc ((prec + 32) * sizeof (CHAR_T)); 1524 if (workstart == NULL) 1525 { 1526 done = -1; 1527 goto all_done; 1528 } 1529 workend = workstart + (prec + 32); 1530 } 1531 } 1532 JUMP (*f, step2_jumps); 1533 1534 /* Process 'h' modifier. There might another 'h' following. */ 1535 LABEL (mod_half): 1536 is_short = 1; 1537 JUMP (*++f, step3a_jumps); 1538 1539 /* Process 'hh' modifier. */ 1540 LABEL (mod_halfhalf): 1541 is_short = 0; 1542 is_char = 1; 1543 JUMP (*++f, step4_jumps); 1544 1545 /* Process 'l' modifier. There might another 'l' following. */ 1546 LABEL (mod_long): 1547 is_long = 1; 1548 JUMP (*++f, step3b_jumps); 1549 1550 /* Process 'L', 'q', or 'll' modifier. No other modifier is 1551 allowed to follow. */ 1552 LABEL (mod_longlong): 1553 is_long_double = 1; 1554 is_long = 1; 1555 JUMP (*++f, step4_jumps); 1556 1557 LABEL (mod_size_t): 1558 is_long_double = sizeof (size_t) > sizeof (unsigned long int); 1559 is_long = sizeof (size_t) > sizeof (unsigned int); 1560 JUMP (*++f, step4_jumps); 1561 1562 LABEL (mod_ptrdiff_t): 1563 is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int); 1564 is_long = sizeof (ptrdiff_t) > sizeof (unsigned int); 1565 JUMP (*++f, step4_jumps); 1566 1567 LABEL (mod_intmax_t): 1568 is_long_double = sizeof (intmax_t) > sizeof (unsigned long int); 1569 is_long = sizeof (intmax_t) > sizeof (unsigned int); 1570 JUMP (*++f, step4_jumps); 1571 1572 /* Process current format. */ 1573 while (1) 1574 { 1575 process_arg (((struct printf_spec *) NULL)); 1576 process_string_arg (((struct printf_spec *) NULL)); 1577 1578 LABEL (form_unknown): 1579 if (spec == L_('\0')) 1580 { 1581 /* The format string ended before the specifier is complete. */ 1582 done = -1; 1583 goto all_done; 1584 } 1585 1586 /* If we are in the fast loop force entering the complicated 1587 one. */ 1588 goto do_positional; 1589 } 1590 1591 /* The format is correctly handled. */ 1592 ++nspecs_done; 1593 1594 if (__builtin_expect (workstart != NULL, 0)) 1595 free (workstart); 1596 workstart = NULL; 1597 1598 /* Look for next format specifier. */ 1599 #ifdef COMPILE_WPRINTF 1600 f = find_spec ((end_of_spec = ++f)); 1601 #else 1602 f = find_spec ((end_of_spec = ++f), &mbstate); 1603 #endif 1604 1605 /* Write the following constant string. */ 1606 outstring (end_of_spec, f - end_of_spec); 1607 } 1608 while (*f != L_('\0')); 1609 1610 /* Unlock stream and return. */ 1611 goto all_done; 1612 1613 /* Here starts the more complex loop to handle positional parameters. */ 1614 do_positional: 1615 { 1616 /* Array with information about the needed arguments. This has to 1617 be dynamically extensible. */ 1618 size_t nspecs = 0; 1619 size_t nspecs_max = 32; /* A more or less arbitrary start value. */ 1620 struct printf_spec *specs 1621 = alloca (nspecs_max * sizeof (struct printf_spec)); 1622 1623 /* The number of arguments the format string requests. This will 1624 determine the size of the array needed to store the argument 1625 attributes. */ 1626 size_t nargs = 0; 1627 int *args_type; 1628 union printf_arg *args_value = NULL; 1629 1630 /* Positional parameters refer to arguments directly. This could 1631 also determine the maximum number of arguments. Track the 1632 maximum number. */ 1633 size_t max_ref_arg = 0; 1634 1635 /* Just a counter. */ 1636 size_t cnt; 1637 1638 1639 if (grouping == (const char *) -1) 1640 { 1641 #ifdef COMPILE_WPRINTF 1642 thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC, 1643 _NL_NUMERIC_THOUSANDS_SEP_WC); 1644 #else 1645 thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); 1646 #endif 1647 1648 grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); 1649 if (*grouping == '\0' || *grouping == CHAR_MAX) 1650 grouping = NULL; 1651 } 1652 1653 for (f = lead_str_end; *f != L_('\0'); f = specs[nspecs++].next_fmt) 1654 { 1655 if (nspecs >= nspecs_max) 1656 { 1657 /* Extend the array of format specifiers. */ 1658 struct printf_spec *old = specs; 1659 1660 nspecs_max *= 2; 1661 specs = alloca (nspecs_max * sizeof (struct printf_spec)); 1662 1663 if (specs == &old[nspecs]) 1664 /* Stack grows up, OLD was the last thing allocated; 1665 extend it. */ 1666 nspecs_max += nspecs_max / 2; 1667 else 1668 { 1669 /* Copy the old array's elements to the new space. */ 1670 memcpy (specs, old, nspecs * sizeof (struct printf_spec)); 1671 if (old == &specs[nspecs]) 1672 /* Stack grows down, OLD was just below the new 1673 SPECS. We can use that space when the new space 1674 runs out. */ 1675 nspecs_max += nspecs_max / 2; 1676 } 1677 } 1678 1679 /* Parse the format specifier. */ 1680 #ifdef COMPILE_WPRINTF 1681 nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg); 1682 #else 1683 nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg, 1684 &mbstate); 1685 #endif 1686 } 1687 1688 /* Determine the number of arguments the format string consumes. */ 1689 nargs = MAX (nargs, max_ref_arg); 1690 1691 /* Allocate memory for the argument descriptions. */ 1692 args_type = alloca (nargs * sizeof (int)); 1693 memset (args_type, 0, nargs * sizeof (int)); 1694 args_value = alloca (nargs * sizeof (union printf_arg)); 1695 1696 /* XXX Could do sanity check here: If any element in ARGS_TYPE is 1697 still zero after this loop, format is invalid. For now we 1698 simply use 0 as the value. */ 1699 1700 /* Fill in the types of all the arguments. */ 1701 for (cnt = 0; cnt < nspecs; ++cnt) 1702 { 1703 /* If the width is determined by an argument this is an int. */ 1704 if (specs[cnt].width_arg != -1) 1705 args_type[specs[cnt].width_arg] = PA_INT; 1706 1707 /* If the precision is determined by an argument this is an int. */ 1708 if (specs[cnt].prec_arg != -1) 1709 args_type[specs[cnt].prec_arg] = PA_INT; 1710 1711 switch (specs[cnt].ndata_args) 1712 { 1713 case 0: /* No arguments. */ 1714 break; 1715 case 1: /* One argument; we already have the type. */ 1716 args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type; 1717 break; 1718 default: 1719 /* We have more than one argument for this format spec. 1720 We must call the arginfo function again to determine 1721 all the types. */ 1722 (void) (*__printf_arginfo_table[specs[cnt].info.spec]) 1723 (&specs[cnt].info, 1724 specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]); 1725 break; 1726 } 1727 } 1728 1729 /* Now we know all the types and the order. Fill in the argument 1730 values. */ 1731 for (cnt = 0; cnt < nargs; ++cnt) 1732 switch (args_type[cnt]) 1733 { 1734 #define T(tag, mem, type) \ 1735 case tag: \ 1736 args_value[cnt].mem = va_arg (ap_save, type); \ 1737 break 1738 1739 T (PA_CHAR, pa_char, int); /* Promoted. */ 1740 T (PA_WCHAR, pa_wchar, wint_t); 1741 T (PA_INT|PA_FLAG_SHORT, pa_short_int, int); /* Promoted. */ 1742 T (PA_INT, pa_int, int); 1743 T (PA_INT|PA_FLAG_LONG, pa_long_int, long int); 1744 T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int); 1745 T (PA_FLOAT, pa_float, double); /* Promoted. */ 1746 T (PA_DOUBLE, pa_double, double); 1747 T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double); 1748 T (PA_STRING, pa_string, const char *); 1749 T (PA_WSTRING, pa_wstring, const wchar_t *); 1750 T (PA_POINTER, pa_pointer, void *); 1751 #undef T 1752 default: 1753 if ((args_type[cnt] & PA_FLAG_PTR) != 0) 1754 args_value[cnt].pa_pointer = va_arg (ap_save, void *); 1755 else 1756 args_value[cnt].pa_long_double = 0.0; 1757 break; 1758 } 1759 1760 /* Now walk through all format specifiers and process them. */ 1761 for (; (size_t) nspecs_done < nspecs; ++nspecs_done) 1762 { 1763 #undef REF 1764 #if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED 1765 # define REF(Name) &&do2_##Name - &&do_form_unknown 1766 #else 1767 # define REF(Name) &&do2_##Name 1768 #endif 1769 #undef LABEL 1770 #define LABEL(Name) do2_##Name 1771 STEP4_TABLE; 1772 1773 int is_negative; 1774 union 1775 { 1776 unsigned long long int longlong; 1777 unsigned long int word; 1778 } number; 1779 int base; 1780 union printf_arg the_arg; 1781 CHAR_T *string; /* Pointer to argument string. */ 1782 1783 /* Fill variables from values in struct. */ 1784 int alt = specs[nspecs_done].info.alt; 1785 int space = specs[nspecs_done].info.space; 1786 int left = specs[nspecs_done].info.left; 1787 int showsign = specs[nspecs_done].info.showsign; 1788 int group = specs[nspecs_done].info.group; 1789 int is_long_double = specs[nspecs_done].info.is_long_double; 1790 int is_short = specs[nspecs_done].info.is_short; 1791 int is_char = specs[nspecs_done].info.is_char; 1792 int is_long = specs[nspecs_done].info.is_long; 1793 int width = specs[nspecs_done].info.width; 1794 int prec = specs[nspecs_done].info.prec; 1795 int use_outdigits = specs[nspecs_done].info.i18n; 1796 char pad = specs[nspecs_done].info.pad; 1797 CHAR_T spec = specs[nspecs_done].info.spec; 1798 CHAR_T *workstart = NULL; 1799 1800 /* Fill in last information. */ 1801 if (specs[nspecs_done].width_arg != -1) 1802 { 1803 /* Extract the field width from an argument. */ 1804 specs[nspecs_done].info.width = 1805 args_value[specs[nspecs_done].width_arg].pa_int; 1806 1807 if (specs[nspecs_done].info.width < 0) 1808 /* If the width value is negative left justification is 1809 selected and the value is taken as being positive. */ 1810 { 1811 specs[nspecs_done].info.width *= -1; 1812 left = specs[nspecs_done].info.left = 1; 1813 } 1814 width = specs[nspecs_done].info.width; 1815 } 1816 1817 if (specs[nspecs_done].prec_arg != -1) 1818 { 1819 /* Extract the precision from an argument. */ 1820 specs[nspecs_done].info.prec = 1821 args_value[specs[nspecs_done].prec_arg].pa_int; 1822 1823 if (specs[nspecs_done].info.prec < 0) 1824 /* If the precision is negative the precision is 1825 omitted. */ 1826 specs[nspecs_done].info.prec = -1; 1827 1828 prec = specs[nspecs_done].info.prec; 1829 } 1830 1831 /* Maybe the buffer is too small. */ 1832 if (MAX (prec, width) + 32 > (int) (sizeof (work_buffer) 1833 / sizeof (CHAR_T))) 1834 { 1835 if (MAX (prec, width) < (int) (32768 / sizeof (CHAR_T))) 1836 workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32) 1837 * sizeof (CHAR_T)) 1838 + (MAX (prec, width) + 32)); 1839 else 1840 { 1841 workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32) 1842 * sizeof (CHAR_T)); 1843 workend = workstart + (MAX (prec, width) + 32); 1844 } 1845 } 1846 1847 /* Process format specifiers. */ 1848 while (1) 1849 { 1850 JUMP (spec, step4_jumps); 1851 1852 process_arg ((&specs[nspecs_done])); 1853 process_string_arg ((&specs[nspecs_done])); 1854 1855 LABEL (form_unknown): 1856 { 1857 extern printf_function **__printf_function_table; 1858 int function_done; 1859 printf_function *function; 1860 unsigned int i; 1861 const void **ptr; 1862 1863 function = 1864 (__printf_function_table == NULL ? NULL : 1865 __printf_function_table[specs[nspecs_done].info.spec]); 1866 1867 if (function == NULL) 1868 function = &printf_unknown; 1869 1870 ptr = alloca (specs[nspecs_done].ndata_args 1871 * sizeof (const void *)); 1872 1873 /* Fill in an array of pointers to the argument values. */ 1874 for (i = 0; i < specs[nspecs_done].ndata_args; ++i) 1875 ptr[i] = &args_value[specs[nspecs_done].data_arg + i]; 1876 1877 /* Call the function. */ 1878 function_done = (*function) (s, &specs[nspecs_done].info, ptr); 1879 1880 /* If an error occurred we don't have information about # 1881 of chars. */ 1882 if (function_done < 0) 1883 { 1884 done = -1; 1885 goto all_done; 1886 } 1887 1888 done += function_done; 1889 } 1890 break; 1891 } 1892 1893 if (__builtin_expect (workstart != NULL, 0)) 1894 free (workstart); 1895 workstart = NULL; 1896 1897 /* Write the following constant string. */ 1898 outstring (specs[nspecs_done].end_of_fmt, 1899 specs[nspecs_done].next_fmt 1900 - specs[nspecs_done].end_of_fmt); 1901 } 1902 } 1903 1904 all_done: 1905 if (__builtin_expect (workstart != NULL, 0)) 1906 free (workstart); 1907 /* Unlock the stream. */ 1908 #ifdef USE_IN_LIBIO 1909 _IO_funlockfile (s); 1910 #else 1911 __funlockfile (s); 1912 #endif 1913 __libc_cleanup_region_end (0); 1914 1915 return done; 1916 } 1917 1918 /* Handle an unknown format specifier. This prints out a canonicalized 1919 representation of the format spec itself. */ 1920 static int 1921 printf_unknown (FILE *s, const struct printf_info *info, 1922 const void *const *args) 1923 1924 { 1925 int done = 0; 1926 CHAR_T work_buffer[MAX (info->width, info->spec) + 32]; 1927 CHAR_T *const workend 1928 = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)]; 1929 register CHAR_T *w; 1930 1931 outchar (L_('%')); 1932 1933 if (info->alt) 1934 outchar (L_('#')); 1935 if (info->group) 1936 outchar (L_('\'')); 1937 if (info->showsign) 1938 outchar (L_('+')); 1939 else if (info->space) 1940 outchar (L_(' ')); 1941 if (info->left) 1942 outchar (L_('-')); 1943 if (info->pad == L_('0')) 1944 outchar (L_('0')); 1945 if (info->i18n) 1946 outchar (L_('I')); 1947 1948 if (info->width != 0) 1949 { 1950 w = _itoa_word (info->width, workend, 10, 0); 1951 while (w < workend) 1952 outchar (*w++); 1953 } 1954 1955 if (info->prec != -1) 1956 { 1957 outchar (L_('.')); 1958 w = _itoa_word (info->prec, workend, 10, 0); 1959 while (w < workend) 1960 outchar (*w++); 1961 } 1962 1963 if (info->spec != L_('\0')) 1964 outchar (info->spec); 1965 1966 all_done: 1967 return done; 1968 } 1969 1970 /* Group the digits according to the grouping rules of the current locale. 1971 The interpretation of GROUPING is as in `struct lconv' from <locale.h>. */ 1972 static CHAR_T * 1973 internal_function 1974 group_number (CHAR_T *w, CHAR_T *rear_ptr, const char *grouping, 1975 #ifdef COMPILE_WPRINTF 1976 wchar_t thousands_sep 1977 #else 1978 const char *thousands_sep 1979 #endif 1980 ) 1981 { 1982 int len; 1983 CHAR_T *src, *s; 1984 #ifndef COMPILE_WPRINTF 1985 int tlen = strlen (thousands_sep); 1986 #endif 1987 1988 /* We treat all negative values like CHAR_MAX. */ 1989 1990 if (*grouping == CHAR_MAX || *grouping <= 0) 1991 /* No grouping should be done. */ 1992 return w; 1993 1994 len = *grouping; 1995 1996 /* Copy existing string so that nothing gets overwritten. */ 1997 src = (CHAR_T *) alloca ((rear_ptr - w) * sizeof (CHAR_T)); 1998 s = (CHAR_T *) __mempcpy (src, w, 1999 (rear_ptr - w) * sizeof (CHAR_T)); 2000 w = rear_ptr; 2001 2002 /* Process all characters in the string. */ 2003 while (s > src) 2004 { 2005 *--w = *--s; 2006 2007 if (--len == 0 && s > src) 2008 { 2009 /* A new group begins. */ 2010 #ifdef COMPILE_WPRINTF 2011 *--w = thousands_sep; 2012 #else 2013 int cnt = tlen; 2014 do 2015 *--w = thousands_sep[--cnt]; 2016 while (cnt > 0); 2017 #endif 2018 2019 len = *grouping++; 2020 if (*grouping == '\0') 2021 /* The previous grouping repeats ad infinitum. */ 2022 --grouping; 2023 else if (*grouping == CHAR_MAX 2024 #if CHAR_MIN < 0 2025 || *grouping < 0 2026 #endif 2027 ) 2028 { 2029 /* No further grouping to be done. 2030 Copy the rest of the number. */ 2031 do 2032 *--w = *--s; 2033 while (s > src); 2034 break; 2035 } 2036 } 2037 } 2038 return w; 2039 } 2040 2041 #ifdef USE_IN_LIBIO 2042 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer. */ 2043 struct helper_file 2044 { 2045 struct _IO_FILE_plus _f; 2046 #ifdef COMPILE_WPRINTF 2047 struct _IO_wide_data _wide_data; 2048 #endif 2049 _IO_FILE *_put_stream; 2050 #ifdef _IO_MTSAFE_IO 2051 _IO_lock_t lock; 2052 #endif 2053 }; 2054 2055 static int 2056 _IO_helper_overflow (_IO_FILE *s, int c) 2057 { 2058 _IO_FILE *target = ((struct helper_file*) s)->_put_stream; 2059 #ifdef COMPILE_WPRINTF 2060 int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base; 2061 if (used) 2062 { 2063 _IO_size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base, 2064 used); 2065 s->_wide_data->_IO_write_ptr -= written; 2066 } 2067 #else 2068 int used = s->_IO_write_ptr - s->_IO_write_base; 2069 if (used) 2070 { 2071 _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used); 2072 s->_IO_write_ptr -= written; 2073 } 2074 #endif 2075 return PUTC (c, s); 2076 } 2077 2078 #ifdef COMPILE_WPRINTF 2079 static const struct _IO_jump_t _IO_helper_jumps = 2080 { 2081 JUMP_INIT_DUMMY, 2082 JUMP_INIT (finish, INTUSE(_IO_wdefault_finish)), 2083 JUMP_INIT (overflow, _IO_helper_overflow), 2084 JUMP_INIT (underflow, _IO_default_underflow), 2085 JUMP_INIT (uflow, INTUSE(_IO_default_uflow)), 2086 JUMP_INIT (pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)), 2087 JUMP_INIT (xsputn, INTUSE(_IO_wdefault_xsputn)), 2088 JUMP_INIT (xsgetn, INTUSE(_IO_wdefault_xsgetn)), 2089 JUMP_INIT (seekoff, _IO_default_seekoff), 2090 JUMP_INIT (seekpos, _IO_default_seekpos), 2091 JUMP_INIT (setbuf, _IO_default_setbuf), 2092 JUMP_INIT (sync, _IO_default_sync), 2093 JUMP_INIT (doallocate, INTUSE(_IO_wdefault_doallocate)), 2094 JUMP_INIT (read, _IO_default_read), 2095 JUMP_INIT (write, _IO_default_write), 2096 JUMP_INIT (seek, _IO_default_seek), 2097 JUMP_INIT (close, _IO_default_close), 2098 JUMP_INIT (stat, _IO_default_stat) 2099 }; 2100 #else 2101 static const struct _IO_jump_t _IO_helper_jumps = 2102 { 2103 JUMP_INIT_DUMMY, 2104 JUMP_INIT (finish, INTUSE(_IO_default_finish)), 2105 JUMP_INIT (overflow, _IO_helper_overflow), 2106 JUMP_INIT (underflow, _IO_default_underflow), 2107 JUMP_INIT (uflow, INTUSE(_IO_default_uflow)), 2108 JUMP_INIT (pbackfail, INTUSE(_IO_default_pbackfail)), 2109 JUMP_INIT (xsputn, INTUSE(_IO_default_xsputn)), 2110 JUMP_INIT (xsgetn, INTUSE(_IO_default_xsgetn)), 2111 JUMP_INIT (seekoff, _IO_default_seekoff), 2112 JUMP_INIT (seekpos, _IO_default_seekpos), 2113 JUMP_INIT (setbuf, _IO_default_setbuf), 2114 JUMP_INIT (sync, _IO_default_sync), 2115 JUMP_INIT (doallocate, INTUSE(_IO_default_doallocate)), 2116 JUMP_INIT (read, _IO_default_read), 2117 JUMP_INIT (write, _IO_default_write), 2118 JUMP_INIT (seek, _IO_default_seek), 2119 JUMP_INIT (close, _IO_default_close), 2120 JUMP_INIT (stat, _IO_default_stat) 2121 }; 2122 #endif 2123 2124 static int 2125 internal_function 2126 buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format, 2127 _IO_va_list args) 2128 { 2129 CHAR_T buf[_IO_BUFSIZ]; 2130 struct helper_file helper; 2131 register _IO_FILE *hp = (_IO_FILE *) &helper._f; 2132 int result, to_flush; 2133 2134 /* Orient the stream. */ 2135 #ifdef ORIENT 2136 ORIENT; 2137 #endif 2138 2139 /* Initialize helper. */ 2140 helper._put_stream = s; 2141 #ifdef COMPILE_WPRINTF 2142 hp->_wide_data = &helper._wide_data; 2143 _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T)); 2144 hp->_mode = 1; 2145 #else 2146 _IO_setp (hp, buf, buf + sizeof buf); 2147 hp->_mode = -1; 2148 #endif 2149 hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK; 2150 #if _IO_JUMPS_OFFSET 2151 hp->_vtable_offset = 0; 2152 #endif 2153 #ifdef _IO_MTSAFE_IO 2154 hp->_lock = NULL; 2155 #endif 2156 _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps; 2157 2158 /* Now print to helper instead. */ 2159 #if defined USE_IN_LIBIO && !defined COMPILE_WPRINTF 2160 result = INTUSE(_IO_vfprintf) (hp, format, args); 2161 #else 2162 result = vfprintf (hp, format, args); 2163 #endif 2164 2165 /* Lock stream. */ 2166 __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s); 2167 _IO_flockfile (s); 2168 2169 /* Now flush anything from the helper to the S. */ 2170 #ifdef COMPILE_WPRINTF 2171 if ((to_flush = (hp->_wide_data->_IO_write_ptr 2172 - hp->_wide_data->_IO_write_base)) > 0) 2173 { 2174 if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush) 2175 != to_flush) 2176 result = -1; 2177 } 2178 #else 2179 if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0) 2180 { 2181 if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush) 2182 result = -1; 2183 } 2184 #endif 2185 2186 /* Unlock the stream. */ 2187 _IO_funlockfile (s); 2188 __libc_cleanup_region_end (0); 2189 2190 return result; 2191 } 2192 2193 #else /* !USE_IN_LIBIO */ 2194 2195 static int 2196 internal_function 2197 buffered_vfprintf (register FILE *s, const CHAR_T *format, va_list args) 2198 { 2199 char buf[BUFSIZ]; 2200 int result; 2201 2202 /* Orient the stream. */ 2203 #ifdef ORIENT 2204 ORIENT; 2205 #endif 2206 2207 s->__bufp = s->__buffer = buf; 2208 s->__bufsize = sizeof buf; 2209 s->__put_limit = s->__buffer + s->__bufsize; 2210 s->__get_limit = s->__buffer; 2211 2212 /* Now use buffer to print. */ 2213 result = vfprintf (s, format, args); 2214 2215 if (fflush (s) == EOF) 2216 result = -1; 2217 s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL; 2218 s->__bufsize = 0; 2219 2220 return result; 2221 } 2222 2223 /* Pads string with given number of a specified character. 2224 This code is taken from iopadn.c of the GNU I/O library. */ 2225 #define PADSIZE 16 2226 static const CHAR_T blanks[PADSIZE] = 2227 { L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), 2228 L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ') }; 2229 static const CHAR_T zeroes[PADSIZE] = 2230 { L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), 2231 L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0') }; 2232 2233 ssize_t 2234 #ifndef COMPILE_WPRINTF 2235 __printf_pad (FILE *s, char pad, size_t count) 2236 #else 2237 __wprintf_pad (FILE *s, wchar_t pad, size_t count) 2238 #endif 2239 { 2240 const CHAR_T *padptr; 2241 register size_t i; 2242 2243 padptr = pad == L_(' ') ? blanks : zeroes; 2244 2245 for (i = count; i >= PADSIZE; i -= PADSIZE) 2246 if (PUT (s, padptr, PADSIZE) != PADSIZE) 2247 return -1; 2248 if (i > 0) 2249 if (PUT (s, padptr, i) != i) 2250 return -1; 2251 2252 return count; 2253 } 2254 #undef PADSIZE 2255 #endif /* USE_IN_LIBIO */ 2256 2257 #ifdef USE_IN_LIBIO 2258 # undef vfprintf 2259 # ifdef strong_alias 2260 /* This is for glibc. */ 2261 # ifdef COMPILE_WPRINTF 2262 strong_alias (_IO_vfwprintf, __vfwprintf); 2263 weak_alias (_IO_vfwprintf, vfwprintf); 2264 # else 2265 strong_alias (_IO_vfprintf, vfprintf); 2266 libc_hidden_def (vfprintf) 2267 INTDEF(_IO_vfprintf) 2268 # endif 2269 # else 2270 # if defined __ELF__ || defined __GNU_LIBRARY__ 2271 # include <gnu-stabs.h> 2272 # ifdef weak_alias 2273 # ifdef COMPILE_WPRINTF 2274 weak_alias (_IO_vfwprintf, vfwprintf); 2275 # else 2276 weak_alias (_IO_vfprintf, vfprintf); 2277 # endif 2278 # endif 2279 # endif 2280 # endif 2281 #endif 2282