Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/*-
2
 * Copyright (c) 1990, 1993
3
 *      The Regents of the University of California.  All rights reserved.
4
 *
5
 * This code is derived from software contributed to Berkeley by
6
 * Chris Torek.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. All advertising materials mentioning features or use of this software
17
 *    must display the following acknowledgement:
18
 *      This product includes software developed by the University of
19
 *      California, Berkeley and its contributors.
20
 * 4. Neither the name of the University nor the names of its contributors
21
 *    may be used to endorse or promote products derived from this software
22
 *    without specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34
 * SUCH DAMAGE.
35
 */
36
 
37
#if defined(LIBC_SCCS) && !defined(lint)
38
#if 0
39
static char sccsid[] = "@(#)vfscanf.c   8.1 (Berkeley) 6/4/93";
40
#endif
41
static const char rcsid[] =
42
                "$\Id: vfscanf.c,v 1.3.2.2 1997/03/07 09:12:11 joerg Exp $";
43
#endif /* LIBC_SCCS and not lint */
44
 
45
#include <stdio.h>
46
#include <stdlib.h>
47
#include <ctype.h>
48
#if __STDC__
49
#include <stdarg.h>
50
#else
51
#include <varargs.h>
52
#endif
53
#include <string.h>
54
 
55
#include "collate.h"
56
#include "local.h"
57
 
58
#define FLOATING_POINT
59
 
60
#include "floatio.h"
61
#define BUF             513     /* Maximum length of numeric string. */
62
 
63
/*
64
 * Flags used during conversion.
65
 */
66
#define LONG            0x01    /* l: long or double */
67
#define LONGDBL         0x02    /* L: long double; unimplemented */
68
#define SHORT           0x04    /* h: short */
69
#define SUPPRESS        0x08    /* suppress assignment */
70
#define POINTER         0x10    /* weird %p pointer (`fake hex') */
71
#define NOSKIP          0x20    /* do not skip blanks */
72
 
73
/*
74
 * The following are used in numeric conversions only:
75
 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
76
 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
77
 */
78
#define SIGNOK          0x40    /* +/- is (still) legal */
79
#define NDIGITS         0x80    /* no digits detected */
80
 
81
#define DPTOK           0x100   /* (float) decimal point is still legal */
82
#define EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
83
 
84
#define PFXOK           0x100   /* 0x prefix is (still) legal */
85
#define NZDIGITS        0x200   /* no zero digits detected */
86
 
87
/*
88
 * Conversion types.
89
 */
90
#define CT_CHAR         0       /* %c conversion */
91
#define CT_CCL          1       /* %[...] conversion */
92
#define CT_STRING       2       /* %s conversion */
93
#define CT_INT          3       /* integer, i.e., strtol or strtoul */
94
#define CT_FLOAT        4       /* floating, i.e., strtod */
95
 
96
//#define u_char unsigned char
97
//#define u_long unsigned long
98
 
99
static u_char *__sccl(char *, u_char *);
100
 
101
/*
102
 * vfscanf
103
 */
104
int
105
__svfscanf(fp, fmt0, ap)
106
        register FILE *fp;
107
        char const *fmt0;
108
        va_list ap;
109
{
110
        register u_char *fmt = (u_char *)fmt0;
111
        register int c;         /* character from format, or conversion */
112
        register size_t width;  /* field width, or 0 */
113
        register char *p;       /* points into all kinds of strings */
114
        register int n;         /* handy integer */
115
        register int flags;     /* flags as defined above */
116
        register char *p0;      /* saves original value of p when necessary */
117
        int nassigned;          /* number of fields assigned */
118
        int nconversions;       /* number of conversions */
119
        int nread;              /* number of characters consumed from fp */
120
        int base;               /* base argument to strtol/strtoul */
121
        u_long (*ccfn)();       /* conversion function (strtol/strtoul) */
122
        char ccltab[256];       /* character class table for %[...] */
123
        char buf[BUF];          /* buffer for numeric conversions */
124
 
125
        /* `basefix' is used to avoid `if' tests in the integer scanner */
126
        static short basefix[17] =
127
                { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
128
 
129
        nassigned = 0;
130
        nconversions = 0;
131
        nread = 0;
132
        base = 0;               /* XXX just to keep gcc happy */
133
        ccfn = NULL;            /* XXX just to keep gcc happy */
134
        for (;;) {
135
                c = *fmt++;
136
                if (c == 0)
137
                        return (nassigned);
138
                if (isspace(c)) {
139
                        for (;;) {
140
                                if (fp->_r <= 0 && __srefill(fp))
141
                                        goto input_failure;
142
                                if (!isspace(*fp->_p))
143
                                        break;
144
                                nread++, fp->_r--, fp->_p++;
145
                        }
146
                        continue;
147
                }
148
                if (c != '%')
149
                        goto literal;
150
                width = 0;
151
                flags = 0;
152
                /*
153
                 * switch on the format.  continue if done;
154
                 * break once format type is derived.
155
                 */
156
again:          c = *fmt++;
157
                switch (c) {
158
                case '%':
159
literal:
160
                        if (fp->_r <= 0 && __srefill(fp))
161
                                goto input_failure;
162
                        if (*fp->_p != c)
163
                                goto match_failure;
164
                        fp->_r--, fp->_p++;
165
                        nread++;
166
                        continue;
167
 
168
                case '*':
169
                        flags |= SUPPRESS;
170
                        goto again;
171
                case 'l':
172
                        flags |= LONG;
173
                        goto again;
174
                case 'L':
175
                        flags |= LONGDBL;
176
                        goto again;
177
                case 'h':
178
                        flags |= SHORT;
179
                        goto again;
180
 
181
                case '0': case '1': case '2': case '3': case '4':
182
                case '5': case '6': case '7': case '8': case '9':
183
                        width = width * 10 + c - '0';
184
                        goto again;
185
 
186
                /*
187
                 * Conversions.
188
                 * Those marked `compat' are for 4.[123]BSD compatibility.
189
                 *
190
                 * (According to ANSI, E and X formats are supposed
191
                 * to the same as e and x.  Sorry about that.)
192
                 */
193
                case 'D':       /* compat */
194
                        flags |= LONG;
195
                        /* FALLTHROUGH */
196
                case 'd':
197
                        c = CT_INT;
198
                        ccfn = (u_long (*)())strtol;
199
                        base = 10;
200
                        break;
201
 
202
                case 'i':
203
                        c = CT_INT;
204
                        ccfn = (u_long (*)())strtol;
205
                        base = 0;
206
                        break;
207
 
208
                case 'O':       /* compat */
209
                        flags |= LONG;
210
                        /* FALLTHROUGH */
211
                case 'o':
212
                        c = CT_INT;
213
                        ccfn = strtoul;
214
                        base = 8;
215
                        break;
216
 
217
                case 'u':
218
                        c = CT_INT;
219
                        ccfn = strtoul;
220
                        base = 10;
221
                        break;
222
 
223
                case 'X':       /* compat   XXX */
224
                        flags |= LONG;
225
                        /* FALLTHROUGH */
226
                case 'x':
227
                        flags |= PFXOK; /* enable 0x prefixing */
228
                        c = CT_INT;
229
                        ccfn = strtoul;
230
                        base = 16;
231
                        break;
232
 
233
#ifdef FLOATING_POINT
234
                case 'E':       /* compat   XXX */
235
                case 'F':       /* compat */
236
                        flags |= LONG;
237
                        /* FALLTHROUGH */
238
                case 'e': case 'f': case 'g':
239
                        c = CT_FLOAT;
240
                        break;
241
#endif
242
 
243
                case 's':
244
                        c = CT_STRING;
245
                        break;
246
 
247
                case '[':
248
                        fmt = __sccl(ccltab, fmt);
249
                        flags |= NOSKIP;
250
                        c = CT_CCL;
251
                        break;
252
 
253
                case 'c':
254
                        flags |= NOSKIP;
255
                        c = CT_CHAR;
256
                        break;
257
 
258
                case 'p':       /* pointer format is like hex */
259
                        flags |= POINTER | PFXOK;
260
                        c = CT_INT;
261
                        ccfn = strtoul;
262
                        base = 16;
263
                        break;
264
 
265
                case 'n':
266
                        nconversions++;
267
                        if (flags & SUPPRESS)   /* ??? */
268
                                continue;
269
                        if (flags & SHORT)
270
                                *va_arg(ap, short *) = nread;
271
                        else if (flags & LONG)
272
                                *va_arg(ap, long *) = nread;
273
                        else
274
                                *va_arg(ap, int *) = nread;
275
                        continue;
276
 
277
                /*
278
                 * Disgusting backwards compatibility hacks.    XXX
279
                 */
280
                case '\0':      /* compat */
281
                        return (EOF);
282
 
283
                default:        /* compat */
284
                        if (isupper(c))
285
                                flags |= LONG;
286
                        c = CT_INT;
287
                        ccfn = (u_long (*)())strtol;
288
                        base = 10;
289
                        break;
290
                }
291
 
292
                /*
293
                 * We have a conversion that requires input.
294
                 */
295
                if (fp->_r <= 0 && __srefill(fp))
296
                        goto input_failure;
297
 
298
                /*
299
                 * Consume leading white space, except for formats
300
                 * that suppress this.
301
                 */
302
                if ((flags & NOSKIP) == 0) {
303
                        while (isspace(*fp->_p)) {
304
                                nread++;
305
                                if (--fp->_r > 0)
306
                                        fp->_p++;
307
                                else if (__srefill(fp))
308
                                        goto input_failure;
309
                        }
310
                        /*
311
                         * Note that there is at least one character in
312
                         * the buffer, so conversions that do not set NOSKIP
313
                         * ca no longer result in an input failure.
314
                         */
315
                }
316
 
317
                /*
318
                 * Do the conversion.
319
                 */
320
                switch (c) {
321
 
322
                case CT_CHAR:
323
                        /* scan arbitrary characters (sets NOSKIP) */
324
                        if (width == 0)
325
                                width = 1;
326
                        if (flags & SUPPRESS) {
327
                                size_t sum = 0;
328
                                for (;;) {
329
                                        if ((n = fp->_r) < width) {
330
                                                sum += n;
331
                                                width -= n;
332
                                                fp->_p += n;
333
                                                if (__srefill(fp)) {
334
                                                        if (sum == 0)
335
                                                            goto input_failure;
336
                                                        break;
337
                                                }
338
                                        } else {
339
                                                sum += width;
340
                                                fp->_r -= width;
341
                                                fp->_p += width;
342
                                                break;
343
                                        }
344
                                }
345
                                nread += sum;
346
                        } else {
347
                                size_t r = fread((void *)va_arg(ap, char *), 1,
348
                                    width, fp);
349
 
350
                                if (r == 0)
351
                                        goto input_failure;
352
                                nread += r;
353
                                nassigned++;
354
                        }
355
                        nconversions++;
356
                        break;
357
 
358
                case CT_CCL:
359
                        /* scan a (nonempty) character class (sets NOSKIP) */
360
                        if (width == 0)
361
                                width = (size_t)~0;     /* `infinity' */
362
                        /* take only those things in the class */
363
                        if (flags & SUPPRESS) {
364
                                n = 0;
365
                                while (ccltab[*fp->_p]) {
366
                                        n++, fp->_r--, fp->_p++;
367
                                        if (--width == 0)
368
                                                break;
369
                                        if (fp->_r <= 0 && __srefill(fp)) {
370
                                                if (n == 0)
371
                                                        goto input_failure;
372
                                                break;
373
                                        }
374
                                }
375
                                if (n == 0)
376
                                        goto match_failure;
377
                        } else {
378
                                p0 = p = va_arg(ap, char *);
379
                                while (ccltab[*fp->_p]) {
380
                                        fp->_r--;
381
                                        *p++ = *fp->_p++;
382
                                        if (--width == 0)
383
                                                break;
384
                                        if (fp->_r <= 0 && __srefill(fp)) {
385
                                                if (p == p0)
386
                                                        goto input_failure;
387
                                                break;
388
                                        }
389
                                }
390
                                n = p - p0;
391
                                if (n == 0)
392
                                        goto match_failure;
393
                                *p = 0;
394
                                nassigned++;
395
                        }
396
                        nread += n;
397
                        nconversions++;
398
                        break;
399
 
400
                case CT_STRING:
401
                        /* like CCL, but zero-length string OK, & no NOSKIP */
402
                        if (width == 0)
403
                                width = (size_t)~0;
404
                        if (flags & SUPPRESS) {
405
                                n = 0;
406
                                while (!isspace(*fp->_p)) {
407
                                        n++, fp->_r--, fp->_p++;
408
                                        if (--width == 0)
409
                                                break;
410
                                        if (fp->_r <= 0 && __srefill(fp))
411
                                                break;
412
                                }
413
                                nread += n;
414
                        } else {
415
                                p0 = p = va_arg(ap, char *);
416
                                while (!isspace(*fp->_p)) {
417
                                        fp->_r--;
418
                                        *p++ = *fp->_p++;
419
                                        if (--width == 0)
420
                                                break;
421
                                        if (fp->_r <= 0 && __srefill(fp))
422
                                                break;
423
                                }
424
                                *p = 0;
425
                                nread += p - p0;
426
                                nassigned++;
427
                        }
428
                        nconversions++;
429
                        continue;
430
 
431
                case CT_INT:
432
                        /* scan an integer as if by strtol/strtoul */
433
#ifdef hardway
434
                        if (width == 0 || width > sizeof(buf) - 1)
435
                                width = sizeof(buf) - 1;
436
#else
437
                        /* size_t is unsigned, hence this optimisation */
438
                        if (--width > sizeof(buf) - 2)
439
                                width = sizeof(buf) - 2;
440
                        width++;
441
#endif
442
                        flags |= SIGNOK | NDIGITS | NZDIGITS;
443
                        for (p = buf; width; width--) {
444
                                c = *fp->_p;
445
                                /*
446
                                 * Switch on the character; `goto ok'
447
                                 * if we accept it as a part of number.
448
                                 */
449
                                switch (c) {
450
 
451
                                /*
452
                                 * The digit 0 is always legal, but is
453
                                 * special.  For %i conversions, if no
454
                                 * digits (zero or nonzero) have been
455
                                 * scanned (only signs), we will have
456
                                 * base==0.  In that case, we should set
457
                                 * it to 8 and enable 0x prefixing.
458
                                 * Also, if we have not scanned zero digits
459
                                 * before this, do not turn off prefixing
460
                                 * (someone else will turn it off if we
461
                                 * have scanned any nonzero digits).
462
                                 */
463
                                case '0':
464
                                        if (base == 0) {
465
                                                base = 8;
466
                                                flags |= PFXOK;
467
                                        }
468
                                        if (flags & NZDIGITS)
469
                                            flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
470
                                        else
471
                                            flags &= ~(SIGNOK|PFXOK|NDIGITS);
472
                                        goto ok;
473
 
474
                                /* 1 through 7 always legal */
475
                                case '1': case '2': case '3':
476
                                case '4': case '5': case '6': case '7':
477
                                        base = basefix[base];
478
                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
479
                                        goto ok;
480
 
481
                                /* digits 8 and 9 ok iff decimal or hex */
482
                                case '8': case '9':
483
                                        base = basefix[base];
484
                                        if (base <= 8)
485
                                                break;  /* not legal here */
486
                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
487
                                        goto ok;
488
 
489
                                /* letters ok iff hex */
490
                                case 'A': case 'B': case 'C':
491
                                case 'D': case 'E': case 'F':
492
                                case 'a': case 'b': case 'c':
493
                                case 'd': case 'e': case 'f':
494
                                        /* no need to fix base here */
495
                                        if (base <= 10)
496
                                                break;  /* not legal here */
497
                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
498
                                        goto ok;
499
 
500
                                /* sign ok only as first character */
501
                                case '+': case '-':
502
                                        if (flags & SIGNOK) {
503
                                                flags &= ~SIGNOK;
504
                                                goto ok;
505
                                        }
506
                                        break;
507
 
508
                                /* x ok iff flag still set & 2nd char */
509
                                case 'x': case 'X':
510
                                        if (flags & PFXOK && p == buf + 1) {
511
                                                base = 16;      /* if %i */
512
                                                flags &= ~PFXOK;
513
                                                goto ok;
514
                                        }
515
                                        break;
516
                                }
517
 
518
                                /*
519
                                 * If we got here, c is not a legal character
520
                                 * for a number.  Stop accumulating digits.
521
                                 */
522
                                break;
523
                ok:
524
                                /*
525
                                 * c is legal: store it and look at the next.
526
                                 */
527
                                *p++ = c;
528
                                if (--fp->_r > 0)
529
                                        fp->_p++;
530
                                else if (__srefill(fp))
531
                                        break;          /* EOF */
532
                        }
533
                        /*
534
                         * If we had only a sign, it is no good; push
535
                         * back the sign.  If the number ends in `x',
536
                         * it was [sign] '0' 'x', so push back the x
537
                         * and treat it as [sign] '0'.
538
                         */
539
                        if (flags & NDIGITS) {
540
                                if (p > buf)
541
                                        (void) ungetc(*(u_char *)--p, fp);
542
                                goto match_failure;
543
                        }
544
                        c = ((u_char *)p)[-1];
545
                        if (c == 'x' || c == 'X') {
546
                                --p;
547
                                (void) ungetc(c, fp);
548
                        }
549
                        if ((flags & SUPPRESS) == 0) {
550
                                u_long res;
551
 
552
                                *p = 0;
553
                                res = (*ccfn)(buf, (char **)NULL, base);
554
                                if (flags & POINTER)
555
                                        *va_arg(ap, void **) = (void *)res;
556
                                else if (flags & SHORT)
557
                                        *va_arg(ap, short *) = res;
558
                                else if (flags & LONG)
559
                                        *va_arg(ap, long *) = res;
560
                                else
561
                                        *va_arg(ap, int *) = res;
562
                                nassigned++;
563
                        }
564
                        nread += p - buf;
565
                        nconversions++;
566
                        break;
567
 
568
#ifdef FLOATING_POINT
569
                case CT_FLOAT:
570
                        /* scan a floating point number as if by strtod */
571
#ifdef hardway
572
                        if (width == 0 || width > sizeof(buf) - 1)
573
                                width = sizeof(buf) - 1;
574
#else
575
                        /* size_t is unsigned, hence this optimisation */
576
                        if (--width > sizeof(buf) - 2)
577
                                width = sizeof(buf) - 2;
578
                        width++;
579
#endif
580
                        flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
581
                        for (p = buf; width; width--) {
582
                                c = *fp->_p;
583
                                /*
584
                                 * This code mimicks the integer conversion
585
                                 * code, but is much simpler.
586
                                 */
587
                                switch (c) {
588
 
589
                                case '0': case '1': case '2': case '3':
590
                                case '4': case '5': case '6': case '7':
591
                                case '8': case '9':
592
                                        flags &= ~(SIGNOK | NDIGITS);
593
                                        goto fok;
594
 
595
                                case '+': case '-':
596
                                        if (flags & SIGNOK) {
597
                                                flags &= ~SIGNOK;
598
                                                goto fok;
599
                                        }
600
                                        break;
601
                                case '.':
602
                                        if (flags & DPTOK) {
603
                                                flags &= ~(SIGNOK | DPTOK);
604
                                                goto fok;
605
                                        }
606
                                        break;
607
                                case 'e': case 'E':
608
                                        /* no exponent without some digits */
609
                                        if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
610
                                                flags =
611
                                                    (flags & ~(EXPOK|DPTOK)) |
612
                                                    SIGNOK | NDIGITS;
613
                                                goto fok;
614
                                        }
615
                                        break;
616
                                }
617
                                break;
618
                fok:
619
                                *p++ = c;
620
                                if (--fp->_r > 0)
621
                                        fp->_p++;
622
                                else if (__srefill(fp))
623
                                        break;  /* EOF */
624
                        }
625
                        /*
626
                         * If no digits, might be missing exponent digits
627
                         * (just give back the exponent) or might be missing
628
                         * regular digits, but had sign and/or decimal point.
629
                         */
630
                        if (flags & NDIGITS) {
631
                                if (flags & EXPOK) {
632
                                        /* no digits at all */
633
                                        while (p > buf)
634
                                                ungetc(*(u_char *)--p, fp);
635
                                        goto match_failure;
636
                                }
637
                                /* just a bad exponent (e and maybe sign) */
638
                                c = *(u_char *)--p;
639
                                if (c != 'e' && c != 'E') {
640
                                        (void) ungetc(c, fp);/* sign */
641
                                        c = *(u_char *)--p;
642
                                }
643
                                (void) ungetc(c, fp);
644
                        }
645
                        if ((flags & SUPPRESS) == 0) {
646
                                double res;
647
 
648
                                *p = 0;
649
                                res = strtod(buf,(char **) NULL);
650
                                if (flags & LONG)
651
                                        *va_arg(ap, double *) = res;
652
                                else
653
                                        *va_arg(ap, float *) = res;
654
                                nassigned++;
655
                        }
656
                        nread += p - buf;
657
                        nconversions++;
658
                        break;
659
#endif /* FLOATING_POINT */
660
                }
661
        }
662
input_failure:
663
        return (nconversions != 0 ? nassigned : EOF);
664
match_failure:
665
        return (nassigned);
666
}
667
 
668
/*
669
 * Fill in the given table from the scanset at the given format
670
 * (just after `[').  Return a pointer to the character past the
671
 * closing `]'.  The table has a 1 wherever characters should be
672
 * considered part of the scanset.
673
 */
674
static u_char *
675
__sccl(tab, fmt)
676
        register char *tab;
677
        register u_char *fmt;
678
{
679
        register int c, n, v, i;
680
 
681
        /* first `clear' the whole table */
682
        c = *fmt++;             /* first char hat => negated scanset */
683
        if (c == '^') {
684
                v = 1;          /* default => accept */
685
                c = *fmt++;     /* get new first char */
686
        } else
687
                v = 0;          /* default => reject */
688
        (void) memset(tab, v, 256);
689
        if (c == 0)
690
                return (fmt - 1);/* format ended before closing ] */
691
 
692
        /*
693
         * Now set the entries corresponding to the actual scanset
694
         * to the opposite of the above.
695
         *
696
         * The first character may be ']' (or '-') without being special;
697
         * the last character may be '-'.
698
         */
699
        v = 1 - v;
700
        for (;;) {
701
                tab[c] = v;             /* take character c */
702
doswitch:
703
                n = *fmt++;             /* and examine the next */
704
                switch (n) {
705
 
706
                case 0:                 /* format ended too soon */
707
                        return (fmt - 1);
708
 
709
                case '-':
710
                        /*
711
                         * A scanset of the form
712
                         *      [01+-]
713
                         * is defined as `the digit 0, the digit 1,
714
                         * the character +, the character -', but
715
                         * the effect of a scanset such as
716
                         *      [a-zA-Z0-9]
717
                         * is implementation defined.  The V7 Unix
718
                         * scanf treats `a-z' as `the letters a through
719
                         * z', but treats `a-a' as `the letter a, the
720
                         * character -, and the letter a'.
721
                         *
722
                         * For compatibility, the `-' is not considerd
723
                         * to define a range if the character following
724
                         * it is either a close bracket (required by ANSI)
725
                         * or is not numerically greater than the character
726
                         * we just stored in the table (c).
727
                         */
728
                        n = *fmt;
729
                        if (n == ']' || __collate_range_cmp (n, c) < 0) {
730
                                c = '-';
731
                                break;  /* resume the for(;;) */
732
                        }
733
                        fmt++;
734
                        /* fill in the range */
735
                        for (i = 0; i < 256; i ++)
736
                                if (   __collate_range_cmp (c, i) < 0
737
                                    && __collate_range_cmp (i, n) <= 0
738
                                   )
739
                                tab[i] = v;
740
#if 1   /* XXX another disgusting compatibility hack */
741
                        c = n;
742
                        /*
743
                         * Alas, the V7 Unix scanf also treats formats
744
                         * such as [a-c-e] as `the letters a through e'.
745
                         * This too is permitted by the standard....
746
                         */
747
                        goto doswitch;
748
#else
749
                        c = *fmt++;
750
                        if (c == 0)
751
                                return (fmt - 1);
752
                        if (c == ']')
753
                                return (fmt);
754
#endif
755
                        break;
756
 
757
                case ']':               /* end of scanset */
758
                        return (fmt);
759
 
760
                default:                /* just another character */
761
                        c = n;
762
                        break;
763
                }
764
        }
765
        /* NOTREACHED */
766
}