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, ¶m,
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