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