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