:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / lib / crtdll / stdio / doscan.c
1 /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */
2 /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
3 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
4 #include <crtdll/stdio.h>
5 #include <crtdll/stdlib.h>
6 #include <crtdll/ctype.h>
7 #include <crtdll/internal/file.h>
8
9
10 #define atold   atof
11
12 // dubious variable 
13 //static int _fltused = 0;
14
15 int
16 _doscan_low(FILE *iop, int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *),
17             const char *fmt, va_list argp);
18
19 //#include <crtdll/local.h>
20
21 #define SPC     01
22 #define STP     02
23
24 #define SHORT   0
25 #define REGULAR 1
26 #define LONG    2
27 #define LONGDOUBLE 4
28 #define INT     0
29 #define FLOAT   1
30
31
32
33 static int _innum(int **ptr, int type, int len, int size, FILE *iop, 
34                   int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), 
35                   int *eofptr);
36 static int _instr(char *ptr, int type, int len, FILE *iop, 
37                   int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), 
38                   int *eofptr);
39 static const char *_getccl(const unsigned char *s);
40
41 static char _sctab[256] = {
42         0,0,0,0,0,0,0,0,
43         0,SPC,SPC,SPC,SPC,SPC,0,0,
44         0,0,0,0,0,0,0,0,
45         0,0,0,0,0,0,0,0,
46         SPC,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 };
51
52 static int nchars = 0;
53
54 int 
55 _doscan(FILE *iop, const char *fmt, va_list argp)
56 {
57   return(_doscan_low(iop, fgetc, ungetc, fmt, argp));
58 }
59
60 int 
61 _dowscan(FILE *iop, const wchar_t *fmt, va_list argp)
62 {
63   return(_doscan_low(iop, fgetwc, ((void *)ungetwc), ((void *)fmt), argp));
64 }
65
66 int
67 _doscan_low(FILE *iop, int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *),
68             const char *fmt, va_list argp)
69 {
70   register int ch;
71   int nmatch, len, ch1;
72   int **ptr, fileended, size;
73
74   nchars = 0;
75   nmatch = 0;
76   fileended = 0;
77   for (;;) switch (ch = *fmt++) {
78   case '\0': 
79     return (nmatch);
80   case '%':
81     if ((ch = *fmt++) == '%')
82       goto def;
83     ptr = 0;
84     if (ch != '*')
85         ptr = va_arg(argp, int **);
86     else
87       ch = *fmt++;
88     len = 0;
89     size = REGULAR;
90     while (isdigit(ch)) {
91       len = len*10 + ch - '0';
92       ch = *fmt++;
93     }
94     if (len == 0)
95       len = 30000;
96     
97     if (ch=='l') 
98     {
99       size = LONG;
100       ch = *fmt++;
101       if (ch=='l')
102       {
103         size = LONGDOUBLE; /* for long long 'll' format */
104         ch = *fmt++;
105       }
106     }
107     else if (ch=='h') {
108       size = SHORT;
109       ch = *fmt++;
110     } else if (ch=='L') {
111       size = LONGDOUBLE;
112       ch = *fmt++;
113     } else if (ch=='[')
114       fmt = _getccl((const unsigned char *)fmt);
115     if (isupper(ch)) {
116       /* ch = tolower(ch);
117          gcc gives warning: ANSI C forbids braced
118          groups within expressions */
119       ch += 'a' - 'A';
120       if (size==LONG)
121         size = LONGDOUBLE;
122       else if (size != LONGDOUBLE)
123         size = LONG;
124     }
125     if (ch == '\0')
126       return(-1);
127
128     if (ch == 'n')
129     {
130       if (!ptr)
131         break;
132       if (size==LONG)
133         **(long**)ptr = nchars;
134       else if (size==SHORT)
135         **(short**)ptr = nchars;
136       else if (size==LONGDOUBLE)
137         **(long**)ptr = nchars;
138       else
139         **(int**)ptr = nchars;
140       break;
141     }
142       
143     if (_innum(ptr, ch, len, size, iop, scan_getc, scan_ungetc,
144                &fileended))
145     {
146       if (ptr)
147         nmatch++;
148     }
149     else
150     {
151       if (fileended && nmatch==0)
152         return(-1);
153       return(nmatch);
154     }
155     break;
156   case ' ':
157   case '\n':
158   case '\t': 
159   case '\r':
160   case '\f':
161   case '\v':
162     while (((nchars++, ch1 = scan_getc(iop))!=EOF) && (_sctab[ch1] & SPC))
163       ;
164     if (ch1 != EOF)
165     {
166       scan_ungetc(ch1, iop);
167     }
168     nchars--;
169     break;
170
171   default:
172   def:
173     ch1 = scan_getc(iop);
174     if (ch1 != EOF) nchars++;
175     if (ch1 != ch) {
176       if (ch1==EOF)
177         return(nmatch? nmatch: -1);
178       scan_ungetc(ch1, iop);
179       nchars--;
180       return(nmatch);
181     }
182   }
183 }
184
185 static int
186 _innum(int **ptr, int type, int len, int size, FILE *iop,
187        int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), int *eofptr)
188 {
189   register char *np;
190   char numbuf[64];
191   register int c, base;
192   int expseen, scale, negflg, c1, ndigit;
193   long lcval;
194   int cpos;
195
196   if (type=='c' || type=='s' || type=='[')
197     return(_instr(ptr? *(char **)ptr: (char *)NULL, type, len,
198                   iop, scan_getc, scan_ungetc, eofptr));
199   lcval = 0;
200   ndigit = 0;
201   scale = INT;
202   if (type=='e'||type=='f'||type=='g')
203     scale = FLOAT;
204   base = 10;
205   if (type=='o')
206     base = 8;
207   else if (type=='x')
208     base = 16;
209   np = numbuf;
210   expseen = 0;
211   negflg = 0;
212   while (((nchars++, c = scan_getc(iop)) != EOF)  && (_sctab[c] & SPC) )
213     ;
214   if (c == EOF) nchars--;
215   if (c=='-') {
216     negflg++;
217     *np++ = c;
218     c = scan_getc(iop);
219     nchars++;
220     len--;
221   } else if (c=='+') {
222     len--;
223     c = scan_getc(iop);
224     nchars++;
225   }
226   cpos = 0;
227   for ( ; --len>=0; *np++ = c, c = scan_getc(iop), nchars++) {
228     cpos++;
229     if (c == '0' && cpos == 1 && type == 'i')
230       base = 8;
231     if ((c == 'x' || c == 'X') && (type == 'i' || type == 'x')
232         && cpos == 2 && lcval == 0)
233     {
234       base = 16;
235       continue;
236     }
237     if (isdigit(c)
238         || (base==16 && (('a'<=c && c<='f') || ('A'<=c && c<='F')))) {
239       ndigit++;
240       if (base==8)
241         lcval <<=3;
242       else if (base==10)
243         lcval = ((lcval<<2) + lcval)<<1;
244       else
245         lcval <<= 4;
246       c1 = c;
247       if (isdigit(c))
248         c -= '0';
249       else if ('a'<=c && c<='f')
250         c -= 'a'-10;
251       else
252         c -= 'A'-10;
253       lcval += c;
254       c = c1;
255       continue;
256     } else if (c=='.') {
257       if (base!=10 || scale==INT)
258         break;
259       ndigit++;
260       continue;
261     } else if ((c=='e'||c=='E') && expseen==0) {
262       if (base!=10 || scale==INT || ndigit==0)
263         break;
264       expseen++;
265       *np++ = c;
266       c = scan_getc(iop);
267       nchars++;
268       if (c!='+'&&c!='-'&&('0'>c||c>'9'))
269         break;
270     } else
271       break;
272   }
273   if (negflg)
274     lcval = -lcval;
275   if (c != EOF) {
276     scan_ungetc(c, iop);
277     *eofptr = 0;
278   } else
279     *eofptr = 1;
280   nchars--;
281   if (np==numbuf || (negflg && np==numbuf+1) ) /* gene dykes*/
282     return(0);
283   if (ptr==NULL)
284     return(1);
285   *np++ = 0;
286   switch((scale<<4) | size) {
287
288   case (FLOAT<<4) | SHORT:
289   case (FLOAT<<4) | REGULAR:
290     **(float **)ptr = (float)atof(numbuf);
291     break;
292
293   case (FLOAT<<4) | LONG:
294     **(double **)ptr = atof(numbuf);
295     break;
296
297   case (FLOAT<<4) | LONGDOUBLE:
298     **(long double **)ptr = atold(numbuf);
299     break;
300
301   case (INT<<4) | SHORT:
302     **(short **)ptr = (short)lcval;
303     break;
304
305   case (INT<<4) | REGULAR:
306     **(int **)ptr = (int)lcval;
307     break;
308
309   case (INT<<4) | LONG:
310     **(long **)ptr = lcval;
311     break;
312
313   case (INT<<4) | LONGDOUBLE:
314     **(long **)ptr = lcval;
315     break;
316   }
317   return(1);
318 }
319
320 static int
321 _instr(char *ptr, int type, int len, FILE *iop,
322        int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), int *eofptr)
323 {
324   register int ch;
325   register char *optr;
326   int ignstp;
327
328   *eofptr = 0;
329   optr = ptr;
330   if (type=='c' && len==30000)
331     len = 1;
332   ignstp = 0;
333   if (type=='s')
334     ignstp = SPC;
335   while ((nchars++, ch = scan_getc(iop)) != EOF && _sctab[ch] & ignstp)
336     ;
337   ignstp = SPC;
338   if (type=='c')
339     ignstp = 0;
340   else if (type=='[')
341     ignstp = STP;
342   while (ch!=EOF && (_sctab[ch]&ignstp)==0) {
343     if (ptr)
344       *ptr++ = ch;
345     if (--len <= 0)
346       break;
347     ch = scan_getc(iop);
348     nchars++;
349   }
350   if (ch != EOF) {
351     if (len > 0)
352     {
353       scan_ungetc(ch, iop);
354       nchars--;
355     }
356     *eofptr = 0;
357   } else
358   {
359     nchars--;
360     *eofptr = 1;
361   }
362   if (!ptr)
363     return(1);
364   if (ptr!=optr) {
365     if (type!='c')
366       *ptr++ = '\0';
367     return(1);
368   }
369   return(0);
370 }
371
372 static const char *
373 _getccl(const unsigned char *s)
374 {
375   register int c, t;
376
377   t = 0;
378   if (*s == '^') {
379     t++;
380     s++;
381   }
382   for (c = 0; c < (sizeof _sctab / sizeof _sctab[0]); c++)
383     if (t)
384       _sctab[c] &= ~STP;
385     else
386       _sctab[c] |= STP;
387   if ((c = *s) == ']' || c == '-') { /* first char is special */
388     if (t)
389       _sctab[c] |= STP;
390     else
391       _sctab[c] &= ~STP;
392     s++;
393   }
394   while ((c = *s++) != ']') {
395     if (c==0)
396       return((const char *)--s);
397     else if (c == '-' && *s != ']' && s[-2] < *s) {
398       for (c = s[-2] + 1; c < *s; c++)
399         if (t)
400           _sctab[c] |= STP;
401         else
402           _sctab[c] &= ~STP;
403     } else if (t)
404       _sctab[c] |= STP;
405     else
406       _sctab[c] &= ~STP;
407   }
408   return((const char *)s);
409 }