OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [newlib-1.10.0/] [newlib/] [libc/] [stdio/] [vfscanf.c] - Blame information for rev 1773

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1010 ivang
/*
2
FUNCTION
3
<<vscanf>>, <<vfscanf>>, <<vsscanf>>---format argument list
4
 
5
INDEX
6
        vscanf
7
INDEX
8
        vfscanf
9
INDEX
10
        vsscanf
11
 
12
ANSI_SYNOPSIS
13
        #include <stdio.h>
14
        #include <stdarg.h>
15
        int vscanf(const char *<[fmt]>, va_list <[list]>);
16
        int vfscanf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
17
        int vsscanf(const char *<[str]>, const char *<[fmt]>, va_list <[list]>);
18
 
19
        int _vscanf_r(void *<[reent]>, const char *<[fmt]>,
20
                       va_list <[list]>);
21
        int _vfscanf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
22
                       va_list <[list]>);
23
        int _vsscanf_r(void *<[reent]>, const char *<[str]>, const char *<[fmt]>,
24
                       va_list <[list]>);
25
 
26
TRAD_SYNOPSIS
27
        #include <stdio.h>
28
        #include <varargs.h>
29
        int vscanf( <[fmt]>, <[ist]>)
30
        char *<[fmt]>;
31
        va_list <[list]>;
32
 
33
        int vfscanf( <[fp]>, <[fmt]>, <[list]>)
34
        FILE *<[fp]>;
35
        char *<[fmt]>;
36
        va_list <[list]>;
37
 
38
        int vsscanf( <[str]>, <[fmt]>, <[list]>)
39
        char *<[str]>;
40
        char *<[fmt]>;
41
        va_list <[list]>;
42
 
43
        int _vscanf_r( <[reent]>, <[fmt]>, <[ist]>)
44
        char *<[reent]>;
45
        char *<[fmt]>;
46
        va_list <[list]>;
47
 
48
        int _vfscanf_r( <[reent]>, <[fp]>, <[fmt]>, <[list]>)
49
        char *<[reent]>;
50
        FILE *<[fp]>;
51
        char *<[fmt]>;
52
        va_list <[list]>;
53
 
54
        int _vsscanf_r( <[reent]>, <[str]>, <[fmt]>, <[list]>)
55
        char *<[reent]>;
56
        char *<[str]>;
57
        char *<[fmt]>;
58
        va_list <[list]>;
59
 
60
DESCRIPTION
61
<<vscanf>>, <<vfscanf>>, and <<vsscanf>> are (respectively) variants
62
of <<scanf>>, <<fscanf>>, and <<sscanf>>.  They differ only in
63
allowing their caller to pass the variable argument list as a
64
<<va_list>> object (initialized by <<va_start>>) rather than
65
directly accepting a variable number of arguments.
66
 
67
RETURNS
68
The return values are consistent with the corresponding functions:
69
<<vscanf>> returns the number of input fields successfully scanned,
70
converted, and stored; the return value does not include scanned
71
fields which were not stored.
72
 
73
If <<vscanf>> attempts to read at end-of-file, the return value
74
is <<EOF>>.
75
 
76
If no fields were stored, the return value is <<0>>.
77
 
78
The routines <<_vscanf_r>>, <<_vfscanf_f>>, and <<_vsscanf_r>> are
79
reentrant versions which take an additional first parameter which points to the
80
reentrancy structure.
81
 
82
PORTABILITY
83
These are GNU extensions.
84
 
85
Supporting OS subroutines required:
86
*/
87
 
88
/*-
89
 * Copyright (c) 1990 The Regents of the University of California.
90
 * All rights reserved.
91
 *
92
 * Redistribution and use in source and binary forms are permitted
93
 * provided that the above copyright notice and this paragraph are
94
 * duplicated in all such forms and that any documentation,
95
 * advertising materials, and other materials related to such
96
 * distribution and use acknowledge that the software was developed
97
 * by the University of California, Berkeley.  The name of the
98
 * University may not be used to endorse or promote products derived
99
 * from this software without specific prior written permission.
100
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
101
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
102
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
103
 */
104
 
105
#include <_ansi.h>
106
#include <ctype.h>
107
#include <stdio.h>
108
#include <stdlib.h>
109
#include <limits.h>
110
#ifdef _HAVE_STDC
111
#include <stdarg.h>
112
#else
113
#include <varargs.h>
114
#endif
115
#include "local.h"
116
 
117
#ifndef NO_FLOATING_POINT
118
#define FLOATING_POINT
119
#endif
120
 
121
#ifdef FLOATING_POINT
122
#include <float.h>
123
 
124
/* Currently a test is made to see if long double processing is warranted.
125
   This could be changed in the future should the _ldtoa_r code be
126
   preferred over _dtoa_r.  */
127
#define _NO_LONGDBL
128
#if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
129
#undef _NO_LONGDBL
130
extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
131
#endif
132
 
133
#define _NO_LONGLONG
134
#if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
135
# undef _NO_LONGLONG
136
#endif
137
 
138
#include "floatio.h"
139
#define BUF     (MAXEXP+MAXFRACT+3)     /* 3 = sign + decimal point + NUL */
140
/* An upper bound for how long a long prints in decimal.  4 / 13 approximates
141
   log (2).  Add one char for roundoff compensation and one for the sign.  */
142
#define MAX_LONG_LEN ((CHAR_BIT * sizeof (long)  - 1) * 4 / 13 + 2)
143
#else
144
#define BUF     40
145
#endif
146
 
147
/*
148
 * Flags used during conversion.
149
 */
150
 
151
#define LONG            0x01    /* l: long or double */
152
#define LONGDBL         0x02    /* L: long double or long long */
153
#define SHORT           0x04    /* h: short */
154
#define SUPPRESS        0x08    /* suppress assignment */
155
#define POINTER         0x10    /* weird %p pointer (`fake hex') */
156
#define NOSKIP          0x20    /* do not skip blanks */
157
 
158
/*
159
 * The following are used in numeric conversions only:
160
 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
161
 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
162
 */
163
 
164
#define SIGNOK          0x40    /* +/- is (still) legal */
165
#define NDIGITS         0x80    /* no digits detected */
166
 
167
#define DPTOK           0x100   /* (float) decimal point is still legal */
168
#define EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
169
 
170
#define PFXOK           0x100   /* 0x prefix is (still) legal */
171
#define NZDIGITS        0x200   /* no zero digits detected */
172
 
173
/*
174
 * Conversion types.
175
 */
176
 
177
#define CT_CHAR         0        /* %c conversion */
178
#define CT_CCL          1       /* %[...] conversion */
179
#define CT_STRING       2       /* %s conversion */
180
#define CT_INT          3       /* integer, i.e., strtol or strtoul */
181
#define CT_FLOAT        4       /* floating, i.e., strtod */
182
 
183
#if 0
184
#define u_char unsigned char
185
#endif
186
#define u_char char
187
#define u_long unsigned long
188
 
189
#ifndef _NO_LONGLONG
190
typedef unsigned long long u_long_long;
191
#endif
192
 
193
/*static*/ u_char *__sccl ();
194
 
195
/*
196
 * vfscanf
197
 */
198
 
199
#define BufferEmpty (fp->_r <= 0 && __srefill(fp))
200
 
201
#ifndef _REENT_ONLY
202
 
203
int
204
_DEFUN (vfscanf, (fp, fmt, ap),
205
    register FILE *fp _AND
206
    _CONST char *fmt _AND
207
    va_list ap)
208
{
209
  CHECK_INIT(fp);
210
  return __svfscanf_r (fp->_data, fp, fmt, ap);
211
}
212
 
213
int
214
__svfscanf (fp, fmt0, ap)
215
     register FILE *fp;
216
     char _CONST *fmt0;
217
     va_list ap;
218
{
219
  return __svfscanf_r (_REENT, fp, fmt0, ap);
220
}
221
 
222
#endif /* !_REENT_ONLY */
223
 
224
int
225
_DEFUN (_vfscanf_r, (data, fp, fmt, ap),
226
    struct _reent *data _AND
227
    register FILE *fp _AND
228
    _CONST char *fmt _AND
229
    va_list ap)
230
{
231
  return __svfscanf_r (data, fp, fmt, ap);
232
}
233
 
234
 
235
int
236
__svfscanf_r (rptr, fp, fmt0, ap)
237
     struct _reent *rptr;
238
     register FILE *fp;
239
     char _CONST *fmt0;
240
     va_list ap;
241
{
242
  register u_char *fmt = (u_char *) fmt0;
243
  register int c;               /* character from format, or conversion */
244
  register size_t width;        /* field width, or 0 */
245
  register char *p;             /* points into all kinds of strings */
246
  register int n;               /* handy integer */
247
  register int flags;           /* flags as defined above */
248
  register char *p0;            /* saves original value of p when necessary */
249
  int nassigned;                /* number of fields assigned */
250
  int nread;                    /* number of characters consumed from fp */
251
  int base = 0;                  /* base argument to strtol/strtoul */
252
  int nbytes = 1;               /* number of bytes read from fmt string */
253
  wchar_t wc;                   /* wchar to use to read format string */
254
 
255
  u_long (*ccfn) () = 0; /* conversion function (strtol/strtoul) */
256
  char ccltab[256];             /* character class table for %[...] */
257
  char buf[BUF];                /* buffer for numeric conversions */
258
  char *lptr;                   /* literal pointer */
259
#ifdef MB_CAPABLE
260
  int state = 0;                /* value to keep track of multibyte state */
261
#endif
262
 
263
  short *sp;
264
  int *ip;
265
  float *flp;
266
  _LONG_DOUBLE *ldp;
267
  double *dp;
268
  long *lp;
269
#ifndef _NO_LONGLONG
270
  long long *llp;
271
#else
272
        u_long _uquad;
273
#endif
274
 
275
  /* `basefix' is used to avoid `if' tests in the integer scanner */
276
  static _CONST short basefix[17] =
277
    {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
278
 
279
  nassigned = 0;
280
  nread = 0;
281
  for (;;)
282
    {
283
#ifndef MB_CAPABLE
284
      wc = *fmt;
285
#else
286
      nbytes = _mbtowc_r (rptr, &wc, fmt, MB_CUR_MAX, &state);
287
#endif
288
      fmt += nbytes;
289
      if (wc == 0)
290
        return nassigned;
291
      if (nbytes == 1 && isspace (wc))
292
        {
293
          for (;;)
294
            {
295
              if (BufferEmpty)
296
                return nassigned;
297
              if (!isspace (*fp->_p))
298
                break;
299
              nread++, fp->_r--, fp->_p++;
300
            }
301
          continue;
302
        }
303
      if (wc != '%')
304
        goto literal;
305
      width = 0;
306
      flags = 0;
307
 
308
      /*
309
       * switch on the format.  continue if done; break once format
310
       * type is derived.
311
       */
312
 
313
    again:
314
      c = *fmt++;
315
 
316
      switch (c)
317
        {
318
        case '%':
319
        literal:
320
          lptr = fmt - nbytes;
321
          for (n = 0; n < nbytes; ++n)
322
            {
323
              if (BufferEmpty)
324
                goto input_failure;
325
              if (*fp->_p != *lptr)
326
                goto match_failure;
327
              fp->_r--, fp->_p++;
328
              nread++;
329
              ++lptr;
330
            }
331
          continue;
332
 
333
        case '*':
334
          flags |= SUPPRESS;
335
          goto again;
336
        case 'l':
337
          flags |= LONG;
338
          goto again;
339
        case 'L':
340
          flags |= LONGDBL;
341
          goto again;
342
        case 'h':
343
          flags |= SHORT;
344
          goto again;
345
 
346
        case '0':
347
        case '1':
348
        case '2':
349
        case '3':
350
        case '4':
351
        case '5':
352
        case '6':
353
        case '7':
354
        case '8':
355
        case '9':
356
          width = width * 10 + c - '0';
357
          goto again;
358
 
359
          /*
360
           * Conversions. Those marked `compat' are for
361
           * 4.[123]BSD compatibility.
362
           *
363
           * (According to ANSI, E and X formats are supposed to
364
           * the same as e and x.  Sorry about that.)
365
           */
366
 
367
        case 'D':               /* compat */
368
          flags |= LONG;
369
          /* FALLTHROUGH */
370
        case 'd':
371
          c = CT_INT;
372
          ccfn = (u_long (*)())_strtol_r;
373
          base = 10;
374
          break;
375
 
376
        case 'i':
377
          c = CT_INT;
378
          ccfn = (u_long (*)())_strtol_r;
379
          base = 0;
380
          break;
381
 
382
        case 'O':               /* compat */
383
          flags |= LONG;
384
          /* FALLTHROUGH */
385
        case 'o':
386
          c = CT_INT;
387
          ccfn = _strtoul_r;
388
          base = 8;
389
          break;
390
 
391
        case 'u':
392
          c = CT_INT;
393
          ccfn = _strtoul_r;
394
          base = 10;
395
          break;
396
 
397
        case 'X':               /* compat   XXX */
398
        case 'x':
399
          flags |= PFXOK;       /* enable 0x prefixing */
400
          c = CT_INT;
401
          ccfn = _strtoul_r;
402
          base = 16;
403
          break;
404
 
405
#ifdef FLOATING_POINT
406
        case 'E':               /* compat   XXX */
407
        case 'G':               /* compat   XXX */
408
/* ANSI says that E,G and X behave the same way as e,g,x */
409
          /* FALLTHROUGH */
410
        case 'e':
411
        case 'f':
412
        case 'g':
413
          c = CT_FLOAT;
414
          break;
415
#endif
416
 
417
        case 's':
418
          c = CT_STRING;
419
          break;
420
 
421
        case '[':
422
          fmt = __sccl (ccltab, fmt);
423
          flags |= NOSKIP;
424
          c = CT_CCL;
425
          break;
426
 
427
        case 'c':
428
          flags |= NOSKIP;
429
          c = CT_CHAR;
430
          break;
431
 
432
        case 'p':               /* pointer format is like hex */
433
          flags |= POINTER | PFXOK;
434
          c = CT_INT;
435
          ccfn = _strtoul_r;
436
          base = 16;
437
          break;
438
 
439
        case 'n':
440
          if (flags & SUPPRESS) /* ??? */
441
            continue;
442
          if (flags & SHORT)
443
            {
444
              sp = va_arg (ap, short *);
445
              *sp = nread;
446
            }
447
          else if (flags & LONG)
448
            {
449
              lp = va_arg (ap, long *);
450
              *lp = nread;
451
            }
452
#ifndef _NO_LONGLONG
453
          else if (flags & LONGDBL)
454
            {
455
              llp = va_arg (ap, long long*);
456
              *llp = nread;
457
            }
458
#endif
459
          else
460
            {
461
              ip = va_arg (ap, int *);
462
              *ip = nread;
463
            }
464
          continue;
465
 
466
          /*
467
           * Disgusting backwards compatibility hacks.  XXX
468
           */
469
        case '\0':              /* compat */
470
          return EOF;
471
 
472
        default:                /* compat */
473
          if (isupper (c))
474
            flags |= LONG;
475
          c = CT_INT;
476
          ccfn = (u_long (*)())_strtol_r;
477
          base = 10;
478
          break;
479
        }
480
 
481
      /*
482
       * We have a conversion that requires input.
483
       */
484
      if (BufferEmpty)
485
        goto input_failure;
486
 
487
      /*
488
       * Consume leading white space, except for formats that
489
       * suppress this.
490
       */
491
      if ((flags & NOSKIP) == 0)
492
        {
493
          while (isspace (*fp->_p))
494
            {
495
              nread++;
496
              if (--fp->_r > 0)
497
                fp->_p++;
498
              else
499
#ifndef CYGNUS_NEC
500
              if (__srefill (fp))
501
#endif
502
                goto input_failure;
503
            }
504
          /*
505
           * Note that there is at least one character in the
506
           * buffer, so conversions that do not set NOSKIP ca
507
           * no longer result in an input failure.
508
           */
509
        }
510
 
511
      /*
512
       * Do the conversion.
513
       */
514
      switch (c)
515
        {
516
 
517
        case CT_CHAR:
518
          /* scan arbitrary characters (sets NOSKIP) */
519
          if (width == 0)
520
            width = 1;
521
          if (flags & SUPPRESS)
522
            {
523
              size_t sum = 0;
524
 
525
              for (;;)
526
                {
527
                  if ((n = fp->_r) < (int)width)
528
                    {
529
                      sum += n;
530
                      width -= n;
531
                      fp->_p += n;
532
#ifndef CYGNUS_NEC
533
                      if (__srefill (fp))
534
                        {
535
#endif
536
                          if (sum == 0)
537
                            goto input_failure;
538
                          break;
539
#ifndef CYGNUS_NEC
540
                        }
541
#endif
542
                    }
543
                  else
544
                    {
545
                      sum += width;
546
                      fp->_r -= width;
547
                      fp->_p += width;
548
                      break;
549
                    }
550
                }
551
              nread += sum;
552
            }
553
          else
554
            {
555
#ifdef CYGNUS_NEC
556
              /* Kludge city for the moment */
557
              char *dest = va_arg (ap, char *);
558
              int n = width;
559
              if (fp->_r == 0)
560
                goto input_failure;
561
 
562
              while (n && fp->_r)
563
                {
564
                  *dest++ = *(fp->_p++);
565
                  n--;
566
                  fp->_r--;
567
                  nread++;
568
                }
569
#else
570
              size_t r = fread ((_PTR) va_arg (ap, char *), 1, width, fp);
571
 
572
              if (r == 0)
573
                goto input_failure;
574
              nread += r;
575
#endif
576
              nassigned++;
577
            }
578
          break;
579
 
580
        case CT_CCL:
581
          /* scan a (nonempty) character class (sets NOSKIP) */
582
          if (width == 0)
583
            width = ~0;          /* `infinity' */
584
          /* take only those things in the class */
585
          if (flags & SUPPRESS)
586
            {
587
              n = 0;
588
              while (ccltab[*fp->_p])
589
                {
590
                  n++, fp->_r--, fp->_p++;
591
                  if (--width == 0)
592
                    break;
593
                  if (BufferEmpty)
594
                    {
595
                      if (n == 0)
596
                        goto input_failure;
597
                      break;
598
                    }
599
                }
600
              if (n == 0)
601
                goto match_failure;
602
            }
603
          else
604
            {
605
              p0 = p = va_arg (ap, char *);
606
              while (ccltab[*fp->_p])
607
                {
608
                  fp->_r--;
609
                  *p++ = *fp->_p++;
610
                  if (--width == 0)
611
                    break;
612
                  if (BufferEmpty)
613
                    {
614
                      if (p == p0)
615
                        goto input_failure;
616
                      break;
617
                    }
618
                }
619
              n = p - p0;
620
              if (n == 0)
621
                goto match_failure;
622
              *p = 0;
623
              nassigned++;
624
            }
625
          nread += n;
626
          break;
627
 
628
        case CT_STRING:
629
          /* like CCL, but zero-length string OK, & no NOSKIP */
630
          if (width == 0)
631
            width = ~0;
632
          if (flags & SUPPRESS)
633
            {
634
              n = 0;
635
              while (!isspace (*fp->_p))
636
                {
637
                  n++, fp->_r--, fp->_p++;
638
                  if (--width == 0)
639
                    break;
640
                  if (BufferEmpty)
641
                    break;
642
                }
643
              nread += n;
644
            }
645
          else
646
            {
647
              p0 = p = va_arg (ap, char *);
648
              while (!isspace (*fp->_p))
649
                {
650
                  fp->_r--;
651
                  *p++ = *fp->_p++;
652
                  if (--width == 0)
653
                    break;
654
                  if (BufferEmpty)
655
                    break;
656
                }
657
              *p = 0;
658
              nread += p - p0;
659
              nassigned++;
660
            }
661
          continue;
662
 
663
        case CT_INT:
664
          /* scan an integer as if by strtol/strtoul */
665
#ifdef hardway
666
          if (width == 0 || width > sizeof (buf) - 1)
667
            width = sizeof (buf) - 1;
668
#else
669
          /* size_t is unsigned, hence this optimisation */
670
          if (--width > sizeof (buf) - 2)
671
            width = sizeof (buf) - 2;
672
          width++;
673
#endif
674
          flags |= SIGNOK | NDIGITS | NZDIGITS;
675
          for (p = buf; width; width--)
676
            {
677
              c = *fp->_p;
678
              /*
679
               * Switch on the character; `goto ok' if we
680
               * accept it as a part of number.
681
               */
682
              switch (c)
683
                {
684
                  /*
685
                   * The digit 0 is always legal, but is special.
686
                   * For %i conversions, if no digits (zero or nonzero)
687
                   * have been scanned (only signs), we will have base==0.
688
                   * In that case, we should set it to 8 and enable 0x
689
                   * prefixing. Also, if we have not scanned zero digits
690
                   * before this, do not turn off prefixing (someone else
691
                   * will turn it off if we have scanned any nonzero digits).
692
                   */
693
                case '0':
694
                  if (base == 0)
695
                    {
696
                      base = 8;
697
                      flags |= PFXOK;
698
                    }
699
                  if (flags & NZDIGITS)
700
                    flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
701
                  else
702
                    flags &= ~(SIGNOK | PFXOK | NDIGITS);
703
                  goto ok;
704
 
705
                  /* 1 through 7 always legal */
706
                case '1':
707
                case '2':
708
                case '3':
709
                case '4':
710
                case '5':
711
                case '6':
712
                case '7':
713
                  base = basefix[base];
714
                  flags &= ~(SIGNOK | PFXOK | NDIGITS);
715
                  goto ok;
716
 
717
                  /* digits 8 and 9 ok iff decimal or hex */
718
                case '8':
719
                case '9':
720
                  base = basefix[base];
721
                  if (base <= 8)
722
                    break;      /* not legal here */
723
                  flags &= ~(SIGNOK | PFXOK | NDIGITS);
724
                  goto ok;
725
 
726
                  /* letters ok iff hex */
727
                case 'A':
728
                case 'B':
729
                case 'C':
730
                case 'D':
731
                case 'E':
732
                case 'F':
733
                case 'a':
734
                case 'b':
735
                case 'c':
736
                case 'd':
737
                case 'e':
738
                case 'f':
739
                  /* no need to fix base here */
740
                  if (base <= 10)
741
                    break;      /* not legal here */
742
                  flags &= ~(SIGNOK | PFXOK | NDIGITS);
743
                  goto ok;
744
 
745
                  /* sign ok only as first character */
746
                case '+':
747
                case '-':
748
                  if (flags & SIGNOK)
749
                    {
750
                      flags &= ~SIGNOK;
751
                      goto ok;
752
                    }
753
                  break;
754
 
755
                  /* x ok iff flag still set & 2nd char */
756
                case 'x':
757
                case 'X':
758
                  if (flags & PFXOK && p == buf + 1)
759
                    {
760
                      base = 16;/* if %i */
761
                      flags &= ~PFXOK;
762
                      goto ok;
763
                    }
764
                  break;
765
                }
766
 
767
              /*
768
               * If we got here, c is not a legal character
769
               * for a number.  Stop accumulating digits.
770
               */
771
              break;
772
            ok:
773
              /*
774
               * c is legal: store it and look at the next.
775
               */
776
              *p++ = c;
777
              if (--fp->_r > 0)
778
                fp->_p++;
779
              else
780
#ifndef CYGNUS_NEC
781
              if (__srefill (fp))
782
#endif
783
                break;          /* EOF */
784
            }
785
          /*
786
           * If we had only a sign, it is no good; push back the sign.
787
           * If the number ends in `x', it was [sign] '0' 'x', so push back
788
           * the x and treat it as [sign] '0'.
789
           */
790
          if (flags & NDIGITS)
791
            {
792
              if (p > buf)
793
                _CAST_VOID ungetc (*(u_char *)-- p, fp);
794
              goto match_failure;
795
            }
796
          c = ((u_char *) p)[-1];
797
          if (c == 'x' || c == 'X')
798
            {
799
              --p;
800
              /*(void)*/ ungetc (c, fp);
801
            }
802
          if ((flags & SUPPRESS) == 0)
803
            {
804
              u_long res;
805
 
806
              *p = 0;
807
              res = (*ccfn) (rptr, buf, (char **) NULL, base);
808
              if (flags & POINTER)
809
                *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
810
              else if (flags & SHORT)
811
                {
812
                  sp = va_arg (ap, short *);
813
                  *sp = res;
814
                }
815
              else if (flags & LONG)
816
                {
817
                  lp = va_arg (ap, long *);
818
                  *lp = res;
819
                }
820
#ifndef _NO_LONGLONG
821
              else if (flags & LONGDBL)
822
                {
823
                  u_long_long resll;
824
                  if (ccfn == _strtoul_r)
825
                    resll = _strtoull_r (rptr, buf, (char **) NULL, base);
826
                  else
827
                    resll = _strtoll_r (rptr, buf, (char **) NULL, base);
828
                  llp = va_arg (ap, long long*);
829
                  *llp = resll;
830
                }
831
#endif
832
              else
833
                {
834
                  ip = va_arg (ap, int *);
835
                  *ip = res;
836
                }
837
              nassigned++;
838
            }
839
          nread += p - buf;
840
          break;
841
 
842
#ifdef FLOATING_POINT
843
        case CT_FLOAT:
844
        {
845
          /* scan a floating point number as if by strtod */
846
          /* This code used to assume that the number of digits is reasonable.
847
             However, ANSI / ISO C makes no such stipulation; we have to get
848
             exact results even when there is an unreasonable amount of
849
             leading zeroes.  */
850
          long leading_zeroes = 0;
851
          long zeroes, exp_adjust;
852
          char *exp_start = NULL;
853
#ifdef hardway
854
          if (width == 0 || width > sizeof (buf) - 1)
855
            width = sizeof (buf) - 1;
856
#else
857
          /* size_t is unsigned, hence this optimisation */
858
          if (--width > sizeof (buf) - 2)
859
            width = sizeof (buf) - 2;
860
          width++;
861
#endif
862
          flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
863
          zeroes = 0;
864
          exp_adjust = 0;
865
          for (p = buf; width; )
866
            {
867
              c = *fp->_p;
868
              /*
869
               * This code mimicks the integer conversion
870
               * code, but is much simpler.
871
               */
872
              switch (c)
873
                {
874
 
875
                case '0':
876
                  if (flags & NDIGITS)
877
                    {
878
                      flags &= ~SIGNOK;
879
                      zeroes++;
880
                      goto fskip;
881
                    }
882
                  /* Fall through.  */
883
                case '1':
884
                case '2':
885
                case '3':
886
                case '4':
887
                case '5':
888
                case '6':
889
                case '7':
890
                case '8':
891
                case '9':
892
                  flags &= ~(SIGNOK | NDIGITS);
893
                  goto fok;
894
 
895
                case '+':
896
                case '-':
897
                  if (flags & SIGNOK)
898
                    {
899
                      flags &= ~SIGNOK;
900
                      goto fok;
901
                    }
902
                  break;
903
                case '.':
904
                  if (flags & DPTOK)
905
                    {
906
                      flags &= ~(SIGNOK | DPTOK);
907
                      leading_zeroes = zeroes;
908
                      goto fok;
909
                    }
910
                  break;
911
                case 'e':
912
                case 'E':
913
                  /* no exponent without some digits */
914
                  if ((flags & (NDIGITS | EXPOK)) == EXPOK
915
                      || ((flags & EXPOK) && zeroes))
916
                    {
917
                      if (! (flags & DPTOK))
918
                        {
919
                          exp_adjust = zeroes - leading_zeroes;
920
                          exp_start = p;
921
                        }
922
                      flags =
923
                        (flags & ~(EXPOK | DPTOK)) |
924
                        SIGNOK | NDIGITS;
925
                      zeroes = 0;
926
                      goto fok;
927
                    }
928
                  break;
929
                }
930
              break;
931
            fok:
932
              *p++ = c;
933
              width--;
934
            fskip:
935
              ++nread;
936
              if (--fp->_r > 0)
937
                fp->_p++;
938
              else
939
#ifndef CYGNUS_NEC
940
              if (__srefill (fp))
941
#endif
942
                break;          /* EOF */
943
            }
944
          if (zeroes)
945
            flags &= ~NDIGITS;
946
          /*
947
           * If no digits, might be missing exponent digits
948
           * (just give back the exponent) or might be missing
949
           * regular digits, but had sign and/or decimal point.
950
           */
951
          if (flags & NDIGITS)
952
            {
953
              if (flags & EXPOK)
954
                {
955
                  /* no digits at all */
956
                  while (p > buf)
957
                    {
958
                      ungetc (*(u_char *)-- p, fp);
959
                      --nread;
960
                    }
961
                  goto match_failure;
962
                }
963
              /* just a bad exponent (e and maybe sign) */
964
              c = *(u_char *)-- p;
965
              --nread;
966
              if (c != 'e' && c != 'E')
967
                {
968
                  _CAST_VOID ungetc (c, fp);    /* sign */
969
                  c = *(u_char *)-- p;
970
                  --nread;
971
                }
972
              _CAST_VOID ungetc (c, fp);
973
            }
974
          if ((flags & SUPPRESS) == 0)
975
            {
976
#ifdef _NO_LONGDBL
977
              double res;
978
#else  /* !_NO_LONG_DBL */
979
              long double res;
980
#endif /* !_NO_LONG_DBL */
981
              long new_exp = 0;
982
 
983
              *p = 0;
984
              if ((flags & (DPTOK | EXPOK)) == EXPOK)
985
                {
986
                  exp_adjust = zeroes - leading_zeroes;
987
                  new_exp = -exp_adjust;
988
                  exp_start = p;
989
                }
990
              else if (exp_adjust)
991
                new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
992
              if (exp_adjust)
993
                {
994
 
995
                  /* If there might not be enough space for the new exponent,
996
                     truncate some trailing digits to make room.  */
997
                  if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
998
                    exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
999
                 sprintf (exp_start, "e%ld", new_exp);
1000
                }
1001
#ifdef _NO_LONGDBL
1002
              res = _strtod_r (rptr, buf, NULL);
1003
#else  /* !_NO_LONGDBL */
1004
              res = _strtold (buf, NULL);
1005
#endif /* !_NO_LONGDBL */
1006
              if (flags & LONG)
1007
                {
1008
                  dp = va_arg (ap, double *);
1009
                  *dp = res;
1010
                }
1011
              else if (flags & LONGDBL)
1012
                {
1013
                  ldp = va_arg (ap, _LONG_DOUBLE *);
1014
                  *ldp = res;
1015
                }
1016
              else
1017
                {
1018
                  flp = va_arg (ap, float *);
1019
                  *flp = res;
1020
                }
1021
              nassigned++;
1022
            }
1023
          break;
1024
        }
1025
#endif /* FLOATING_POINT */
1026
        }
1027
    }
1028
input_failure:
1029
  return nassigned ? nassigned : -1;
1030
match_failure:
1031
  return nassigned;
1032
}
1033
 
1034
/*
1035
 * Fill in the given table from the scanset at the given format
1036
 * (just after `[').  Return a pointer to the character past the
1037
 * closing `]'.  The table has a 1 wherever characters should be
1038
 * considered part of the scanset.
1039
 */
1040
 
1041
/*static*/
1042
u_char *
1043
__sccl (tab, fmt)
1044
     register char *tab;
1045
     register u_char *fmt;
1046
{
1047
  register int c, n, v;
1048
 
1049
  /* first `clear' the whole table */
1050
  c = *fmt++;                   /* first char hat => negated scanset */
1051
  if (c == '^')
1052
    {
1053
      v = 1;                    /* default => accept */
1054
      c = *fmt++;               /* get new first char */
1055
    }
1056
  else
1057
    v = 0;                       /* default => reject */
1058
  /* should probably use memset here */
1059
  for (n = 0; n < 256; n++)
1060
    tab[n] = v;
1061
  if (c == 0)
1062
    return fmt - 1;             /* format ended before closing ] */
1063
 
1064
  /*
1065
   * Now set the entries corresponding to the actual scanset to the
1066
   * opposite of the above.
1067
   *
1068
   * The first character may be ']' (or '-') without being special; the
1069
   * last character may be '-'.
1070
   */
1071
 
1072
  v = 1 - v;
1073
  for (;;)
1074
    {
1075
      tab[c] = v;               /* take character c */
1076
    doswitch:
1077
      n = *fmt++;               /* and examine the next */
1078
      switch (n)
1079
        {
1080
 
1081
        case 0:          /* format ended too soon */
1082
          return fmt - 1;
1083
 
1084
        case '-':
1085
          /*
1086
           * A scanset of the form [01+-] is defined as `the digit 0, the
1087
           * digit 1, the character +, the character -', but the effect of a
1088
           * scanset such as [a-zA-Z0-9] is implementation defined.  The V7
1089
           * Unix scanf treats `a-z' as `the letters a through z', but treats
1090
           * `a-a' as `the letter a, the character -, and the letter a'.
1091
           *
1092
           * For compatibility, the `-' is not considerd to define a range if
1093
           * the character following it is either a close bracket (required by
1094
           * ANSI) or is not numerically greater than the character we just
1095
           * stored in the table (c).
1096
           */
1097
          n = *fmt;
1098
          if (n == ']' || n < c)
1099
            {
1100
              c = '-';
1101
              break;            /* resume the for(;;) */
1102
            }
1103
          fmt++;
1104
          do
1105
            {                   /* fill in the range */
1106
              tab[++c] = v;
1107
            }
1108
          while (c < n);
1109
#if 1                   /* XXX another disgusting compatibility hack */
1110
          /*
1111
           * Alas, the V7 Unix scanf also treats formats such
1112
           * as [a-c-e] as `the letters a through e'. This too
1113
           * is permitted by the standard....
1114
           */
1115
          goto doswitch;
1116
#else
1117
          c = *fmt++;
1118
          if (c == 0)
1119
            return fmt - 1;
1120
          if (c == ']')
1121
            return fmt;
1122
#endif
1123
 
1124
          break;
1125
 
1126
 
1127
        case ']':               /* end of scanset */
1128
          return fmt;
1129
 
1130
        default:                /* just another character */
1131
          c = n;
1132
          break;
1133
        }
1134
    }
1135
  /* NOTREACHED */
1136
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.