source: trunk/third/sendmail/libsm/vfscanf.c @ 19204

Revision 19204, 18.7 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1990, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * By using this file, you agree to the terms and conditions set
11 * forth in the LICENSE file which can be found at the top level of
12 * the sendmail distribution.
13 */
14
15#include <sm/gen.h>
16SM_IDSTR(id, "@(#)$Id: vfscanf.c,v 1.1.1.1 2003-04-08 15:06:05 zacheiss Exp $")
17
18#include <ctype.h>
19#include <stdlib.h>
20#include <errno.h>
21#include <setjmp.h>
22#include <sys/time.h>
23#include <sm/varargs.h>
24#include <sm/config.h>
25#include <sm/io.h>
26#include <sm/signal.h>
27#include <sm/clock.h>
28#include <sm/string.h>
29#include "local.h"
30
31#define BUF             513     /* Maximum length of numeric string. */
32
33/* Flags used during conversion. */
34#define LONG            0x01    /* l: long or double */
35#define SHORT           0x04    /* h: short */
36#define QUAD            0x08    /* q: quad (same as ll) */
37#define SUPPRESS        0x10    /* suppress assignment */
38#define POINTER         0x20    /* weird %p pointer (`fake hex') */
39#define NOSKIP          0x40    /* do not skip blanks */
40
41/*
42**  The following are used in numeric conversions only:
43**  SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
44**  SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
45*/
46
47#define SIGNOK          0x080   /* +/- is (still) legal */
48#define NDIGITS         0x100   /* no digits detected */
49
50#define DPTOK           0x200   /* (float) decimal point is still legal */
51#define EXPOK           0x400   /* (float) exponent (e+3, etc) still legal */
52
53#define PFXOK           0x200   /* 0x prefix is (still) legal */
54#define NZDIGITS        0x400   /* no zero digits detected */
55
56/* Conversion types. */
57#define CT_CHAR         0       /* %c conversion */
58#define CT_CCL          1       /* %[...] conversion */
59#define CT_STRING       2       /* %s conversion */
60#define CT_INT          3       /* integer, i.e., strtoll or strtoull */
61#define CT_FLOAT        4       /* floating, i.e., strtod */
62
63static unsigned char *sm_sccl __P((char *, unsigned char *));
64static jmp_buf ScanTimeOut;
65
66/*
67**  SCANALRM -- handler when timeout activated for sm_io_vfscanf()
68**
69**  Returns flow of control to where setjmp(ScanTimeOut) was set.
70**
71**      Parameters:
72**              sig -- unused
73**
74**      Returns:
75**              does not return
76**
77**      Side Effects:
78**              returns flow of control to setjmp(ScanTimeOut).
79**
80**      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
81**              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
82**              DOING.
83*/
84
85/* ARGSUSED0 */
86static void
87scanalrm(sig)
88        int sig;
89{
90        longjmp(ScanTimeOut, 1);
91}
92
93/*
94**  SM_VFSCANF -- convert input into data units
95**
96**      Parameters:
97**              fp -- file pointer for input data
98**              timeout -- time intvl allowed to complete (milliseconds)
99**              fmt0 -- format for finding data units
100**              ap -- vectors for memory location for storing data units
101**
102**      Results:
103**              Success: number of data units assigned
104**              Failure: SM_IO_EOF
105*/
106
107int
108sm_vfscanf(fp, timeout, fmt0, ap)
109        register SM_FILE_T *fp;
110        int SM_NONVOLATILE timeout;
111        char const *fmt0;
112        va_list SM_NONVOLATILE ap;
113{
114        register unsigned char *SM_NONVOLATILE fmt = (unsigned char *) fmt0;
115        register int c;         /* character from format, or conversion */
116        register size_t width;  /* field width, or 0 */
117        register char *p;       /* points into all kinds of strings */
118        register int n;         /* handy integer */
119        register int flags;     /* flags as defined above */
120        register char *p0;      /* saves original value of p when necessary */
121        int nassigned;          /* number of fields assigned */
122        int nread;              /* number of characters consumed from fp */
123        int base;               /* base argument to strtoll/strtoull */
124        ULONGLONG_T (*ccfn)();  /* conversion function (strtoll/strtoull) */
125        char ccltab[256];       /* character class table for %[...] */
126        char buf[BUF];          /* buffer for numeric conversions */
127        SM_EVENT *evt = NULL;
128
129        /* `basefix' is used to avoid `if' tests in the integer scanner */
130        static short basefix[17] =
131                { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
132
133        if (timeout == SM_TIME_DEFAULT)
134                timeout = fp->f_timeout;
135        if (timeout == SM_TIME_IMMEDIATE)
136        {
137                /*
138                **  Filling the buffer will take time and we are wanted to
139                **  return immediately. So...
140                */
141
142                errno = EAGAIN;
143                return SM_IO_EOF;
144        }
145
146        if (timeout != SM_TIME_FOREVER)
147        {
148                if (setjmp(ScanTimeOut) != 0)
149                {
150                        errno = EAGAIN;
151                        return SM_IO_EOF;
152                }
153
154                evt = sm_seteventm(timeout, scanalrm, 0);
155        }
156
157        nassigned = 0;
158        nread = 0;
159        base = 0;               /* XXX just to keep gcc happy */
160        ccfn = NULL;            /* XXX just to keep gcc happy */
161        for (;;)
162        {
163                c = *fmt++;
164                if (c == 0)
165                {
166                        if (evt != NULL)
167                                sm_clrevent(evt); /*  undo our timeout */
168                        return nassigned;
169                }
170                if (isspace(c))
171                {
172                        while ((fp->f_r > 0 || sm_refill(fp, SM_TIME_FOREVER)
173                                                == 0) &&
174                            isspace(*fp->f_p))
175                                nread++, fp->f_r--, fp->f_p++;
176                        continue;
177                }
178                if (c != '%')
179                        goto literal;
180                width = 0;
181                flags = 0;
182
183                /*
184                **  switch on the format.  continue if done;
185                **  break once format type is derived.
186                */
187
188again:          c = *fmt++;
189                switch (c)
190                {
191                  case '%':
192literal:
193                        if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
194                                goto input_failure;
195                        if (*fp->f_p != c)
196                                goto match_failure;
197                        fp->f_r--, fp->f_p++;
198                        nread++;
199                        continue;
200
201                  case '*':
202                        flags |= SUPPRESS;
203                        goto again;
204                  case 'h':
205                        flags |= SHORT;
206                        goto again;
207                  case 'l':
208                        if (*fmt == 'l')
209                        {
210                                fmt++;
211                                flags |= QUAD;
212                        }
213                        else
214                        {
215                                flags |= LONG;
216                        }
217                        goto again;
218                  case 'q':
219                        flags |= QUAD;
220                        goto again;
221
222                  case '0': case '1': case '2': case '3': case '4':
223                  case '5': case '6': case '7': case '8': case '9':
224                        width = width * 10 + c - '0';
225                        goto again;
226
227                /*
228                **  Conversions.
229                **  Those marked `compat' are for 4.[123]BSD compatibility.
230                **
231                **  (According to ANSI, E and X formats are supposed
232                **  to the same as e and x.  Sorry about that.)
233                */
234
235                  case 'D':     /* compat */
236                        flags |= LONG;
237                        /* FALLTHROUGH */
238                  case 'd':
239                        c = CT_INT;
240                        ccfn = (ULONGLONG_T (*)())sm_strtoll;
241                        base = 10;
242                        break;
243
244                  case 'i':
245                        c = CT_INT;
246                        ccfn = (ULONGLONG_T (*)())sm_strtoll;
247                        base = 0;
248                        break;
249
250                  case 'O':     /* compat */
251                        flags |= LONG;
252                        /* FALLTHROUGH */
253                  case 'o':
254                        c = CT_INT;
255                        ccfn = sm_strtoull;
256                        base = 8;
257                        break;
258
259                  case 'u':
260                        c = CT_INT;
261                        ccfn = sm_strtoull;
262                        base = 10;
263                        break;
264
265                  case 'X':
266                  case 'x':
267                        flags |= PFXOK; /* enable 0x prefixing */
268                        c = CT_INT;
269                        ccfn = sm_strtoull;
270                        base = 16;
271                        break;
272
273                  case 'E':
274                  case 'G':
275                  case 'e':
276                  case 'f':
277                  case 'g':
278                        c = CT_FLOAT;
279                        break;
280
281                  case 's':
282                        c = CT_STRING;
283                        break;
284
285                  case '[':
286                        fmt = sm_sccl(ccltab, fmt);
287                        flags |= NOSKIP;
288                        c = CT_CCL;
289                        break;
290
291                  case 'c':
292                        flags |= NOSKIP;
293                        c = CT_CHAR;
294                        break;
295
296                  case 'p':     /* pointer format is like hex */
297                        flags |= POINTER | PFXOK;
298                        c = CT_INT;
299                        ccfn = sm_strtoull;
300                        base = 16;
301                        break;
302
303                  case 'n':
304                        if (flags & SUPPRESS)   /* ??? */
305                                continue;
306                        if (flags & SHORT)
307                                *SM_VA_ARG(ap, short *) = nread;
308                        else if (flags & LONG)
309                                *SM_VA_ARG(ap, long *) = nread;
310                        else
311                                *SM_VA_ARG(ap, int *) = nread;
312                        continue;
313
314                /* Disgusting backwards compatibility hacks.    XXX */
315                  case '\0':    /* compat */
316                        if (evt != NULL)
317                                sm_clrevent(evt); /*  undo our timeout */
318                        return SM_IO_EOF;
319
320                  default:      /* compat */
321                        if (isupper(c))
322                                flags |= LONG;
323                        c = CT_INT;
324                        ccfn = (ULONGLONG_T (*)()) sm_strtoll;
325                        base = 10;
326                        break;
327                }
328
329                /* We have a conversion that requires input. */
330                if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
331                        goto input_failure;
332
333                /*
334                **  Consume leading white space, except for formats
335                **  that suppress this.
336                */
337
338                if ((flags & NOSKIP) == 0)
339                {
340                        while (isspace(*fp->f_p))
341                        {
342                                nread++;
343                                if (--fp->f_r > 0)
344                                        fp->f_p++;
345                                else if (sm_refill(fp, SM_TIME_FOREVER))
346                                        goto input_failure;
347                        }
348                        /*
349                        **  Note that there is at least one character in
350                        **  the buffer, so conversions that do not set NOSKIP
351                        **  can no longer result in an input failure.
352                        */
353                }
354
355                /* Do the conversion. */
356                switch (c)
357                {
358                  case CT_CHAR:
359                        /* scan arbitrary characters (sets NOSKIP) */
360                        if (width == 0)
361                                width = 1;
362                        if (flags & SUPPRESS)
363                        {
364                                size_t sum = 0;
365                                for (;;)
366                                {
367                                        if ((size_t) (n = fp->f_r) < width)
368                                        {
369                                                sum += n;
370                                                width -= n;
371                                                fp->f_p += n;
372                                                if (sm_refill(fp,
373                                                              SM_TIME_FOREVER))
374                                                {
375                                                        if (sum == 0)
376                                                                goto input_failure;
377                                                        break;
378                                                }
379                                        }
380                                        else
381                                        {
382                                                sum += width;
383                                                fp->f_r -= width;
384                                                fp->f_p += width;
385                                                break;
386                                        }
387                                }
388                                nread += sum;
389                        }
390                        else
391                        {
392                                size_t r;
393
394                                r = sm_io_read(fp, SM_TIME_FOREVER,
395                                                (void *) SM_VA_ARG(ap, char *),
396                                                width);
397                                if (r == 0)
398                                        goto input_failure;
399                                nread += r;
400                                nassigned++;
401                        }
402                        break;
403
404                  case CT_CCL:
405                        /* scan a (nonempty) character class (sets NOSKIP) */
406                        if (width == 0)
407                                width = (size_t)~0;     /* `infinity' */
408
409                        /* take only those things in the class */
410                        if (flags & SUPPRESS)
411                        {
412                                n = 0;
413                                while (ccltab[*fp->f_p] != '\0')
414                                {
415                                        n++, fp->f_r--, fp->f_p++;
416                                        if (--width == 0)
417                                                break;
418                                        if (fp->f_r <= 0 &&
419                                            sm_refill(fp, SM_TIME_FOREVER))
420                                        {
421                                                if (n == 0) /* XXX how? */
422                                                        goto input_failure;
423                                                break;
424                                        }
425                                }
426                                if (n == 0)
427                                        goto match_failure;
428                        }
429                        else
430                        {
431                                p0 = p = SM_VA_ARG(ap, char *);
432                                while (ccltab[*fp->f_p] != '\0')
433                                {
434                                        fp->f_r--;
435                                        *p++ = *fp->f_p++;
436                                        if (--width == 0)
437                                                break;
438                                        if (fp->f_r <= 0 &&
439                                            sm_refill(fp, SM_TIME_FOREVER))
440                                        {
441                                                if (p == p0)
442                                                        goto input_failure;
443                                                break;
444                                        }
445                                }
446                                n = p - p0;
447                                if (n == 0)
448                                        goto match_failure;
449                                *p = 0;
450                                nassigned++;
451                        }
452                        nread += n;
453                        break;
454
455                  case CT_STRING:
456                        /* like CCL, but zero-length string OK, & no NOSKIP */
457                        if (width == 0)
458                                width = (size_t)~0;
459                        if (flags & SUPPRESS)
460                        {
461                                n = 0;
462                                while (!isspace(*fp->f_p))
463                                {
464                                        n++, fp->f_r--, fp->f_p++;
465                                        if (--width == 0)
466                                                break;
467                                        if (fp->f_r <= 0 &&
468                                            sm_refill(fp, SM_TIME_FOREVER))
469                                                break;
470                                }
471                                nread += n;
472                        }
473                        else
474                        {
475                                p0 = p = SM_VA_ARG(ap, char *);
476                                while (!isspace(*fp->f_p))
477                                {
478                                        fp->f_r--;
479                                        *p++ = *fp->f_p++;
480                                        if (--width == 0)
481                                                break;
482                                        if (fp->f_r <= 0 &&
483                                            sm_refill(fp, SM_TIME_FOREVER))
484                                                break;
485                                }
486                                *p = 0;
487                                nread += p - p0;
488                                nassigned++;
489                        }
490                        continue;
491
492                  case CT_INT:
493                        /* scan an integer as if by strtoll/strtoull */
494#if SM_CONF_BROKEN_SIZE_T
495                        if (width == 0 || width > sizeof(buf) - 1)
496                                width = sizeof(buf) - 1;
497#else /* SM_CONF_BROKEN_SIZE_T */
498                        /* size_t is unsigned, hence this optimisation */
499                        if (--width > sizeof(buf) - 2)
500                                width = sizeof(buf) - 2;
501                        width++;
502#endif /* SM_CONF_BROKEN_SIZE_T */
503                        flags |= SIGNOK | NDIGITS | NZDIGITS;
504                        for (p = buf; width > 0; width--)
505                        {
506                                c = *fp->f_p;
507
508                                /*
509                                **  Switch on the character; `goto ok'
510                                **  if we accept it as a part of number.
511                                */
512
513                                switch (c)
514                                {
515
516                                /*
517                                **  The digit 0 is always legal, but is
518                                **  special.  For %i conversions, if no
519                                **  digits (zero or nonzero) have been
520                                **  scanned (only signs), we will have
521                                **  base==0.  In that case, we should set
522                                **  it to 8 and enable 0x prefixing.
523                                **  Also, if we have not scanned zero digits
524                                **  before this, do not turn off prefixing
525                                **  (someone else will turn it off if we
526                                **  have scanned any nonzero digits).
527                                */
528
529                                  case '0':
530                                        if (base == 0)
531                                        {
532                                                base = 8;
533                                                flags |= PFXOK;
534                                        }
535                                        if (flags & NZDIGITS)
536                                            flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
537                                        else
538                                            flags &= ~(SIGNOK|PFXOK|NDIGITS);
539                                        goto ok;
540
541                                /* 1 through 7 always legal */
542                                  case '1': case '2': case '3':
543                                  case '4': case '5': case '6': case '7':
544                                        base = basefix[base];
545                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
546                                        goto ok;
547
548                                /* digits 8 and 9 ok iff decimal or hex */
549                                  case '8': case '9':
550                                        base = basefix[base];
551                                        if (base <= 8)
552                                                break;  /* not legal here */
553                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
554                                        goto ok;
555
556                                /* letters ok iff hex */
557                                  case 'A': case 'B': case 'C':
558                                  case 'D': case 'E': case 'F':
559                                  case 'a': case 'b': case 'c':
560                                  case 'd': case 'e': case 'f':
561
562                                        /* no need to fix base here */
563                                        if (base <= 10)
564                                                break;  /* not legal here */
565                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
566                                        goto ok;
567
568                                /* sign ok only as first character */
569                                  case '+': case '-':
570                                        if (flags & SIGNOK)
571                                        {
572                                                flags &= ~SIGNOK;
573                                                goto ok;
574                                        }
575                                        break;
576
577                                /* x ok iff flag still set & 2nd char */
578                                  case 'x': case 'X':
579                                        if (flags & PFXOK && p == buf + 1)
580                                        {
581                                                base = 16;      /* if %i */
582                                                flags &= ~PFXOK;
583                                                goto ok;
584                                        }
585                                        break;
586                                }
587
588                                /*
589                                **  If we got here, c is not a legal character
590                                **  for a number.  Stop accumulating digits.
591                                */
592
593                                break;
594                ok:
595                                /* c is legal: store it and look at the next. */
596                                *p++ = c;
597                                if (--fp->f_r > 0)
598                                        fp->f_p++;
599                                else if (sm_refill(fp, SM_TIME_FOREVER))
600                                        break;          /* SM_IO_EOF */
601                        }
602
603                        /*
604                        **  If we had only a sign, it is no good; push
605                        **  back the sign.  If the number ends in `x',
606                        **  it was [sign] '0' 'x', so push back the x
607                        **  and treat it as [sign] '0'.
608                        */
609
610                        if (flags & NDIGITS)
611                        {
612                                if (p > buf)
613                                        (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
614                                                            *(unsigned char *)--p);
615                                goto match_failure;
616                        }
617                        c = ((unsigned char *)p)[-1];
618                        if (c == 'x' || c == 'X')
619                        {
620                                --p;
621                                (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
622                        }
623                        if ((flags & SUPPRESS) == 0)
624                        {
625                                ULONGLONG_T res;
626
627                                *p = 0;
628                                res = (*ccfn)(buf, (char **)NULL, base);
629                                if (flags & POINTER)
630                                        *SM_VA_ARG(ap, void **) =
631                                            (void *)(long) res;
632                                else if (flags & QUAD)
633                                        *SM_VA_ARG(ap, LONGLONG_T *) = res;
634                                else if (flags & LONG)
635                                        *SM_VA_ARG(ap, long *) = res;
636                                else if (flags & SHORT)
637                                        *SM_VA_ARG(ap, short *) = res;
638                                else
639                                        *SM_VA_ARG(ap, int *) = res;
640                                nassigned++;
641                        }
642                        nread += p - buf;
643                        break;
644
645                  case CT_FLOAT:
646                        /* scan a floating point number as if by strtod */
647                        if (width == 0 || width > sizeof(buf) - 1)
648                                width = sizeof(buf) - 1;
649                        flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
650                        for (p = buf; width; width--)
651                        {
652                                c = *fp->f_p;
653
654                                /*
655                                **  This code mimicks the integer conversion
656                                **  code, but is much simpler.
657                                */
658
659                                switch (c)
660                                {
661
662                                  case '0': case '1': case '2': case '3':
663                                  case '4': case '5': case '6': case '7':
664                                  case '8': case '9':
665                                        flags &= ~(SIGNOK | NDIGITS);
666                                        goto fok;
667
668                                  case '+': case '-':
669                                        if (flags & SIGNOK)
670                                        {
671                                                flags &= ~SIGNOK;
672                                                goto fok;
673                                        }
674                                        break;
675                                  case '.':
676                                        if (flags & DPTOK)
677                                        {
678                                                flags &= ~(SIGNOK | DPTOK);
679                                                goto fok;
680                                        }
681                                        break;
682                                  case 'e': case 'E':
683
684                                        /* no exponent without some digits */
685                                        if ((flags&(NDIGITS|EXPOK)) == EXPOK)
686                                        {
687                                                flags =
688                                                    (flags & ~(EXPOK|DPTOK)) |
689                                                    SIGNOK | NDIGITS;
690                                                goto fok;
691                                        }
692                                        break;
693                                }
694                                break;
695                fok:
696                                *p++ = c;
697                                if (--fp->f_r > 0)
698                                        fp->f_p++;
699                                else if (sm_refill(fp, SM_TIME_FOREVER))
700                                        break;  /* SM_IO_EOF */
701                        }
702
703                        /*
704                        **  If no digits, might be missing exponent digits
705                        **  (just give back the exponent) or might be missing
706                        **  regular digits, but had sign and/or decimal point.
707                        */
708
709                        if (flags & NDIGITS)
710                        {
711                                if (flags & EXPOK)
712                                {
713                                        /* no digits at all */
714                                        while (p > buf)
715                                                (void) sm_io_ungetc(fp,
716                                                             SM_TIME_DEFAULT,
717                                                             *(unsigned char *)--p);
718                                        goto match_failure;
719                                }
720
721                                /* just a bad exponent (e and maybe sign) */
722                                c = *(unsigned char *) --p;
723                                if (c != 'e' && c != 'E')
724                                {
725                                        (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
726                                                            c); /* sign */
727                                        c = *(unsigned char *)--p;
728                                }
729                                (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
730                        }
731                        if ((flags & SUPPRESS) == 0)
732                        {
733                                double res;
734
735                                *p = 0;
736                                res = strtod(buf, (char **) NULL);
737                                if (flags & LONG)
738                                        *SM_VA_ARG(ap, double *) = res;
739                                else
740                                        *SM_VA_ARG(ap, float *) = res;
741                                nassigned++;
742                        }
743                        nread += p - buf;
744                        break;
745                }
746        }
747input_failure:
748        if (evt != NULL)
749                sm_clrevent(evt); /*  undo our timeout */
750        return nassigned ? nassigned : -1;
751match_failure:
752        if (evt != NULL)
753                sm_clrevent(evt); /*  undo our timeout */
754        return nassigned;
755}
756
757/*
758**  SM_SCCL -- sequenced character comparison list
759**
760**  Fill in the given table from the scanset at the given format
761**  (just after `[').  Return a pointer to the character past the
762**  closing `]'.  The table has a 1 wherever characters should be
763**  considered part of the scanset.
764**
765**      Parameters:
766**              tab -- array flagging "active" char's to match (returned)
767**              fmt -- character list (within "[]")
768**
769**      Results:
770*/
771
772static unsigned char *
773sm_sccl(tab, fmt)
774        register char *tab;
775        register unsigned char *fmt;
776{
777        register int c, n, v;
778
779        /* first `clear' the whole table */
780        c = *fmt++;             /* first char hat => negated scanset */
781        if (c == '^')
782        {
783                v = 1;          /* default => accept */
784                c = *fmt++;     /* get new first char */
785        }
786        else
787                v = 0;          /* default => reject */
788
789        /* should probably use memset here */
790        for (n = 0; n < 256; n++)
791                tab[n] = v;
792        if (c == 0)
793                return fmt - 1; /* format ended before closing ] */
794
795        /*
796        **  Now set the entries corresponding to the actual scanset
797        **  to the opposite of the above.
798        **
799        **  The first character may be ']' (or '-') without being special;
800        **  the last character may be '-'.
801        */
802
803        v = 1 - v;
804        for (;;)
805        {
806                tab[c] = v;             /* take character c */
807doswitch:
808                n = *fmt++;             /* and examine the next */
809                switch (n)
810                {
811
812                  case 0:                       /* format ended too soon */
813                        return fmt - 1;
814
815                  case '-':
816                        /*
817                        **  A scanset of the form
818                        **      [01+-]
819                        **  is defined as `the digit 0, the digit 1,
820                        **  the character +, the character -', but
821                        **  the effect of a scanset such as
822                        **      [a-zA-Z0-9]
823                        **  is implementation defined.  The V7 Unix
824                        **  scanf treats `a-z' as `the letters a through
825                        **  z', but treats `a-a' as `the letter a, the
826                        **  character -, and the letter a'.
827                        **
828                        **  For compatibility, the `-' is not considerd
829                        **  to define a range if the character following
830                        **  it is either a close bracket (required by ANSI)
831                        **  or is not numerically greater than the character
832                        **  we just stored in the table (c).
833                        */
834
835                        n = *fmt;
836                        if (n == ']' || n < c)
837                        {
838                                c = '-';
839                                break;  /* resume the for(;;) */
840                        }
841                        fmt++;
842                        do
843                        {
844                                /* fill in the range */
845                                tab[++c] = v;
846                        } while (c < n);
847#if 1   /* XXX another disgusting compatibility hack */
848
849                        /*
850                        **  Alas, the V7 Unix scanf also treats formats
851                        **  such as [a-c-e] as `the letters a through e'.
852                        **  This too is permitted by the standard....
853                        */
854
855                        goto doswitch;
856#else
857                        c = *fmt++;
858                        if (c == 0)
859                                return fmt - 1;
860                        if (c == ']')
861                                return fmt;
862                        break;
863#endif
864
865                  case ']':             /* end of scanset */
866                        return fmt;
867
868                  default:              /* just another character */
869                        c = n;
870                        break;
871                }
872        }
873        /* NOTREACHED */
874}
Note: See TracBrowser for help on using the repository browser.