1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * and/or other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18 /* Split from vfscanf.c */
19
20 #define _DEFAULT_SOURCE
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include "local.h"
24
25 /*
26 * Fill in the given table from the scanset at the given format
27 * (just after `['). Return a pointer to the character past the
28 * closing `]'. The table has a 1 wherever characters should be
29 * considered part of the scanset.
30 */
31
32 u_char *
__sccl(register char * tab,register u_char * fmt)33 __sccl (register char *tab,
34 register u_char *fmt)
35 {
36 register int c, n, v;
37
38 /* first `clear' the whole table */
39 c = *fmt++; /* first char hat => negated scanset */
40 if (c == '^')
41 {
42 v = 1; /* default => accept */
43 c = *fmt++; /* get new first char */
44 }
45 else
46 v = 0; /* default => reject */
47 /* should probably use memset here */
48 for (n = 0; n < 256; n++)
49 tab[n] = v;
50 if (c == 0)
51 return fmt - 1; /* format ended before closing ] */
52
53 /*
54 * Now set the entries corresponding to the actual scanset to the
55 * opposite of the above.
56 *
57 * The first character may be ']' (or '-') without being special; the
58 * last character may be '-'.
59 */
60
61 v = 1 - v;
62 for (;;)
63 {
64 tab[c] = v; /* take character c */
65 doswitch:
66 n = *fmt++; /* and examine the next */
67 switch (n)
68 {
69
70 case 0: /* format ended too soon */
71 return fmt - 1;
72
73 case '-':
74 /*
75 * A scanset of the form [01+-] is defined as `the digit 0, the
76 * digit 1, the character +, the character -', but the effect of a
77 * scanset such as [a-zA-Z0-9] is implementation defined. The V7
78 * Unix scanf treats `a-z' as `the letters a through z', but treats
79 * `a-a' as `the letter a, the character -, and the letter a'.
80 *
81 * For compatibility, the `-' is not considerd to define a range if
82 * the character following it is either a close bracket (required by
83 * ANSI) or is not numerically greater than the character we just
84 * stored in the table (c).
85 */
86 n = *fmt;
87 if (n == ']' || n < c)
88 {
89 c = '-';
90 break; /* resume the for(;;) */
91 }
92 fmt++;
93 do
94 { /* fill in the range */
95 tab[++c] = v;
96 }
97 while (c < n);
98 #if 1 /* XXX another disgusting compatibility hack */
99 /*
100 * Alas, the V7 Unix scanf also treats formats such
101 * as [a-c-e] as `the letters a through e'. This too
102 * is permitted by the standard....
103 */
104 goto doswitch;
105 #else
106 c = *fmt++;
107 if (c == 0)
108 return fmt - 1;
109 if (c == ']')
110 return fmt;
111 #endif
112
113 break;
114
115
116 case ']': /* end of scanset */
117 return fmt;
118
119 default: /* just another character */
120 c = n;
121 break;
122 }
123 }
124 /* NOTREACHED */
125 }
126