]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libstdio/vfscanf.c
kernel: clear FPillegal in pexit() and before pprint()
[plan9front.git] / sys / src / libstdio / vfscanf.c
1 /*
2  * pANS stdio -- vfscanf
3  */
4 #include "iolib.h"
5 #include <ctype.h>
6 static int icvt_f(FILE *f, va_list *args, int store, int width, int type);
7 static int icvt_x(FILE *f, va_list *args, int store, int width, int type);
8 static int icvt_sq(FILE *f, va_list *args, int store, int width, int type);
9 static int icvt_c(FILE *f, va_list *args, int store, int width, int type);
10 static int icvt_d(FILE *f, va_list *args, int store, int width, int type);
11 static int icvt_i(FILE *f, va_list *args, int store, int width, int type);
12 static int icvt_n(FILE *f, va_list *args, int store, int width, int type);
13 static int icvt_o(FILE *f, va_list *args, int store, int width, int type);
14 static int icvt_p(FILE *f, va_list *args, int store, int width, int type);
15 static int icvt_s(FILE *f, va_list *args, int store, int width, int type);
16 static int icvt_u(FILE *f, va_list *args, int store, int width, int type);
17 static int (*icvt[])(FILE *, va_list *, int, int, int)={
18 0,      0,      0,      0,      0,      0,      0,      0,      /* ^@ ^A ^B ^C ^D ^E ^F ^G */
19 0,      0,      0,      0,      0,      0,      0,      0,      /* ^H ^I ^J ^K ^L ^M ^N ^O */
20 0,      0,      0,      0,      0,      0,      0,      0,      /* ^P ^Q ^R ^S ^T ^U ^V ^W */
21 0,      0,      0,      0,      0,      0,      0,      0,      /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
22 0,      0,      0,      0,      0,      0,      0,      0,      /* sp  !  "  #  $  %  &  ' */
23 0,      0,      0,      0,      0,      0,      0,      0,      /*  (  )  *  +  ,  -  .  / */
24 0,      0,      0,      0,      0,      0,      0,      0,      /*  0  1  2  3  4  5  6  7 */
25 0,      0,      0,      0,      0,      0,      0,      0,      /*  8  9  :  ;  <  =  >  ? */
26 0,      0,      0,      0,      0,      icvt_f, 0,      icvt_f, /*  @  A  B  C  D  E  F  G */
27 0,      0,      0,      0,      0,      0,      0,      0,      /*  H  I  J  K  L  M  N  O */
28 0,      0,      0,      0,      0,      0,      0,      0,      /*  P  Q  R  S  T  U  V  W */
29 icvt_x, 0,      0,      icvt_sq,0,      0,      0,      0,      /*  X  Y  Z  [  \  ]  ^  _ */
30 0,      0,      0,      icvt_c, icvt_d, icvt_f, icvt_f, icvt_f, /*  `  a  b  c  d  e  f  g */
31 0,      icvt_i, 0,      0,      0,      0,      icvt_n, icvt_o, /*  h  i  j  k  l  m  n  o */
32 icvt_p, 0,      0,      icvt_s, 0,      icvt_u, 0,      0,      /*  p  q  r  s  t  u  v  w */
33 icvt_x, 0,      0,      0,      0,      0,      0,      0,      /*  x  y  z  {  |  }  ~ ^? */
34
35 0,      0,      0,      0,      0,      0,      0,      0,
36 0,      0,      0,      0,      0,      0,      0,      0,
37 0,      0,      0,      0,      0,      0,      0,      0,
38 0,      0,      0,      0,      0,      0,      0,      0,
39 0,      0,      0,      0,      0,      0,      0,      0,
40 0,      0,      0,      0,      0,      0,      0,      0,
41 0,      0,      0,      0,      0,      0,      0,      0,
42 0,      0,      0,      0,      0,      0,      0,      0,
43 0,      0,      0,      0,      0,      0,      0,      0,
44 0,      0,      0,      0,      0,      0,      0,      0,
45 0,      0,      0,      0,      0,      0,      0,      0,
46 0,      0,      0,      0,      0,      0,      0,      0,
47 0,      0,      0,      0,      0,      0,      0,      0,
48 0,      0,      0,      0,      0,      0,      0,      0,
49 0,      0,      0,      0,      0,      0,      0,      0,
50 0,      0,      0,      0,      0,      0,      0,      0,
51
52 };
53 #define ngetc(f)                (nread++, getc(f))
54 #define nungetc(c, f)           (--nread, ungetc((c), f))
55 #define wgetc(c, f, out)        if(width--==0) goto out; (c)=ngetc(f)
56 #define wungetc(c, f)           (++width, nungetc(c, f))
57 static int nread, ncvt;
58 static const char *fmtp;
59
60 int vfscanf(FILE *f, const char *s, va_list args){
61         int c, width, type, store;
62         nread=0;
63         ncvt=0;
64         fmtp=s;
65         for(;*fmtp;fmtp++) switch(*fmtp){
66         default:
67                 if(isspace(*fmtp)){
68                         do
69                                 c=ngetc(f);
70                         while(isspace(c));
71                         if(c==EOF) return ncvt?ncvt:EOF;
72                         nungetc(c, f);
73                         break;
74                 }
75         NonSpecial:
76                 c=ngetc(f);
77                 if(c==EOF) return ncvt?ncvt:EOF;
78                 if(c!=*fmtp){
79                         nungetc(c, f);
80                         return ncvt;
81                 }
82                 break;
83         case '%':
84                 fmtp++;
85                 if(*fmtp!='*') store=1;
86                 else{
87                         store=0;
88                         fmtp++;
89                 }
90                 if('0'<=*fmtp && *fmtp<='9'){
91                         width=0;
92                         while('0'<=*fmtp && *fmtp<='9') width=width*10 + *fmtp++ - '0';
93                 }
94                 else
95                         width=-1;
96                 type=*fmtp=='h' || *fmtp=='l' || *fmtp=='L'?*fmtp++:'n';
97                 if(!icvt[*fmtp]) goto NonSpecial;
98                 if(!(*icvt[*fmtp])(f, &args, store, width, type))
99                         return ncvt?ncvt:EOF;
100                 if(*fmtp=='\0') break;
101                 if(store) ncvt++;
102         }
103         return ncvt;    
104 }
105 static int icvt_n(FILE *f, va_list *args, int store, int width, int type){
106 #pragma ref f
107 #pragma ref width
108         if(store){
109                 --ncvt; /* this assignment doesn't count! */
110                 switch(type){
111                 case 'h': *va_arg(*args, short *)=nread; break;
112                 case 'n': *va_arg(*args, int *)=nread; break;
113                 case 'l':
114                 case 'L': *va_arg(*args, long *)=nread; break;
115                 }
116         }
117         return 1;
118 }
119 #define SIGNED          1
120 #define UNSIGNED        2
121 #define POINTER         3
122 /*
123  * Generic fixed-point conversion
124  *      f is the input FILE *;
125  *      args is the va_list * into which to store the number;
126  *      store is a flag to enable storing;
127  *      width is the maximum field width;
128  *      type is 'h' 'l' or 'L', the scanf type modifier;
129  *      unsgned is SIGNED, UNSIGNED or POINTER, giving part of the type to store in;
130  *      base is the number base -- if 0, C number syntax is used.
131  */
132 static int icvt_fixed(FILE *f, va_list *args,
133                                 int store, int width, int type, int unsgned, int base){
134         unsigned long int num=0;
135         int sign=1, ndig=0, dig;
136         int c;
137         do
138                 c=ngetc(f);
139         while(isspace(c));
140         if(width--==0){
141                 nungetc(c, f);
142                 goto Done;
143         }
144         if(c=='+'){
145                 wgetc(c, f, Done);
146         }
147         else if(c=='-'){
148                 sign=-1;
149                 wgetc(c, f, Done);
150         }
151         switch(base){
152         case 0:
153                 if(c=='0'){
154                         wgetc(c, f, Done);
155                         if(c=='x' || c=='X'){
156                                 wgetc(c, f, Done);
157                                 base=16;
158                         }
159                         else{
160                                 ndig=1;
161                                 base=8;
162                         }
163                 }
164                 else
165                         base=10;
166                 break;
167         case 16:
168                 if(c=='0'){
169                         wgetc(c, f, Done);
170                         if(c=='x' || c=='X'){
171                                 wgetc(c, f, Done);
172                         }
173                         else ndig=1;
174                 }
175                 break;
176         }
177         while('0'<=c && c<='9' || 'a'<=c && c<='f' || 'A'<=c && c<='F'){
178                 dig='0'<=c && c<='9'?c-'0':'a'<=c && c<='f'?c-'a'+10:c-'A'+10;
179                 if(dig>=base) break;
180                 ndig++;
181                 num=num*base+dig;
182                 wgetc(c, f, Done);
183         }
184         nungetc(c, f);
185 Done:
186         if(ndig==0) return 0;
187         if(store){
188                 switch(unsgned){
189                 case SIGNED:
190                         switch(type){
191                         case 'h': *va_arg(*args,  short *)=num*sign; break;
192                         case 'n': *va_arg(*args,  int *)=num*sign; break;
193                         case 'l':
194                         case 'L': *va_arg(*args,  long *)=num*sign; break;
195                         }
196                         break;
197                 case UNSIGNED:
198                         switch(type){
199                         case 'h': *va_arg(*args, unsigned short *)=num*sign; break;
200                         case 'n': *va_arg(*args, unsigned int *)=num*sign; break;
201                         case 'l':
202                         case 'L': *va_arg(*args, unsigned long *)=num*sign; break;
203                         }
204                         break;
205                 case POINTER:
206                         *va_arg(*args, void **)=(void *)(num*sign); break;
207                 }
208         }
209         return 1;
210 }
211 static int icvt_d(FILE *f, va_list *args, int store, int width, int type){
212         return icvt_fixed(f, args, store, width, type, SIGNED, 10);
213 }
214 static int icvt_x(FILE *f, va_list *args, int store, int width, int type){
215         return icvt_fixed(f, args, store, width, type, UNSIGNED, 16);
216 }
217 static int icvt_o(FILE *f, va_list *args, int store, int width, int type){
218         return icvt_fixed(f, args, store, width, type, UNSIGNED, 8);
219 }
220 static int icvt_i(FILE *f, va_list *args, int store, int width, int type){
221         return icvt_fixed(f, args, store, width, type, SIGNED, 0);
222 }
223 static int icvt_u(FILE *f, va_list *args, int store, int width, int type){
224         return icvt_fixed(f, args, store, width, type, UNSIGNED, 10);
225 }
226 static int icvt_p(FILE *f, va_list *args, int store, int width, int type){
227         return icvt_fixed(f, args, store, width, type, POINTER, 16);
228 }
229 #define NBUF    509
230 static int icvt_f(FILE *f, va_list *args, int store, int width, int type){
231         char buf[NBUF+1];
232         char *s=buf;
233         int c, ndig=0, ndpt=0, nexp=1;
234         if(width<0 || NBUF<width) width=NBUF;   /* bug -- no limit specified in ansi */
235         do
236                 c=ngetc(f);
237         while(isspace(c));
238         if(width--==0){
239                 nungetc(c, f);
240                 goto Done;
241         }
242         if(c=='+' || c=='-'){
243                 *s++=c;
244                 wgetc(c, f, Done);
245         }
246         while('0'<=c && c<='9' || ndpt==0 && c=='.'){
247                 if(c=='.') ndpt++;
248                 else ndig++;
249                 *s++=c;
250                 wgetc(c, f, Done);
251         }
252         if(c=='e' || c=='E'){
253                 *s++=c;
254                 nexp=0;
255                 wgetc(c, f, Done);
256                 if(c=='+' || c=='-'){
257                         *s++=c;
258                         wgetc(c, f, Done);
259                 }
260                 while('0'<=c && c<='9'){
261                         *s++=c;
262                         nexp++;
263                         wgetc(c, f, Done);
264                 }
265         }
266         nungetc(c, f);
267 Done:
268         if(ndig==0 || nexp==0) return 0;
269         *s='\0';
270         if(store) switch(type){
271         case 'h':
272         case 'n': *va_arg(*args, float *)=atof(buf); break;
273         case 'L': /* bug -- should store in a long double */
274         case 'l': *va_arg(*args, double *)=atof(buf); break;
275         }
276         return 1;
277 }
278 static int icvt_s(FILE *f, va_list *args, int store, int width, int type){
279 #pragma ref type
280         int c, nn;
281         register char *s;
282         if(store) s=va_arg(*args, char *);
283         do
284                 c=ngetc(f);
285         while(isspace(c));
286         if(width--==0){
287                 nungetc(c, f);
288                 goto Done;
289         }
290         nn=0;
291         while(!isspace(c)){
292                 if(c==EOF){
293                         nread--;
294                         if(nn==0) return 0;
295                         else goto Done;
296                 }
297                 nn++;
298                 if(store) *s++=c;
299                 wgetc(c, f, Done);
300         }
301         nungetc(c, f);
302 Done:
303         if(store) *s='\0';
304         return 1;
305 }
306 static int icvt_c(FILE *f, va_list *args, int store, int width, int type){
307 #pragma ref type
308         int c;
309         register char *s;
310         if(store) s=va_arg(*args, char *);
311         if(width<0) width=1;
312         for(;;){
313                 wgetc(c, f, Done);
314                 if(c==EOF) return 0;
315                 if(store) *s++=c;
316         }
317 Done:
318         return 1;
319 }
320 static int match(int c, const char *pat){
321         int ok=1;
322         if(*pat=='^'){
323                 ok=!ok;
324                 pat++;
325         }
326         while(pat!=fmtp){
327                 if(pat+2<fmtp && pat[1]=='-'){
328                         if(pat[0]<=c && c<=pat[2]
329                         || pat[2]<=c && c<=pat[0])
330                                 return ok;
331                         pat+=2;
332                 }
333                 else if(c==*pat) return ok;
334                 pat++;
335         }
336         return !ok;
337 }
338 static int icvt_sq(FILE *f, va_list *args, int store, int width, int type){
339 #pragma ref type
340         int c, nn;
341         register char *s;
342         register const char *pat;
343         pat=++fmtp;
344         if(*fmtp=='^') fmtp++;
345         if(*fmtp!='\0') fmtp++;
346         while(*fmtp!='\0' && *fmtp!=']') fmtp++;
347         if(store) s=va_arg(*args, char *);
348         nn=0;
349         for(;;){
350                 wgetc(c, f, Done);
351                 if(c==EOF){
352                         nread--;
353                         if(nn==0) return 0;
354                         else goto Done;
355                 }
356                 if(!match(c, pat)) break;
357                 if(store) *s++=c;
358                 nn++;
359         }
360         nungetc(c, f);
361 Done:
362         if(store) *s='\0';
363         return 1;
364 }