1250661Sdavidcs/* __gmp_doscan -- formatted input internals. 2284982Sdavidcs 3250661Sdavidcs THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST 4250661Sdavidcs CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN 5250661Sdavidcs FUTURE GNU MP RELEASES. 6250661Sdavidcs 7250661SdavidcsCopyright 2001, 2002, 2003 Free Software Foundation, Inc. 8250661Sdavidcs 9250661SdavidcsThis file is part of the GNU MP Library. 10250661Sdavidcs 11250661SdavidcsThe GNU MP Library is free software; you can redistribute it and/or modify 12250661Sdavidcsit under the terms of the GNU Lesser General Public License as published by 13250661Sdavidcsthe Free Software Foundation; either version 3 of the License, or (at your 14250661Sdavidcsoption) any later version. 15250661Sdavidcs 16250661SdavidcsThe GNU MP Library is distributed in the hope that it will be useful, but 17250661SdavidcsWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18250661Sdavidcsor FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 19250661SdavidcsLicense for more details. 20250661Sdavidcs 21250661SdavidcsYou should have received a copy of the GNU Lesser General Public License 22250661Sdavidcsalong with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ 23250661Sdavidcs 24250661Sdavidcs#define _GNU_SOURCE /* for DECIMAL_POINT in langinfo.h */ 25250661Sdavidcs 26250661Sdavidcs#include "config.h" 27250661Sdavidcs 28250661Sdavidcs#if HAVE_STDARG 29250661Sdavidcs#include <stdarg.h> 30250661Sdavidcs#else 31250661Sdavidcs#include <varargs.h> 32250661Sdavidcs#endif 33250661Sdavidcs 34250661Sdavidcs#include <ctype.h> 35250661Sdavidcs#include <stddef.h> /* for ptrdiff_t */ 36250661Sdavidcs#include <stdio.h> 37250661Sdavidcs#include <stdlib.h> /* for strtol */ 38250661Sdavidcs#include <string.h> 39250661Sdavidcs 40250661Sdavidcs#if HAVE_LANGINFO_H 41250661Sdavidcs#include <langinfo.h> /* for nl_langinfo */ 42250661Sdavidcs#endif 43250661Sdavidcs 44250661Sdavidcs#if HAVE_LOCALE_H 45250661Sdavidcs#include <locale.h> /* for localeconv */ 46250661Sdavidcs#endif 47250661Sdavidcs 48250661Sdavidcs#if HAVE_INTTYPES_H 49250661Sdavidcs# include <inttypes.h> /* for intmax_t */ 50250661Sdavidcs#else 51250661Sdavidcs# if HAVE_STDINT_H 52250661Sdavidcs# include <stdint.h> 53250661Sdavidcs# endif 54250661Sdavidcs#endif 55250661Sdavidcs 56250661Sdavidcs#if HAVE_SYS_TYPES_H 57250661Sdavidcs#include <sys/types.h> /* for quad_t */ 58250661Sdavidcs#endif 59250661Sdavidcs 60250661Sdavidcs#include "gmp.h" 61250661Sdavidcs#include "gmp-impl.h" 62250661Sdavidcs 63250661Sdavidcs 64250661Sdavidcs/* Change this to "#define TRACE(x) x" for some traces. */ 65250661Sdavidcs#define TRACE(x) 66250661Sdavidcs 67250661Sdavidcs 68250661Sdavidcs/* General: 69250661Sdavidcs 70250661Sdavidcs It's necessary to parse up the format string to recognise the GMP 71250661Sdavidcs extra types F, Q and Z. Other types and conversions are passed 72250661Sdavidcs across to the standard sscanf or fscanf via funs->scan, for ease of 73250661Sdavidcs implementation. This is essential in the case of something like glibc 74250661Sdavidcs %p where the pointer format isn't actually documented. 75250661Sdavidcs 76250661Sdavidcs Because funs->scan doesn't get the whole input it can't put the right 77250661Sdavidcs values in for %n, so that's handled in __gmp_doscan. Neither sscanf 78250661Sdavidcs nor fscanf directly indicate how many characters were read, so an 79250661Sdavidcs extra %n is appended to each run for that. For fscanf this merely 80250661Sdavidcs supports our %n output, but for sscanf it lets funs->step move us 81250661Sdavidcs along the input string. 82250661Sdavidcs 83250661Sdavidcs Whitespace and literal matches in the format string, including %%, 84250661Sdavidcs are handled directly within __gmp_doscan. This is reasonably 85250661Sdavidcs efficient, and avoids some suspicious behaviour observed in various 86250661Sdavidcs system libc's. GLIBC 2.2.4 for instance returns 0 on 87250661Sdavidcs 88250661Sdavidcs sscanf(" ", " x") 89250661Sdavidcs or 90250661Sdavidcs sscanf(" ", " x%d",&n) 91250661Sdavidcs 92250661Sdavidcs whereas we think they should return EOF, since end-of-string is 93250661Sdavidcs reached when a match of "x" is required. 94250661Sdavidcs 95250661Sdavidcs For standard % conversions, funs->scan is called once for each 96250661Sdavidcs conversion. If we had vfscanf and vsscanf and could rely on their 97250661Sdavidcs fixed text matching behaviour then we could call them with multiple 98250661Sdavidcs consecutive standard conversions. But plain fscanf and sscanf work 99250661Sdavidcs fine, and parsing one field at a time shouldn't be too much of a 100250661Sdavidcs slowdown. 101250661Sdavidcs 102250661Sdavidcs gmpscan: 103250661Sdavidcs 104250661Sdavidcs gmpscan reads a gmp type. It's only used from one place, but is a 105250661Sdavidcs separate subroutine to avoid a big chunk of complicated code in the 106250661Sdavidcs middle of __gmp_doscan. Within gmpscan a couple of loopbacks make it 107250661Sdavidcs possible to share code for parsing integers, rationals and floats. 108250661Sdavidcs 109250661Sdavidcs In gmpscan normally one char of lookahead is maintained, but when width 110250661Sdavidcs is reached that stops, on the principle that an fgetc/ungetc of a char 111250661Sdavidcs past where we're told to stop would be undesirable. "chars" is how many 112250661Sdavidcs characters have been read so far, including the current c. When 113250661Sdavidcs chars==width and another character is desired then a jump is done to the 114250661Sdavidcs "convert" stage. c is invalid and mustn't be unget'ed in this case; 115250661Sdavidcs chars is set to width+1 to indicate that. 116250661Sdavidcs 117250661Sdavidcs gmpscan normally returns the number of characters read. -1 means an 118250661Sdavidcs invalid field, -2 means EOF reached before any matching characters 119250661Sdavidcs were read. 120250661Sdavidcs 121250661Sdavidcs For hex floats, the mantissa part is passed to mpf_set_str, then the 122250661Sdavidcs exponent is applied with mpf_mul_exp or mpf_div_2exp. This is easier 123250661Sdavidcs than teaching mpf_set_str about an exponent factor (ie. 2) differing 124250661Sdavidcs from the mantissa radix point factor (ie. 16). mpf_mul_exp and 125250661Sdavidcs mpf_div_2exp will preserve the application requested precision, so 126250661Sdavidcs nothing in that respect is lost by making this a two-step process. 127250661Sdavidcs 128250661Sdavidcs Matching and errors: 129250661Sdavidcs 130250661Sdavidcs C99 7.19.6.2 paras 9 and 10 say an input item is read as the longest 131250661Sdavidcs string which is a match for the appropriate type, or a prefix of a 132250661Sdavidcs match. With that done, if it's only a prefix then the result is a 133250661Sdavidcs matching failure, ie. invalid input. 134250661Sdavidcs 135250661Sdavidcs This rule seems fairly clear, but doesn't seem to be universally 136250661Sdavidcs applied in system C libraries. Even GLIBC doesn't seem to get it 137250661Sdavidcs right, insofar as it seems to accept some apparently invalid forms. 138250661Sdavidcs Eg. glibc 2.3.1 accepts "0x" for a "%i", where a reading of the 139250661Sdavidcs standard would suggest a non-empty sequence of digits should be 140250661Sdavidcs required after an "0x". 141250661Sdavidcs 142250661Sdavidcs A footnote to 7.19.6.2 para 17 notes how this input item reading can 143250661Sdavidcs mean inputs acceptable to strtol are not acceptable to fscanf. We 144 think this confirms our reading of "0x" as invalid. 145 146 Clearly gmp_sscanf could backtrack to a longest input which was a 147 valid match for a given item, but this is not done, since C99 says 148 sscanf is identical to fscanf, so we make gmp_sscanf identical to 149 gmp_fscanf. 150 151 Types: 152 153 C99 says "ll" is for long long, and "L" is for long double floats. 154 Unfortunately in GMP 4.1.1 we documented the two as equivalent. This 155 doesn't affect us directly, since both are passed through to plain 156 scanf. It seems wisest not to try to enforce the C99 rule. This is 157 consistent with what we said before, though whether it actually 158 worked was always up to the C library. 159 160 Alternatives: 161 162 Consideration was given to using separate code for gmp_fscanf and 163 gmp_sscanf. The sscanf case could zip across a string doing literal 164 matches or recognising digits in gmpscan, rather than making a 165 function call fun->get per character. The fscanf could use getc 166 rather than fgetc too, which might help those systems where getc is a 167 macro or otherwise inlined. But none of this scanning and converting 168 will be particularly fast, so the two are done together to keep it a 169 little simpler for now. 170 171 Various multibyte string issues are not addressed, for a start C99 172 scanf says the format string is multibyte. Since we pass %c, %s and 173 %[ to the system scanf, they might do multibyte reads already, but 174 it's another matter whether or not that can be used, since our digit 175 and whitespace parsing is only unibyte. The plan is to quietly 176 ignore multibyte locales for now. This is not as bad as it sounds, 177 since GMP is presumably used mostly on numbers, which can be 178 perfectly adequately treated in plain ASCII. 179 180*/ 181 182 183struct gmp_doscan_params_t { 184 int base; 185 int ignore; 186 char type; 187 int width; 188}; 189 190 191#define GET(c) \ 192 do { \ 193 ASSERT (chars <= width); \ 194 chars++; \ 195 if (chars > width) \ 196 goto convert; \ 197 (c) = (*funs->get) (data); \ 198 } while (0) 199 200/* store into "s", extending if necessary */ 201#define STORE(c) \ 202 do { \ 203 ASSERT (s_upto <= s_alloc); \ 204 if (s_upto >= s_alloc) \ 205 { \ 206 size_t s_alloc_new = s_alloc + S_ALLOC_STEP; \ 207 s = __GMP_REALLOCATE_FUNC_TYPE (s, s_alloc, s_alloc_new, char); \ 208 s_alloc = s_alloc_new; \ 209 } \ 210 s[s_upto++] = c; \ 211 } while (0) 212 213#define S_ALLOC_STEP 512 214 215static int 216gmpscan (const struct gmp_doscan_funs_t *funs, void *data, 217 const struct gmp_doscan_params_t *p, void *dst) 218{ 219 int chars, c, base, first, width, seen_point, seen_digit, hexfloat; 220 size_t s_upto, s_alloc, hexexp; 221 char *s; 222 int invalid = 0; 223 224 TRACE (printf ("gmpscan\n")); 225 226 ASSERT (p->type == 'F' || p->type == 'Q' || p->type == 'Z'); 227 228 c = (*funs->get) (data); 229 if (c == EOF) 230 return -2; 231 232 chars = 1; 233 first = 1; 234 seen_point = 0; 235 width = (p->width == 0 ? INT_MAX-1 : p->width); 236 base = p->base; 237 s_alloc = S_ALLOC_STEP; 238 s = __GMP_ALLOCATE_FUNC_TYPE (s_alloc, char); 239 s_upto = 0; 240 hexfloat = 0; 241 hexexp = 0; 242 243 another: 244 seen_digit = 0; 245 if (c == '-') 246 { 247 STORE (c); 248 goto get_for_sign; 249 } 250 else if (c == '+') 251 { 252 /* don't store '+', it's not accepted by mpz_set_str etc */ 253 get_for_sign: 254 GET (c); 255 } 256 257 if (base == 0) 258 { 259 base = 10; /* decimal if no base indicator */ 260 if (c == '0') 261 { 262 seen_digit = 1; /* 0 alone is a valid number */ 263 if (p->type != 'F') 264 base = 8; /* leading 0 is octal, for non-floats */ 265 STORE (c); 266 GET (c); 267 if (c == 'x' || c == 'X') 268 { 269 base = 16; 270 seen_digit = 0; /* must have digits after an 0x */ 271 if (p->type == 'F') /* don't pass 'x' to mpf_set_str_point */ 272 hexfloat = 1; 273 else 274 STORE (c); 275 GET (c); 276 } 277 } 278 } 279 280 digits: 281 for (;;) 282 { 283 if (base == 16) 284 { 285 if (! isxdigit (c)) 286 break; 287 } 288 else 289 { 290 if (! isdigit (c)) 291 break; 292 if (base == 8 && (c == '8' || c == '9')) 293 break; 294 } 295 296 seen_digit = 1; 297 STORE (c); 298 GET (c); 299 } 300 301 if (first) 302 { 303 /* decimal point */ 304 if (p->type == 'F' && ! seen_point) 305 { 306 /* For a multi-character decimal point, if the first character is 307 present then all of it must be, otherwise the input is 308 considered invalid. */ 309 const char *point = GMP_DECIMAL_POINT; 310 int pc = (unsigned char) *point++; 311 if (c == pc) 312 { 313 for (;;) 314 { 315 STORE (c); 316 GET (c); 317 pc = (unsigned char) *point++; 318 if (pc == '\0') 319 break; 320 if (c != pc) 321 goto set_invalid; 322 } 323 seen_point = 1; 324 goto digits; 325 } 326 } 327 328 /* exponent */ 329 if (p->type == 'F') 330 { 331 if (hexfloat && (c == 'p' || c == 'P')) 332 { 333 hexexp = s_upto; /* exponent location */ 334 base = 10; /* exponent in decimal */ 335 goto exponent; 336 } 337 else if (! hexfloat && (c == 'e' || c == 'E')) 338 { 339 exponent: 340 /* must have at least one digit in the mantissa, just an exponent 341 is not good enough */ 342 if (! seen_digit) 343 goto set_invalid; 344 345 do_second: 346 first = 0; 347 STORE (c); 348 GET (c); 349 goto another; 350 } 351 } 352 353 /* denominator */ 354 if (p->type == 'Q' && c == '/') 355 { 356 /* must have at least one digit in the numerator */ 357 if (! seen_digit) 358 goto set_invalid; 359 360 /* now look for at least one digit in the denominator */ 361 seen_digit = 0; 362 363 /* allow the base to be redetermined for "%i" */ 364 base = p->base; 365 goto do_second; 366 } 367 } 368 369 convert: 370 if (! seen_digit) 371 { 372 set_invalid: 373 invalid = 1; 374 goto done; 375 } 376 377 if (! p->ignore) 378 { 379 STORE ('\0'); 380 TRACE (printf (" convert \"%s\"\n", s)); 381 382 /* We ought to have parsed out a valid string above, so just test 383 mpz_set_str etc with an ASSERT. */ 384 switch (p->type) { 385 case 'F': 386 { 387 mpf_ptr f = (mpf_ptr) dst; 388 if (hexexp != 0) 389 s[hexexp] = '\0'; 390 ASSERT_NOCARRY (mpf_set_str (f, s, hexfloat ? 16 : 10)); 391 if (hexexp != 0) 392 { 393 char *dummy; 394 long exp; 395 exp = strtol (s + hexexp + 1, &dummy, 10); 396 if (exp >= 0) 397 mpf_mul_2exp (f, f, (unsigned long) exp); 398 else 399 mpf_div_2exp (f, f, - (unsigned long) exp); 400 } 401 } 402 break; 403 case 'Q': 404 ASSERT_NOCARRY (mpq_set_str ((mpq_ptr) dst, s, p->base)); 405 break; 406 case 'Z': 407 ASSERT_NOCARRY (mpz_set_str ((mpz_ptr) dst, s, p->base)); 408 break; 409 default: 410 ASSERT (0); 411 /*FALLTHRU*/ 412 break; 413 } 414 } 415 416 done: 417 ASSERT (chars <= width+1); 418 if (chars != width+1) 419 { 420 (*funs->unget) (c, data); 421 TRACE (printf (" ungetc %d, to give %d chars\n", c, chars-1)); 422 } 423 chars--; 424 425 (*__gmp_free_func) (s, s_alloc); 426 427 if (invalid) 428 { 429 TRACE (printf (" invalid\n")); 430 return -1; 431 } 432 433 TRACE (printf (" return %d chars (cf width %d)\n", chars, width)); 434 return chars; 435} 436 437 438/* Read and discard whitespace, if any. Return number of chars skipped. 439 Whitespace skipping never provokes the EOF return from __gmp_doscan, so 440 it's not necessary to watch for EOF from funs->get, */ 441static int 442skip_white (const struct gmp_doscan_funs_t *funs, void *data) 443{ 444 int c; 445 int ret = 0; 446 447 do 448 { 449 c = (funs->get) (data); 450 ret++; 451 } 452 while (isspace (c)); 453 454 (funs->unget) (c, data); 455 ret--; 456 457 TRACE (printf (" skip white %d\n", ret)); 458 return ret; 459} 460 461 462int 463__gmp_doscan (const struct gmp_doscan_funs_t *funs, void *data, 464 const char *orig_fmt, va_list orig_ap) 465{ 466 struct gmp_doscan_params_t param; 467 va_list ap; 468 char *alloc_fmt; 469 const char *fmt, *this_fmt, *end_fmt; 470 size_t orig_fmt_len, alloc_fmt_size, len; 471 int new_fields, new_chars; 472 char fchar; 473 int fields = 0; 474 int chars = 0; 475 476 TRACE (printf ("__gmp_doscan \"%s\"\n", orig_fmt); 477 if (funs->scan == (gmp_doscan_scan_t) sscanf) 478 printf (" s=\"%s\"\n", * (const char **) data)); 479 480 /* Don't modify orig_ap, if va_list is actually an array and hence call by 481 reference. It could be argued that it'd be more efficient to leave 482 callers to make a copy if they care, but doing so here is going to be a 483 very small part of the total work, and we may as well keep applications 484 out of trouble. */ 485 va_copy (ap, orig_ap); 486 487 /* Parts of the format string are going to be copied so that a " %n" can 488 be appended. alloc_fmt is some space for that. orig_fmt_len+4 will be 489 needed if fmt consists of a single "%" specifier, but otherwise is an 490 overestimate. We're not going to be very fast here, so use 491 __gmp_allocate_func rather than TMP_ALLOC. */ 492 orig_fmt_len = strlen (orig_fmt); 493 alloc_fmt_size = orig_fmt_len + 4; 494 alloc_fmt = __GMP_ALLOCATE_FUNC_TYPE (alloc_fmt_size, char); 495 496 fmt = orig_fmt; 497 end_fmt = orig_fmt + orig_fmt_len; 498 499 for (;;) 500 { 501 next: 502 fchar = *fmt++; 503 504 if (fchar == '\0') 505 break; 506 507 if (isspace (fchar)) 508 { 509 chars += skip_white (funs, data); 510 continue; 511 } 512 513 if (fchar != '%') 514 { 515 int c; 516 literal: 517 c = (funs->get) (data); 518 if (c != fchar) 519 { 520 (funs->unget) (c, data); 521 if (c == EOF) 522 { 523 eof_no_match: 524 if (fields == 0) 525 fields = EOF; 526 } 527 goto done; 528 } 529 chars++; 530 continue; 531 } 532 533 param.type = '\0'; 534 param.base = 0; /* for e,f,g,i */ 535 param.ignore = 0; 536 param.width = 0; 537 538 this_fmt = fmt-1; 539 TRACE (printf (" this_fmt \"%s\"\n", this_fmt)); 540 541 for (;;) 542 { 543 ASSERT (fmt <= end_fmt); 544 545 fchar = *fmt++; 546 switch (fchar) { 547 548 case '\0': /* unterminated % sequence */ 549 ASSERT (0); 550 goto done; 551 552 case '%': /* literal % */ 553 goto literal; 554 555 case '[': /* character range */ 556 fchar = *fmt++; 557 if (fchar == '^') 558 fchar = *fmt++; 559 /* ']' allowed as the first char (possibly after '^') */ 560 if (fchar == ']') 561 fchar = *fmt++; 562 for (;;) 563 { 564 ASSERT (fmt <= end_fmt); 565 if (fchar == '\0') 566 { 567 /* unterminated % sequence */ 568 ASSERT (0); 569 goto done; 570 } 571 if (fchar == ']') 572 break; 573 fchar = *fmt++; 574 } 575 /*FALLTHRU*/ 576 case 'c': /* characters */ 577 case 's': /* string of non-whitespace */ 578 case 'p': /* pointer */ 579 libc_type: 580 len = fmt - this_fmt; 581 memcpy (alloc_fmt, this_fmt, len); 582 alloc_fmt[len++] = '%'; 583 alloc_fmt[len++] = 'n'; 584 alloc_fmt[len] = '\0'; 585 586 TRACE (printf (" scan \"%s\"\n", alloc_fmt); 587 if (funs->scan == (gmp_doscan_scan_t) sscanf) 588 printf (" s=\"%s\"\n", * (const char **) data)); 589 590 new_chars = -1; 591 if (param.ignore) 592 { 593 new_fields = (*funs->scan) (data, alloc_fmt, &new_chars, NULL); 594 ASSERT (new_fields == 0 || new_fields == EOF); 595 } 596 else 597 { 598 void *arg = va_arg (ap, void *); 599 new_fields = (*funs->scan) (data, alloc_fmt, arg, &new_chars); 600 ASSERT (new_fields==0 || new_fields==1 || new_fields==EOF); 601 602 if (new_fields == 0) 603 goto done; /* invalid input */ 604 605 if (new_fields == 1) 606 ASSERT (new_chars != -1); 607 } 608 TRACE (printf (" new_fields %d new_chars %d\n", 609 new_fields, new_chars)); 610 611 if (new_fields == -1) 612 goto eof_no_match; /* EOF before anything matched */ 613 614 /* Under param.ignore, when new_fields==0 we don't know if 615 it's a successful match or an invalid field. new_chars 616 won't have been assigned if it was an invalid field. */ 617 if (new_chars == -1) 618 goto done; /* invalid input */ 619 620 chars += new_chars; 621 (*funs->step) (data, new_chars); 622 623 increment_fields: 624 if (! param.ignore) 625 fields++; 626 goto next; 627 628 case 'd': /* decimal */ 629 case 'u': /* decimal */ 630 param.base = 10; 631 goto numeric; 632 633 case 'e': /* float */ 634 case 'E': /* float */ 635 case 'f': /* float */ 636 case 'g': /* float */ 637 case 'G': /* float */ 638 case 'i': /* integer with base marker */ 639 numeric: 640 if (param.type != 'F' && param.type != 'Q' && param.type != 'Z') 641 goto libc_type; 642 643 chars += skip_white (funs, data); 644 645 new_chars = gmpscan (funs, data, ¶m, 646 param.ignore ? NULL : va_arg (ap, void*)); 647 if (new_chars == -2) 648 goto eof_no_match; 649 if (new_chars == -1) 650 goto done; 651 652 ASSERT (new_chars >= 0); 653 chars += new_chars; 654 goto increment_fields; 655 656 case 'a': /* glibc allocate string */ 657 case '\'': /* glibc digit groupings */ 658 break; 659 660 case 'F': /* mpf_t */ 661 case 'j': /* intmax_t */ 662 case 'L': /* long long */ 663 case 'q': /* quad_t */ 664 case 'Q': /* mpq_t */ 665 case 't': /* ptrdiff_t */ 666 case 'z': /* size_t */ 667 case 'Z': /* mpz_t */ 668 set_type: 669 param.type = fchar; 670 break; 671 672 case 'h': /* short or char */ 673 if (param.type != 'h') 674 goto set_type; 675 param.type = 'H'; /* internal code for "hh" */ 676 break; 677 678 goto numeric; 679 680 case 'l': /* long, long long, double or long double */ 681 if (param.type != 'l') 682 goto set_type; 683 param.type = 'L'; /* "ll" means "L" */ 684 break; 685 686 case 'n': 687 if (! param.ignore) 688 { 689 void *p; 690 p = va_arg (ap, void *); 691 TRACE (printf (" store %%n to %p\n", p)); 692 switch (param.type) { 693 case '\0': * (int *) p = chars; break; 694 case 'F': mpf_set_si ((mpf_ptr) p, (long) chars); break; 695 case 'H': * (char *) p = chars; break; 696 case 'h': * (short *) p = chars; break; 697#if HAVE_INTMAX_T 698 case 'j': * (intmax_t *) p = chars; break; 699#else 700 case 'j': ASSERT_FAIL (intmax_t not available); break; 701#endif 702 case 'l': * (long *) p = chars; break; 703#if HAVE_QUAD_T && HAVE_LONG_LONG 704 case 'q': 705 ASSERT_ALWAYS (sizeof (quad_t) == sizeof (long long)); 706 /*FALLTHRU*/ 707#else 708 case 'q': ASSERT_FAIL (quad_t not available); break; 709#endif 710#if HAVE_LONG_LONG 711 case 'L': * (long long *) p = chars; break; 712#else 713 case 'L': ASSERT_FAIL (long long not available); break; 714#endif 715 case 'Q': mpq_set_si ((mpq_ptr) p, (long) chars, 1L); break; 716#if HAVE_PTRDIFF_T 717 case 't': * (ptrdiff_t *) p = chars; break; 718#else 719 case 't': ASSERT_FAIL (ptrdiff_t not available); break; 720#endif 721 case 'z': * (size_t *) p = chars; break; 722 case 'Z': mpz_set_si ((mpz_ptr) p, (long) chars); break; 723 default: ASSERT (0); break; 724 } 725 } 726 goto next; 727 728 case 'o': 729 param.base = 8; 730 goto numeric; 731 732 case 'x': 733 case 'X': 734 param.base = 16; 735 goto numeric; 736 737 case '0': case '1': case '2': case '3': case '4': 738 case '5': case '6': case '7': case '8': case '9': 739 param.width = 0; 740 do { 741 param.width = param.width * 10 + (fchar-'0'); 742 fchar = *fmt++; 743 } while (isdigit (fchar)); 744 fmt--; /* unget the non-digit */ 745 break; 746 747 case '*': 748 param.ignore = 1; 749 break; 750 751 default: 752 /* something invalid in a % sequence */ 753 ASSERT (0); 754 goto next; 755 } 756 } 757 } 758 759 done: 760 (*__gmp_free_func) (alloc_fmt, alloc_fmt_size); 761 return fields; 762} 763