[BACK]Return to doscan.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / scanf

Annotation of OpenXM_contrib/gmp/scanf/doscan.c, Revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>