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