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