OSDN Git Service

Initial revision
[uclinux-h8/uClibc.git] / libc / stdio / scanf.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4
5 #ifdef __STDC__
6 #include <stdarg.h>
7 #define va_strt      va_start
8 #else
9 #include <varargs.h>
10 #define va_strt(p,i) va_start(p)
11 #endif
12
13 #ifdef L_scanf
14 #ifdef __STDC__
15 int scanf(const char * fmt, ...)
16 #else
17 int scanf(fmt, va_alist)
18 __const char *fmt;
19 va_dcl
20 #endif
21 {
22   va_list ptr;
23   int rv;
24   va_strt(ptr, fmt);
25   rv = vfscanf(stdin,fmt,ptr);
26   va_end(ptr);
27   return rv;
28 }
29 #endif
30
31 #ifdef L_sscanf
32 #ifdef __STDC__
33 int sscanf(char * sp, const char * fmt, ...)
34 #else
35 int sscanf(sp, fmt, va_alist)
36 char * sp;
37 __const char *fmt;
38 va_dcl
39 #endif
40 {
41 static FILE  string[1] =
42 {
43    {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1,
44     _IOFBF | __MODE_READ}
45 };
46
47   va_list ptr;
48   int rv;
49   va_strt(ptr, fmt);
50   string->bufpos = sp;
51   rv = vfscanf(string,fmt,ptr);
52   va_end(ptr);
53   return rv;
54 }
55 #endif
56
57 #ifdef L_fscanf
58 #ifdef __STDC__
59 int fscanf(FILE * fp, const char * fmt, ...)
60 #else
61 int fscanf(fp, fmt, va_alist)
62 FILE * fp;
63 __const char *fmt;
64 va_dcl
65 #endif
66 {
67   va_list ptr;
68   int rv;
69   va_strt(ptr, fmt);
70   rv = vfscanf(fp,fmt,ptr);
71   va_end(ptr);
72   return rv;
73 }
74 #endif
75
76 #ifdef L_vscanf
77 int vscanf(fmt, ap)
78 __const char *fmt;
79 va_list ap;
80 {
81   return vfscanf(stdin,fmt,ap);
82 }
83 #endif
84
85 #ifdef L_vsscanf
86 int vsscanf(sp, fmt, ap)
87 char * sp;
88 __const char *fmt;
89 {
90 static FILE  string[1] =
91 {
92    {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1,
93     _IOFBF | __MODE_READ}
94 };
95
96   string->bufpos = sp;
97   return vfscanf(string,fmt,ap);
98 }
99 #endif
100
101 #ifdef L_vfscanf
102
103 #if FLOATS
104 int _vfscanf_fp_ref = 1;
105 #else
106 int _vfscanf_fp_ref = 0;
107 #endif
108
109 /* #define      skip()  do{c=getc(fp); if (c<1) goto done;}while(isspace(c))*/
110
111 #define skip()  while(isspace(c)) { if ((c=getc(fp))<1) goto done; }
112
113 #if FLOATS
114 /* fp scan actions */
115 #define F_NADA  0       /* just change state */
116 #define F_SIGN  1       /* set sign */
117 #define F_ESIGN 2       /* set exponent's sign */
118 #define F_INT   3       /* adjust integer part */
119 #define F_FRAC  4       /* adjust fraction part */
120 #define F_EXP   5       /* adjust exponent part */
121 #define F_QUIT  6
122
123 #define NSTATE  8
124 #define FS_INIT         0       /* initial state */
125 #define FS_SIGNED       1       /* saw sign */
126 #define FS_DIGS         2       /* saw digits, no . */
127 #define FS_DOT          3       /* saw ., no digits */
128 #define FS_DD           4       /* saw digits and . */
129 #define FS_E            5       /* saw 'e' */
130 #define FS_ESIGN        6       /* saw exp's sign */
131 #define FS_EDIGS        7       /* saw exp's digits */
132
133 #define FC_DIG          0
134 #define FC_DOT          1
135 #define FC_E            2
136 #define FC_SIGN         3
137
138 /* given transition,state do what action? */
139 int fp_do[][NSTATE] = {
140         {F_INT,F_INT,F_INT,
141          F_FRAC,F_FRAC,
142          F_EXP,F_EXP,F_EXP},    /* see digit */
143         {F_NADA,F_NADA,F_NADA,
144          F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT},   /* see '.' */
145         {F_QUIT,F_QUIT,
146          F_NADA,F_QUIT,F_NADA,
147          F_QUIT,F_QUIT,F_QUIT}, /* see e/E */
148         {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
149          F_ESIGN,F_QUIT,F_QUIT},        /* see sign */
150 };
151 /* given transition,state what is new state? */
152 int fp_ns[][NSTATE] = {
153         {FS_DIGS,FS_DIGS,FS_DIGS,
154          FS_DD,FS_DD,
155          FS_EDIGS,FS_EDIGS,FS_EDIGS},   /* see digit */
156         {FS_DOT,FS_DOT,FS_DD,
157          },     /* see '.' */
158         {0,0,
159          FS_E,0,FS_E,
160         },      /* see e/E */
161         {FS_SIGNED,0,0,0,0,
162          FS_ESIGN,0,0}, /* see sign */
163 };
164 /* which states are valid terminators? */
165 int fp_sval[NSTATE] = {
166         0,0,1,0,1,0,0,1
167 };
168 #endif
169
170 int
171 vfscanf(fp, fmt, ap)
172 register FILE *fp;
173 register char *fmt;
174 va_list ap;
175
176 {
177    register long n;
178    register int c, width, lval, cnt = 0;
179    int   store, neg, base, wide1, endnull, rngflag, c2;
180    register unsigned char *p;
181    unsigned char delim[128], digits[17], *q;
182 #if FLOATS
183    long  frac, expo;
184    int   eneg, fraclen, fstate, trans;
185    double fx, fp_scan();
186 #endif
187
188    if (!*fmt)
189       return (0);
190
191    c = getc(fp);
192    while (c > 0)
193    {
194       store = 0;
195       if (*fmt == '%')
196       {
197          n = 0;
198          width = -1;
199          wide1 = 1;
200          base = 10;
201          lval = (sizeof(long) == sizeof(int));
202          store = 1;
203          endnull = 1;
204          neg = -1;
205
206          strcpy(delim, "\011\012\013\014\015 ");
207          strcpy(digits, "0123456789ABCDEF");
208
209          if (fmt[1] == '*')
210          {
211             endnull = store = 0;
212             ++fmt;
213          }
214
215          while (isdigit(*++fmt))/* width digit(s) */
216          {
217             if (width == -1)
218                width = 0;
219             wide1 = width = (width * 10) + (*fmt - '0');
220          }
221          --fmt;
222        fmtnxt:
223          ++fmt;
224          switch (tolower(*fmt)) /* tolower() is a MACRO! */
225          {
226          case '*':
227             endnull = store = 0;
228             goto fmtnxt;
229
230          case 'l':              /* long data */
231             lval = 1;
232             goto fmtnxt;
233          case 'h':              /* short data */
234             lval = 0;
235             goto fmtnxt;
236
237          case 'i':              /* any-base numeric */
238             base = 0;
239             goto numfmt;
240
241          case 'b':              /* unsigned binary */
242             base = 2;
243             goto numfmt;
244
245          case 'o':              /* unsigned octal */
246             base = 8;
247             goto numfmt;
248
249          case 'x':              /* unsigned hexadecimal */
250             base = 16;
251             goto numfmt;
252
253          case 'd':              /* SIGNED decimal */
254             neg = 0;
255             /* FALL-THRU */
256
257          case 'u':              /* unsigned decimal */
258           numfmt:skip();
259
260             if (isupper(*fmt))
261                lval = 1;
262
263             if (!base)
264             {
265                base = 10;
266                neg = 0;
267                if (c == '%')
268                {
269                   base = 2;
270                   goto skip1;
271                }
272                else if (c == '0')
273                {
274                   c = getc(fp);
275                   if (c < 1)
276                      goto savnum;
277                   if ((c != 'x')
278                       && (c != 'X'))
279                   {
280                      base = 8;
281                      digits[8] = '\0';
282                      goto zeroin;
283                   }
284                   base = 16;
285                   goto skip1;
286                }
287             }
288
289             if ((neg == 0) && (base == 10)
290                 && ((neg = (c == '-')) || (c == '+')))
291             {
292              skip1:
293                c = getc(fp);
294                if (c < 1)
295                   goto done;
296             }
297
298             digits[base] = '\0';
299             p = ((unsigned char *)
300                  strchr(digits, toupper(c)));
301
302             if ((!c || !p) && width)
303                goto done;
304
305             while (p && width-- && c)
306             {
307                n = (n * base) + (p - digits);
308                c = getc(fp);
309              zeroin:
310                p = ((unsigned char *)
311                     strchr(digits, toupper(c)));
312             }
313           savnum:
314             if (store)
315             {
316                if (neg == 1)
317                   n = -n;
318                if (lval)
319                   *va_arg(ap, long*) = n;
320                else
321                   *va_arg(ap, short*) = n;
322                ++cnt;
323             }
324             break;
325
326 #if FLOATS
327          case 'e':              /* float */
328          case 'f':
329          case 'g':
330             skip();
331             fprintf(stderr,"LIBM:SCANF");
332
333             if (isupper(*fmt))
334                lval = 1;
335
336             fstate = FS_INIT;
337             neg = 0;
338             eneg = 0;
339             n = 0;
340             frac = 0;
341             expo = 0;
342             fraclen = 0;
343
344             while (c && width--)
345             {
346                if (c >= '0' && c <= '9')
347                   trans = FC_DIG;
348                else if (c == '.')
349                   trans = FC_DOT;
350                else if (c == '+' || c == '-')
351                   trans = FC_SIGN;
352                else if (tolower(c) == 'e')
353                   trans = FC_E;
354                else
355                   goto fdone;
356
357                switch (fp_do[trans][fstate])
358                {
359                case F_SIGN:
360                   neg = (c == '-');
361                   break;
362                case F_ESIGN:
363                   eneg = (c == '-');
364                   break;
365                case F_INT:
366                   n = 10 * n + (c - '0');
367                   break;
368                case F_FRAC:
369                   frac = 10 * frac + (c - '0');
370                   fraclen++;
371                   break;
372                case F_EXP:
373                   expo = 10 * expo + (c - '0');
374                   break;
375                case F_QUIT:
376                   goto fdone;
377                }
378                fstate = fp_ns[trans][fstate];
379                c = getc(fp);
380             }
381
382           fdone:
383             if (!fp_sval[fstate])
384                goto done;
385             if (store)
386             {
387                fx = fp_scan(neg, eneg, n, frac, expo, fraclen);
388                if (lval)
389                   *va_arg(ap, double *) = fx;
390                else
391                   *va_arg(ap, float *) = fx;
392                ++cnt;
393             }
394             break;
395 #else
396          case 'e':              /* float */
397          case 'f':
398          case 'g':
399                 fprintf(stderr, "LIBC:SCANF");
400                 exit(-1);
401 #endif
402
403          case 'c':              /* character data */
404             width = wide1;
405             lval = endnull = 0;
406             delim[0] = '\0';
407             goto strproc;
408
409          case '[':              /* string w/ delimiter set */
410
411             /* get delimiters */
412             p = delim;
413
414             if (*++fmt == '^')
415             {
416                fmt++;
417                lval = 0;
418             }
419             else
420                lval = 1;
421
422             rngflag = 2;
423             if ((*fmt == ']') || (*fmt == '-'))
424             {
425                *p++ = *fmt++;
426                rngflag = 0;
427             }
428
429             while (*fmt != ']')
430             {
431                if (*fmt == '\0')
432                   goto done;
433                switch (rngflag)
434                {
435                case 1:
436                   c2 = *(p - 2);
437                   if (c2 <= *fmt)
438                   {
439                      p -= 2;
440                      while (c2 < *fmt)
441                         *p++ = c2++;
442                      rngflag = 2;
443                      break;
444                   }
445                   /* fall thru intentional */
446
447                case 0:
448                   rngflag = (*fmt == '-');
449                   break;
450
451                case 2:
452                   rngflag = 0;
453                }
454
455                *p++ = *fmt++;
456             }
457
458             *p = '\0';
459             goto strproc;
460
461          case 's':              /* string data */
462             lval = 0;
463             skip();
464           strproc:
465             /* process string */
466             p = va_arg(ap, unsigned char *);
467
468             /* if the 1st char fails, match fails */
469             if (width)
470             {
471                q = ((unsigned char *)
472                     strchr(delim, c));
473                if ((c < 1) || lval == (q==0))
474                {
475                   if (endnull)
476                      *p = '\0';
477                   goto done;
478                }
479             }
480
481             for (;;)            /* FOREVER */
482             {
483                if (store)
484                   *p++ = c;
485                if (((c = getc(fp)) < 1) ||
486                    (--width == 0))
487                   break;
488
489                q = ((unsigned char *)
490                     strchr(delim, c));
491                if (lval == (q==0))
492                   break;
493             }
494
495             if (store)
496             {
497                if (endnull)
498                   *p = '\0';
499                ++cnt;
500             }
501             break;
502
503          case '\0':             /* early EOS */
504             --fmt;
505             /* FALL THRU */
506
507          default:
508             goto cmatch;
509          }
510       }
511       else if (isspace(*fmt))   /* skip whitespace */
512       {
513          skip();
514       }
515       else
516       {                         /* normal match char */
517        cmatch:
518          if (c != *fmt)
519             break;
520          c = getc(fp);
521       }
522
523       if (!*++fmt)
524          break;
525    }
526
527  done:                          /* end of scan */
528    if ((c == EOF) && (cnt == 0))
529       return (EOF);
530
531    if( c != EOF )
532       ungetc(c, fp);
533    return (cnt);
534 }
535
536 #endif