1 /*
2 * Copyright (c) 2003, 2007-14 Matteo Frigo
3 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21
22 #include "kernel/ifftw.h"
23 #include <string.h>
24 #include <stddef.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #ifdef USE_CTYPE
29 #include <ctype.h>
30 #else
31 /* Screw ctype. On linux, the is* functions call a routine that gets
32 the ctype map in the current locale. Because this operation is
33 expensive, the map is cached on a per-thread basis. I am not
34 willing to link this crap with FFTW. Not over my dead body.
35
36 Sic transit gloria mundi.
37 */
38 #undef isspace
39 #define isspace(x) ((x) >= 0 && (x) <= ' ')
40 #undef isdigit
41 #define isdigit(x) ((x) >= '0' && (x) <= '9')
42 #undef isupper
43 #define isupper(x) ((x) >= 'A' && (x) <= 'Z')
44 #undef islower
45 #define islower(x) ((x) >= 'a' && (x) <= 'z')
46 #endif
47
mygetc(scanner * sc)48 static int mygetc(scanner *sc)
49 {
50 if (sc->ungotc != EOF) {
51 int c = sc->ungotc;
52 sc->ungotc = EOF;
53 return c;
54 }
55 return(sc->getchr(sc));
56 }
57
58 #define GETCHR(sc) mygetc(sc)
59
myungetc(scanner * sc,int c)60 static void myungetc(scanner *sc, int c)
61 {
62 sc->ungotc = c;
63 }
64
65 #define UNGETCHR(sc, c) myungetc(sc, c)
66
eat_blanks(scanner * sc)67 static void eat_blanks(scanner *sc)
68 {
69 int ch;
70 while (ch = GETCHR(sc), isspace(ch))
71 ;
72 UNGETCHR(sc, ch);
73 }
74
mygets(scanner * sc,char * s,int maxlen)75 static void mygets(scanner *sc, char *s, int maxlen)
76 {
77 char *s0 = s;
78 int ch;
79
80 A(maxlen > 0);
81 while ((ch = GETCHR(sc)) != EOF && !isspace(ch)
82 && ch != ')' && ch != '(' && s < s0 + maxlen)
83 *s++ = (char)(ch & 0xFF);
84 *s = 0;
85 UNGETCHR(sc, ch);
86 }
87
getlong(scanner * sc,int base,int * ret)88 static long getlong(scanner *sc, int base, int *ret)
89 {
90 int sign = 1, ch, count;
91 long x = 0;
92
93 ch = GETCHR(sc);
94 if (ch == '-' || ch == '+') {
95 sign = ch == '-' ? -1 : 1;
96 ch = GETCHR(sc);
97 }
98 for (count = 0; ; ++count) {
99 if (isdigit(ch))
100 ch -= '0';
101 else if (isupper(ch))
102 ch -= 'A' - 10;
103 else if (islower(ch))
104 ch -= 'a' - 10;
105 else
106 break;
107 x = x * base + ch;
108 ch = GETCHR(sc);
109 }
110 x *= sign;
111 UNGETCHR(sc, ch);
112 *ret = count > 0;
113 return x;
114 }
115
116 /* vscan is mostly scanf-like, with our additional format specifiers,
117 but with a few twists. It returns simply 0 or 1 indicating whether
118 the match was successful. '(' and ')' in the format string match
119 those characters preceded by any whitespace. Finally, if a
120 character match fails, it will ungetchr() the last character back
121 onto the stream. */
vscan(scanner * sc,const char * format,va_list ap)122 static int vscan(scanner *sc, const char *format, va_list ap)
123 {
124 const char *s = format;
125 char c;
126 int ch = 0;
127 int fmt_len;
128
129 while ((c = *s++)) {
130 fmt_len = 0;
131 switch (c) {
132 case '%':
133 getformat:
134 switch ((c = *s++)) {
135 case 's': {
136 char *x = va_arg(ap, char *);
137 mygets(sc, x, fmt_len);
138 break;
139 }
140 case 'd': {
141 int *x = va_arg(ap, int *);
142 *x = (int) getlong(sc, 10, &ch);
143 if (!ch) return 0;
144 break;
145 }
146 case 'x': {
147 int *x = va_arg(ap, int *);
148 *x = (int) getlong(sc, 16, &ch);
149 if (!ch) return 0;
150 break;
151 }
152 case 'M': {
153 md5uint *x = va_arg(ap, md5uint *);
154 *x = (md5uint)
155 (0xFFFFFFFF & getlong(sc, 16, &ch));
156 if (!ch) return 0;
157 break;
158 }
159 case '*': {
160 if ((fmt_len = va_arg(ap, int)) <= 0) return 0;
161 goto getformat;
162 }
163 default:
164 A(0 /* unknown format */);
165 break;
166 }
167 break;
168 default:
169 if (isspace(c) || c == '(' || c == ')')
170 eat_blanks(sc);
171 if (!isspace(c) && (ch = GETCHR(sc)) != c) {
172 UNGETCHR(sc, ch);
173 return 0;
174 }
175 break;
176 }
177 }
178 return 1;
179 }
180
scan(scanner * sc,const char * format,...)181 static int scan(scanner *sc, const char *format, ...)
182 {
183 int ret;
184 va_list ap;
185 va_start(ap, format);
186 ret = vscan(sc, format, ap);
187 va_end(ap);
188 return ret;
189 }
190
X(mkscanner)191 scanner *X(mkscanner)(size_t size, int (*getchr)(scanner *sc))
192 {
193 scanner *s = (scanner *)MALLOC(size, OTHER);
194 s->scan = scan;
195 s->vscan = vscan;
196 s->getchr = getchr;
197 s->ungotc = EOF;
198 return s;
199 }
200
X(scanner_destroy)201 void X(scanner_destroy)(scanner *sc)
202 {
203 X(ifree)(sc);
204 }
205