source: trunk/sys/dietlibc/__v_scanf.c @ 76

Last change on this file since 76 was 1, checked in by alain, 7 years ago

First import

File size: 8.0 KB
Line 
1#include "dietfeatures.h"
2#include <stdarg.h>
3#include <ctype.h>
4#include <stdlib.h>
5#include <string.h>
6#include <limits.h>
7
8#include "dietstdio.h"
9#include "dietwarning.h"
10
11#define A_GETC(fn)      (++consumed,(fn)->getch((fn)->data))
12#define A_PUTC(c,fn)    (--consumed,(fn)->putch((c),(fn)->data))
13
14int __v_scanf(struct arg_scanf* fn, const char *format, va_list arg_ptr)
15{
16  unsigned int ch;      /* format act. char */
17  int n=0;
18
19  /* arg_ptr tmps */
20#ifdef WANT_FLOATING_POINT_IN_SCANF
21  double *pd;
22  float  *pf;
23#endif
24#ifdef WANT_LONGLONG_SCANF
25  long long *pll;
26#endif
27  long   *pl;
28  short  *ph;
29  int    *pi;
30  char    *s;
31
32  unsigned int consumed=0;
33
34  /* get one char */
35  int tpch= A_GETC(fn);
36
37  //while ((tpch!=-1)&&(*format))
38  while (*format)
39  {
40    ch=*format++;
41    switch (ch) {
42    /* end of format string ?!? */
43    case 0: return 0;
44
45    /* skip spaces ... */
46    case ' ':
47    case '\f':
48    case '\t':
49    case '\v':
50    case '\n':
51    case '\r':
52      while((*format)&&(isspace(*format))) ++format;
53      while(isspace(tpch)) tpch=A_GETC(fn);
54      break;
55
56    /* format string ... */
57    case '%':
58      {
59        unsigned int _div=0;
60        int width=-1;
61        char flag_width=0;
62        char flag_discard=0;
63        char flag_half=0;
64        char flag_long=0;
65        char flag_longlong=0;
66
67in_scan:
68        ch=*format++;
69        if(ch!='n' && tpch==-1) goto err_out;
70        switch (ch) {
71        /* end of format string ?!? */
72        case 0: return 0;
73
74        /* check for % */
75        case '%':
76          if ((unsigned char)tpch != ch) goto err_out;
77          tpch=A_GETC(fn);
78          break;
79
80        /* FLAGS */
81        case '*':
82          flag_discard=1;
83          goto in_scan;
84        case 'h':
85          flag_half=1;
86          goto in_scan;
87        case 'l':
88          if (flag_long) flag_longlong=1;
89          flag_long=1;
90          goto in_scan;
91        case 'q':
92        case 'L':
93          flag_longlong=1;
94          goto in_scan;
95
96        /* WIDTH */
97        case '0':
98        case '1':
99        case '2':
100        case '3':
101        case '4':
102        case '5':
103        case '6':
104        case '7':
105        case '8':
106        case '9':
107          width=strtol(format-1,&s,10);
108          format=s;
109          flag_width=1;
110          goto in_scan;
111
112        /* scan for integer / strtol reimplementation ... */
113        case 'p':
114        case 'X':
115        case 'x':
116          _div+=6;
117        case 'd':
118          _div+=2;
119        case 'o':
120          _div+=8;
121        case 'u':
122        case 'i':
123          {
124#ifdef WANT_LONGLONG_SCANF
125            unsigned long long v=0;
126#else
127            unsigned long v=0;
128#endif
129            unsigned int consumedsofar;
130            int neg=0;
131            while(isspace(tpch)) tpch=A_GETC(fn);
132            if (tpch=='-') {
133              tpch=A_GETC(fn);
134              neg=1;
135            }
136
137            if (tpch=='+') tpch=A_GETC(fn);
138
139            if (tpch==-1) return n;
140            consumedsofar=consumed;
141
142            if (!flag_width) {
143              if ((_div==16) && (tpch=='0')) goto scan_hex;
144              if (!_div) {
145                _div=10;
146                if (tpch=='0') {
147                  _div=8;
148scan_hex:
149                  tpch=A_GETC(fn);
150                  if ((tpch|32)=='x') {
151                    tpch=A_GETC(fn);
152                    _div=16;
153                  }
154                }
155              }
156            }
157            while ((width)&&(tpch!=-1)) {
158              register unsigned long c=tpch&0xff;
159#ifdef WANT_LONGLONG_SCANF
160              register unsigned long long d=c|0x20;
161#else
162              register unsigned long d=c|0x20;
163#endif
164              c=(d>='a'?d-'a'+10:c<='9'?c-'0':0xff);
165              if (c>=_div) break;
166              d=v*_div;
167#ifdef WANT_LONGLONG_SCANF
168              v=(d<v)?ULLONG_MAX:d+c;
169#else
170              v=(d<v)?ULONG_MAX:d+c;
171#endif
172              --width;
173              tpch=A_GETC(fn);
174            }
175
176            if (consumedsofar==consumed) return n;
177
178            if ((ch|0x20)<'p') {
179#ifdef WANT_LONGLONG_SCANF
180              register long long l=v;
181              if (v>=-((unsigned long long)LLONG_MIN)) {
182                l=(neg)?LLONG_MIN:LLONG_MAX;
183              }
184              else {
185                if (neg) v*=-1;
186              }
187#else
188              register long l=v;
189              if (v>=-((unsigned long)LONG_MIN)) {
190                l=(neg)?LONG_MIN:LONG_MAX;
191              }
192              else {
193                if (neg) v*=-1;
194              }
195#endif
196            }
197            if (!flag_discard) {
198#ifdef WANT_LONGLONG_SCANF
199              if (flag_longlong) {
200                pll=(long long *)va_arg(arg_ptr,long long*);
201                *pll=v;
202              } else
203#endif
204              if (flag_long) {
205                pl=(long *)va_arg(arg_ptr,long*);
206                *pl=v;
207              } else if (flag_half) {
208                ph=(short*)va_arg(arg_ptr,short*);
209                *ph=v;
210              } else {
211                pi=(int *)va_arg(arg_ptr,int*);
212                *pi=v;
213              }
214              if(consumedsofar<consumed) ++n;
215            }
216          }
217          break;
218
219        /* FIXME: return value of *scanf with ONE float maybe -1 instead of 0 */
220#ifdef WANT_FLOATING_POINT_IN_SCANF
221        /* floating point numbers */
222        case 'e':
223        case 'E':
224        case 'f':
225        case 'g':
226          {
227            double d=0.0;
228            int neg=0;
229            unsigned int consumedsofar;
230
231            while(isspace(tpch)) tpch=A_GETC(fn);
232
233            if (tpch=='-') {
234              tpch=A_GETC(fn);
235              neg=1;
236            }
237            if (tpch=='+') tpch=A_GETC(fn);
238
239            consumedsofar=consumed;
240
241            while (isdigit(tpch)) {
242              d=d*10+(tpch-'0');
243              tpch=A_GETC(fn);
244            }
245            if (tpch=='.') {
246              double factor=.1;
247              consumedsofar++;
248              tpch=A_GETC(fn);
249              while (isdigit(tpch)) {
250                d=d+(factor*(tpch-'0'));
251                factor/=10;
252                tpch=A_GETC(fn);
253              }
254            }
255            if (consumedsofar==consumed) return n;      /* error */
256            if ((tpch|0x20)=='e') {
257              int exp=0, prec=tpch;
258              double factor=10;
259              tpch=A_GETC(fn);
260              if (tpch=='-') {
261                factor=0.1;
262                tpch=A_GETC(fn);
263              } else if (tpch=='+') {
264                tpch=A_GETC(fn);
265              } else {
266                d=0;
267                if (tpch!=-1) A_PUTC(tpch,fn);
268                tpch=prec;
269                goto exp_out;
270              }
271              consumedsofar=consumed;
272              while (isdigit(tpch)) {
273                exp=exp*10+(tpch-'0');
274                tpch=A_GETC(fn);
275              }
276              if (consumedsofar==consumed) return n;    /* error */
277              while (exp) {     /* as in strtod: XXX: this introduces rounding errors */
278                d*=factor; --exp;
279              }
280            }
281exp_out:
282            if (neg) d = -d;
283            if (!flag_discard) {
284              if (flag_long) {
285                pd=(double *)va_arg(arg_ptr,double*);
286                *pd=d;
287              } else {
288                pf=(float *)va_arg(arg_ptr,float*);
289                *pf=d;
290              }
291              ++n;
292            }
293          }
294          break;
295#endif
296
297        /* char-sequences */
298        case 'c':
299          if (!flag_discard) {
300            s=(char *)va_arg(arg_ptr,char*);
301            ++n;
302          }
303          if (!flag_width) width=1;
304          while (width && (tpch!=-1)) {
305            if (!flag_discard) *(s++)=tpch;
306            --width;
307            tpch=A_GETC(fn);
308          }
309          break;
310
311        /* string */
312        case 's':
313          if (!flag_discard) s=(char *)va_arg(arg_ptr,char*);
314          while(isspace(tpch)) tpch=A_GETC(fn);
315          if (tpch==-1) break;          /* end of scan -> error */
316          while (width && (tpch!=-1) && (!isspace(tpch))) {
317            if (!flag_discard) *s=tpch;
318            if (tpch) ++s; else break;
319            --width;
320            tpch=A_GETC(fn);
321          }
322          if (!flag_discard) { *s=0; ++n; }
323          break;
324
325        /* consumed-count */
326        case 'n':
327          if (!flag_discard) {
328            pi=(int *)va_arg(arg_ptr,int *);
329//          ++n;        /* in accordance to ANSI C we don't count this conversion */
330            *pi=consumed-1;
331          }
332          break;
333
334#ifdef WANT_CHARACTER_CLASSES_IN_SCANF
335        case '[':
336          {
337            char cset[256];
338            int flag_not=0;
339            int flag_dash=0;
340            memset(cset,0,sizeof(cset));
341            ch=*format++;
342            /* first char specials */
343            if (ch=='^') {
344              flag_not=1;
345              ch=*format++;
346            }
347            if ((ch=='-')||(ch==']')) {
348              cset[ch]=1;
349              ch=*format++;
350            }
351            /* almost all non special chars */
352            for (;(*format) && (*format!=']');++format) {
353              if (flag_dash) {
354                register unsigned char tmp=*format;
355                for (;ch<=tmp;++ch) cset[ch]=1;
356                flag_dash=0;
357                ch=*format;
358              }
359              else if (*format=='-') flag_dash=1;
360              else {
361                cset[ch]=1;
362                ch=*format;
363              }
364            }
365            /* last char specials */
366            if (flag_dash) cset['-']=1;
367            else cset[ch]=1;
368
369            /* like %c or %s */
370            if (!flag_discard) {
371              s=(char *)va_arg(arg_ptr,char*);
372              ++n;
373            }
374            while (width && (tpch>=0) && (cset[tpch]^flag_not)) {
375              if (!flag_discard) *s=tpch;
376              if (tpch) ++s; else break;
377              --width;
378              tpch=A_GETC(fn);
379            }
380            if (!flag_discard) *s=0;
381            ++format;
382          }
383          break;
384#endif
385        default:
386          goto err_out;
387        }
388      }
389      break;
390
391    /* check if equal format string... */
392    default:
393      if ((unsigned char)tpch != ch) goto err_out;
394      tpch=A_GETC(fn);
395      break;
396    }
397  }
398
399  /* maybe a "%n" follows */
400  if(*format) {
401    while(isspace(*format)) format++;
402    if(format[0] == '%' && format[1] == 'n') {
403      pi = (int *) va_arg(arg_ptr, int *);
404      *pi = consumed - 1;
405    }
406  }
407
408err_out:
409  if (tpch<0 && n==0) return EOF;
410  A_PUTC(tpch,fn);
411  return n;
412}
413
414link_warning("__v_scanf","warning: the scanf functions add several kilobytes of bloat.");
Note: See TracBrowser for help on using the repository browser.