os/ossrv/genericopenlibs/cstdlib/LSTDIO/VFSCANF.C
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* VFSCANF.C
sl@0
     2
 * 
sl@0
     3
 * Portions Copyright (c) 1990-2004 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     4
 * All rights reserved.
sl@0
     5
 */
sl@0
     6
sl@0
     7
/* No user fns here. Pesch 15apr92. */
sl@0
     8
sl@0
     9
/*
sl@0
    10
 * Copyright (c) 1990 The Regents of the University of California.
sl@0
    11
 * All rights reserved.
sl@0
    12
 *
sl@0
    13
 * Redistribution and use in source and binary forms are permitted
sl@0
    14
 * provided that the above copyright notice and this paragraph are
sl@0
    15
 * duplicated in all such forms and that any documentation,
sl@0
    16
 * advertising materials, and other materials related to such
sl@0
    17
 * distribution and use acknowledge that the software was developed
sl@0
    18
 * by the University of California, Berkeley.  The name of the
sl@0
    19
 * University may not be used to endorse or promote products derived
sl@0
    20
 * from this software without specific prior written permission.
sl@0
    21
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
sl@0
    22
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
sl@0
    23
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
sl@0
    24
 */
sl@0
    25
sl@0
    26
#include <_ansi.h>
sl@0
    27
#include <ctype.h>
sl@0
    28
#include <stdio.h>
sl@0
    29
#include <stdlib.h>
sl@0
    30
#include <stdarg.h>
sl@0
    31
#include "LOCAL.H"
sl@0
    32
sl@0
    33
#include "FLOATIO.H"
sl@0
    34
#define	BUF	(MAXEXP+MAXFRACT+3)	/* 3 = sign + decimal point + NUL */
sl@0
    35
sl@0
    36
/*
sl@0
    37
 * Flags used during conversion.
sl@0
    38
 */
sl@0
    39
sl@0
    40
#define	LONG		0x01	/* l: long or double */
sl@0
    41
#define	LONGDBL		0x02	/* L: long double; unimplemented */
sl@0
    42
#define	SHORT		0x04	/* h: short */
sl@0
    43
#define	SUPPRESS	0x08	/* suppress assignment */
sl@0
    44
#define	POINTER		0x10	/* weird %p pointer (`fake hex') */
sl@0
    45
#define	NOSKIP		0x20	/* do not skip blanks */
sl@0
    46
sl@0
    47
/*
sl@0
    48
 * The following are used in numeric conversions only:
sl@0
    49
 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
sl@0
    50
 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
sl@0
    51
 */
sl@0
    52
sl@0
    53
#define	SIGNOK		0x40	/* +/- is (still) legal */
sl@0
    54
#define	NDIGITS		0x80	/* no digits detected */
sl@0
    55
sl@0
    56
#define	DPTOK		0x100	/* (float) decimal point is still legal */
sl@0
    57
#define	EXPOK		0x200	/* (float) exponent (e+3, etc) still legal */
sl@0
    58
sl@0
    59
#define	PFXOK		0x100	/* 0x prefix is (still) legal */
sl@0
    60
#define	NZDIGITS	0x200	/* no zero digits detected */
sl@0
    61
sl@0
    62
/*
sl@0
    63
 * Conversion types.
sl@0
    64
 */
sl@0
    65
sl@0
    66
#define	CT_CHAR		0	/* %c conversion */
sl@0
    67
#define	CT_CCL		1	/* %[...] conversion */
sl@0
    68
#define	CT_STRING	2	/* %s conversion */
sl@0
    69
#define	CT_INT		3	/* integer, i.e., strtol or strtoul */
sl@0
    70
#define	CT_FLOAT	4	/* floating, i.e., strtod */
sl@0
    71
sl@0
    72
#define u_char char
sl@0
    73
#define u_long unsigned long
sl@0
    74
sl@0
    75
/*static*/ u_char *__sccl (register char *tab,register u_char *fmt);
sl@0
    76
sl@0
    77
/*
sl@0
    78
 * vfscanf
sl@0
    79
 */
sl@0
    80
sl@0
    81
#define BufferEmpty (fp->_r <= 0 && __srefill(fp))
sl@0
    82
sl@0
    83
int
sl@0
    84
__svfscanf (register FILE *fp,char const *fmt0, va_list ap)
sl@0
    85
{
sl@0
    86
  register u_char *fmt = (u_char *) fmt0;
sl@0
    87
  register int c;		/* character from format, or conversion */
sl@0
    88
  register size_t width;	/* field width, or 0 */
sl@0
    89
  register char *p;		/* points into all kinds of strings */
sl@0
    90
  register int n;		/* handy integer */
sl@0
    91
  register int flags;		/* flags as defined above */
sl@0
    92
  register char *p0;		/* saves original value of p when necessary */
sl@0
    93
  int nassigned;		/* number of fields assigned */
sl@0
    94
  int nread;			/* number of characters consumed from fp */
sl@0
    95
  int base = 0;			/* base argument to strtol/strtoul */
sl@0
    96
sl@0
    97
  u_long (*ccfn) (const char *_n, char **_end_PTR, int _base) = 0;	/* conversion function (strtol/strtoul) */
sl@0
    98
  char ccltab[256];		/* character class table for %[...] */
sl@0
    99
  char buf[BUF];		/* buffer for numeric conversions */
sl@0
   100
sl@0
   101
  short *sp;
sl@0
   102
  int *ip;
sl@0
   103
  float *flp;
sl@0
   104
  double *dp;
sl@0
   105
  long *lp;
sl@0
   106
sl@0
   107
  /* `basefix' is used to avoid `if' tests in the integer scanner */
sl@0
   108
  static const short basefix[17] =
sl@0
   109
    {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
sl@0
   110
sl@0
   111
  nassigned = 0;
sl@0
   112
  nread = 0;
sl@0
   113
  for (;;)
sl@0
   114
    {
sl@0
   115
      c = *fmt++;
sl@0
   116
      if (c == 0)
sl@0
   117
	return nassigned;
sl@0
   118
      if (isspace (c))
sl@0
   119
	{
sl@0
   120
	  for (;;)
sl@0
   121
	    {
sl@0
   122
	      if (BufferEmpty)
sl@0
   123
		return nassigned;
sl@0
   124
	      if (!isspace (*fp->_p))
sl@0
   125
		break;
sl@0
   126
	      nread++, fp->_r--, fp->_p++;
sl@0
   127
	    }
sl@0
   128
	  continue;
sl@0
   129
	}
sl@0
   130
      if (c != '%')
sl@0
   131
	goto literal;
sl@0
   132
      width = 0;
sl@0
   133
      flags = 0;
sl@0
   134
sl@0
   135
      /*
sl@0
   136
       * switch on the format.  continue if done; break once format
sl@0
   137
       * type is derived.
sl@0
   138
       */
sl@0
   139
sl@0
   140
    again:
sl@0
   141
      c = *fmt++;
sl@0
   142
sl@0
   143
      switch (c)
sl@0
   144
	{
sl@0
   145
	case '%':
sl@0
   146
	literal:
sl@0
   147
	  if (BufferEmpty)
sl@0
   148
	    goto input_failure;
sl@0
   149
	  if (*fp->_p != c)
sl@0
   150
	    goto match_failure;
sl@0
   151
	  fp->_r--, fp->_p++;
sl@0
   152
	  nread++;
sl@0
   153
	  continue;
sl@0
   154
sl@0
   155
	case '*':
sl@0
   156
	  flags |= SUPPRESS;
sl@0
   157
	  goto again;
sl@0
   158
	case 'l':
sl@0
   159
	  flags |= LONG;
sl@0
   160
	  goto again;
sl@0
   161
	case 'L':
sl@0
   162
	  /* not supported flags |= LONGDBL; */
sl@0
   163
	  goto again;
sl@0
   164
	case 'h':
sl@0
   165
	  flags |= SHORT;
sl@0
   166
	  goto again;
sl@0
   167
sl@0
   168
	case '0':
sl@0
   169
	case '1':
sl@0
   170
	case '2':
sl@0
   171
	case '3':
sl@0
   172
	case '4':
sl@0
   173
	case '5':
sl@0
   174
	case '6':
sl@0
   175
	case '7':
sl@0
   176
	case '8':
sl@0
   177
	case '9':
sl@0
   178
	  width = width * 10 + c - '0';
sl@0
   179
	  goto again;
sl@0
   180
sl@0
   181
	  /*
sl@0
   182
	   * Conversions. Those marked `compat' are for
sl@0
   183
	   * 4.[123]BSD compatibility.
sl@0
   184
	   *
sl@0
   185
	   * (According to ANSI, E and X formats are supposed to
sl@0
   186
	   * the same as e and x.  Sorry about that.)
sl@0
   187
	   */
sl@0
   188
sl@0
   189
	case 'D':		/* compat */
sl@0
   190
	  flags |= LONG;
sl@0
   191
	  /* FALLTHROUGH */
sl@0
   192
	case 'd':
sl@0
   193
	  c = CT_INT;
sl@0
   194
	  ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtol;
sl@0
   195
	  base = 10;
sl@0
   196
	  break;
sl@0
   197
sl@0
   198
	case 'i':
sl@0
   199
	  c = CT_INT;
sl@0
   200
	  ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtol;
sl@0
   201
	  base = 0;
sl@0
   202
	  break;
sl@0
   203
sl@0
   204
	case 'O':		/* compat */
sl@0
   205
	  flags |= LONG;
sl@0
   206
	  /* FALLTHROUGH */
sl@0
   207
	case 'o':
sl@0
   208
	  c = CT_INT;
sl@0
   209
	  ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtoul;
sl@0
   210
	  base = 8;
sl@0
   211
	  break;
sl@0
   212
sl@0
   213
	case 'u':
sl@0
   214
	  c = CT_INT;
sl@0
   215
	  ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtoul;
sl@0
   216
	  base = 10;
sl@0
   217
	  break;
sl@0
   218
sl@0
   219
	case 'X':		/* compat   XXX */
sl@0
   220
	case 'x':
sl@0
   221
	  flags |= PFXOK;	/* enable 0x prefixing */
sl@0
   222
	  c = CT_INT;
sl@0
   223
	  ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtoul;
sl@0
   224
	  base = 16;
sl@0
   225
	  break;
sl@0
   226
sl@0
   227
	case 'E':		/* compat   XXX */
sl@0
   228
	case 'G':		/* compat   XXX */
sl@0
   229
/* ANSI says that E,G and X behave the same way as e,g,x */
sl@0
   230
	  /* FALLTHROUGH */
sl@0
   231
	case 'e':
sl@0
   232
	case 'f':
sl@0
   233
	case 'g':
sl@0
   234
	  c = CT_FLOAT;
sl@0
   235
	  break;
sl@0
   236
sl@0
   237
	case 's':
sl@0
   238
	  c = CT_STRING;
sl@0
   239
	  break;
sl@0
   240
sl@0
   241
	case '[':
sl@0
   242
	  fmt = __sccl (ccltab, fmt);
sl@0
   243
	  flags |= NOSKIP;
sl@0
   244
	  c = CT_CCL;
sl@0
   245
	  break;
sl@0
   246
sl@0
   247
	case 'c':
sl@0
   248
	  flags |= NOSKIP;
sl@0
   249
	  c = CT_CHAR;
sl@0
   250
	  break;
sl@0
   251
sl@0
   252
	case 'p':		/* pointer format is like hex */
sl@0
   253
	  flags |= POINTER | PFXOK;
sl@0
   254
	  c = CT_INT;
sl@0
   255
	  ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtoul;
sl@0
   256
	  base = 16;
sl@0
   257
	  break;
sl@0
   258
sl@0
   259
	case 'n':
sl@0
   260
	  if (flags & SUPPRESS)	/* ??? */
sl@0
   261
	    continue;
sl@0
   262
	  if (flags & SHORT)
sl@0
   263
	    {
sl@0
   264
	      sp = va_arg (ap, short *);
sl@0
   265
	      *sp = (short)nread;
sl@0
   266
	    }
sl@0
   267
	  else if (flags & LONG)
sl@0
   268
	    {
sl@0
   269
	      lp = va_arg (ap, long *);
sl@0
   270
	      *lp = nread;
sl@0
   271
	    }
sl@0
   272
	  else
sl@0
   273
	    {
sl@0
   274
	      ip = va_arg (ap, int *);
sl@0
   275
	      *ip = nread;
sl@0
   276
	    }
sl@0
   277
	  continue;
sl@0
   278
sl@0
   279
	  /*
sl@0
   280
	   * Disgusting backwards compatibility hacks.	XXX
sl@0
   281
	   */
sl@0
   282
	case '\0':		/* compat */
sl@0
   283
	  return EOF;
sl@0
   284
sl@0
   285
	default:		/* compat */
sl@0
   286
	  if (isupper (c))
sl@0
   287
	    flags |= LONG;
sl@0
   288
	  c = CT_INT;
sl@0
   289
	  ccfn = (u_long (*)(const char *_n, char **_end_PTR, int _base))strtol;
sl@0
   290
	  base = 10;
sl@0
   291
	  break;
sl@0
   292
	}
sl@0
   293
sl@0
   294
      /*
sl@0
   295
       * We have a conversion that requires input.
sl@0
   296
       */
sl@0
   297
      if (BufferEmpty)
sl@0
   298
	goto input_failure;
sl@0
   299
sl@0
   300
      /*
sl@0
   301
       * Consume leading white space, except for formats that
sl@0
   302
       * suppress this.
sl@0
   303
       */
sl@0
   304
      if ((flags & NOSKIP) == 0)
sl@0
   305
	{
sl@0
   306
	  while (isspace (*fp->_p))
sl@0
   307
	    {
sl@0
   308
	      nread++;
sl@0
   309
	      if (--fp->_r > 0)
sl@0
   310
		fp->_p++;
sl@0
   311
	      else
sl@0
   312
	      if (__srefill (fp))
sl@0
   313
		goto input_failure;
sl@0
   314
	    }
sl@0
   315
	  /*
sl@0
   316
	   * Note that there is at least one character in the
sl@0
   317
	   * buffer, so conversions that do not set NOSKIP ca
sl@0
   318
	   * no longer result in an input failure.
sl@0
   319
	   */
sl@0
   320
	}
sl@0
   321
sl@0
   322
      /*
sl@0
   323
       * Do the conversion.
sl@0
   324
       */
sl@0
   325
      switch (c)
sl@0
   326
	{
sl@0
   327
sl@0
   328
	case CT_CHAR:
sl@0
   329
	  /* scan arbitrary characters (sets NOSKIP) */
sl@0
   330
	  if (width == 0)
sl@0
   331
	    width = 1;
sl@0
   332
	  if (flags & SUPPRESS)
sl@0
   333
	    {
sl@0
   334
	      size_t sum = 0;
sl@0
   335
sl@0
   336
	      for (;;)
sl@0
   337
		{
sl@0
   338
		  if ((n = fp->_r) < (int)width)
sl@0
   339
		    {
sl@0
   340
		      sum += n;
sl@0
   341
		      width -= n;
sl@0
   342
		      fp->_p += n;
sl@0
   343
		      if (__srefill (fp))
sl@0
   344
			{
sl@0
   345
			  if (sum == 0)
sl@0
   346
			    goto input_failure;
sl@0
   347
			  break;
sl@0
   348
			}
sl@0
   349
		    }
sl@0
   350
		  else
sl@0
   351
		    {
sl@0
   352
		      sum += width;
sl@0
   353
		      fp->_r -= width;
sl@0
   354
		      fp->_p += width;
sl@0
   355
		      break;
sl@0
   356
		    }
sl@0
   357
		}
sl@0
   358
	      nread += sum;
sl@0
   359
	    }
sl@0
   360
	  else
sl@0
   361
	    {
sl@0
   362
	      size_t r = fread ((void*) va_arg (ap, char *), 1, width, fp);
sl@0
   363
sl@0
   364
	      if (r == 0)
sl@0
   365
		goto input_failure;
sl@0
   366
	      nread += r;
sl@0
   367
	      nassigned++;
sl@0
   368
	    }
sl@0
   369
	  break;
sl@0
   370
sl@0
   371
	case CT_CCL:
sl@0
   372
	  /* scan a (nonempty) character class (sets NOSKIP) */
sl@0
   373
	  if (width == 0)
sl@0
   374
	    width = (unsigned long)(~0);		/* `infinity' */
sl@0
   375
	  /* take only those things in the class */
sl@0
   376
	  if (flags & SUPPRESS)
sl@0
   377
	    {
sl@0
   378
	      n = 0;
sl@0
   379
	      while (ccltab[*fp->_p])
sl@0
   380
		{
sl@0
   381
		  n++, fp->_r--, fp->_p++;
sl@0
   382
		  if (--width == 0)
sl@0
   383
		    break;
sl@0
   384
		  if (BufferEmpty)
sl@0
   385
		    {
sl@0
   386
		      if (n == 0)
sl@0
   387
			goto input_failure;
sl@0
   388
		      break;
sl@0
   389
		    }
sl@0
   390
		}
sl@0
   391
	      if (n == 0)
sl@0
   392
		goto match_failure;
sl@0
   393
	    }
sl@0
   394
	  else
sl@0
   395
	    {
sl@0
   396
	      p0 = p = va_arg (ap, char *);
sl@0
   397
	      while (ccltab[*fp->_p])
sl@0
   398
		{
sl@0
   399
		  fp->_r--;
sl@0
   400
		  *p++ = *fp->_p++;
sl@0
   401
		  if (--width == 0)
sl@0
   402
		    break;
sl@0
   403
		  if (BufferEmpty)
sl@0
   404
		    {
sl@0
   405
		      if (p == p0)
sl@0
   406
			goto input_failure;
sl@0
   407
		      break;
sl@0
   408
		    }
sl@0
   409
		}
sl@0
   410
	      n = p - p0;
sl@0
   411
	      if (n == 0)
sl@0
   412
		goto match_failure;
sl@0
   413
	      *p = 0;
sl@0
   414
	      nassigned++;
sl@0
   415
	    }
sl@0
   416
	  nread += n;
sl@0
   417
	  break;
sl@0
   418
sl@0
   419
	case CT_STRING:
sl@0
   420
	  /* like CCL, but zero-length string OK, & no NOSKIP */
sl@0
   421
	  if (width == 0)
sl@0
   422
	    width = (unsigned long)(~0);
sl@0
   423
	  if (flags & SUPPRESS)
sl@0
   424
	    {
sl@0
   425
	      n = 0;
sl@0
   426
	      while (!isspace (*fp->_p))
sl@0
   427
		{
sl@0
   428
		  n++, fp->_r--, fp->_p++;
sl@0
   429
		  if (--width == 0)
sl@0
   430
		    break;
sl@0
   431
		  if (BufferEmpty)
sl@0
   432
		    break;
sl@0
   433
		}
sl@0
   434
	      nread += n;
sl@0
   435
	    }
sl@0
   436
	  else
sl@0
   437
	    {
sl@0
   438
	      p0 = p = va_arg (ap, char *);
sl@0
   439
	      while (!isspace (*fp->_p))
sl@0
   440
		{
sl@0
   441
		  fp->_r--;
sl@0
   442
		  *p++ = *fp->_p++;
sl@0
   443
		  if (--width == 0)
sl@0
   444
		    break;
sl@0
   445
		  if (BufferEmpty)
sl@0
   446
		    break;
sl@0
   447
		}
sl@0
   448
	      *p = 0;
sl@0
   449
	      nread += p - p0;
sl@0
   450
	      nassigned++;
sl@0
   451
	    }
sl@0
   452
	  continue;
sl@0
   453
sl@0
   454
	case CT_INT:
sl@0
   455
	  /* scan an integer as if by strtol/strtoul */
sl@0
   456
#ifdef hardway
sl@0
   457
	  if (width == 0 || width > sizeof (buf) - 1)
sl@0
   458
	    width = sizeof (buf) - 1;
sl@0
   459
#else
sl@0
   460
	  /* size_t is unsigned, hence this optimisation */
sl@0
   461
	  if (--width > sizeof (buf) - 2)
sl@0
   462
	    width = sizeof (buf) - 2;
sl@0
   463
	  width++;
sl@0
   464
#endif
sl@0
   465
	  flags |= SIGNOK | NDIGITS | NZDIGITS;
sl@0
   466
	  for (p = buf; width; width--)
sl@0
   467
	    {
sl@0
   468
	      c = *fp->_p;
sl@0
   469
	      /*
sl@0
   470
	       * Switch on the character; `goto ok' if we
sl@0
   471
	       * accept it as a part of number.
sl@0
   472
	       */
sl@0
   473
	      switch (c)
sl@0
   474
		{
sl@0
   475
		  /*
sl@0
   476
		   * The digit 0 is always legal, but is special.
sl@0
   477
		   * For %i conversions, if no digits (zero or nonzero)
sl@0
   478
		   * have been scanned (only signs), we will have base==0.
sl@0
   479
		   * In that case, we should set it to 8 and enable 0x
sl@0
   480
		   * prefixing. Also, if we have not scanned zero digits
sl@0
   481
		   * before this, do not turn off prefixing (someone else
sl@0
   482
		   * will turn it off if we have scanned any nonzero digits).
sl@0
   483
		   */
sl@0
   484
		case '0':
sl@0
   485
		  if (base == 0)
sl@0
   486
		    {
sl@0
   487
		      base = 8;
sl@0
   488
		      flags |= PFXOK;
sl@0
   489
		    }
sl@0
   490
		  if (flags & NZDIGITS)
sl@0
   491
		    flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
sl@0
   492
		  else
sl@0
   493
		    flags &= ~(SIGNOK | PFXOK | NDIGITS);
sl@0
   494
		  goto ok;
sl@0
   495
sl@0
   496
		  /* 1 through 7 always legal */
sl@0
   497
		case '1':
sl@0
   498
		case '2':
sl@0
   499
		case '3':
sl@0
   500
		case '4':
sl@0
   501
		case '5':
sl@0
   502
		case '6':
sl@0
   503
		case '7':
sl@0
   504
		  base = basefix[base];
sl@0
   505
		  flags &= ~(SIGNOK | PFXOK | NDIGITS);
sl@0
   506
		  goto ok;
sl@0
   507
sl@0
   508
		  /* digits 8 and 9 ok iff decimal or hex */
sl@0
   509
		case '8':
sl@0
   510
		case '9':
sl@0
   511
		  base = basefix[base];
sl@0
   512
		  if (base <= 8)
sl@0
   513
		    break;	/* not legal here */
sl@0
   514
		  flags &= ~(SIGNOK | PFXOK | NDIGITS);
sl@0
   515
		  goto ok;
sl@0
   516
sl@0
   517
		  /* letters ok iff hex */
sl@0
   518
		case 'A':
sl@0
   519
		case 'B':
sl@0
   520
		case 'C':
sl@0
   521
		case 'D':
sl@0
   522
		case 'E':
sl@0
   523
		case 'F':
sl@0
   524
		case 'a':
sl@0
   525
		case 'b':
sl@0
   526
		case 'c':
sl@0
   527
		case 'd':
sl@0
   528
		case 'e':
sl@0
   529
		case 'f':
sl@0
   530
		  /* no need to fix base here */
sl@0
   531
		  if (base <= 10)
sl@0
   532
		    break;	/* not legal here */
sl@0
   533
		  flags &= ~(SIGNOK | PFXOK | NDIGITS);
sl@0
   534
		  goto ok;
sl@0
   535
sl@0
   536
		  /* sign ok only as first character */
sl@0
   537
		case '+':
sl@0
   538
		case '-':
sl@0
   539
		  if (flags & SIGNOK)
sl@0
   540
		    {
sl@0
   541
		      flags &= ~SIGNOK;
sl@0
   542
		      goto ok;
sl@0
   543
		    }
sl@0
   544
		  break;
sl@0
   545
sl@0
   546
		  /* x ok iff flag still set & 2nd char */
sl@0
   547
		case 'x':
sl@0
   548
		case 'X':
sl@0
   549
		  if (flags & PFXOK && p == buf + 1)
sl@0
   550
		    {
sl@0
   551
		      base = 16;/* if %i */
sl@0
   552
		      flags &= ~PFXOK;
sl@0
   553
		      goto ok;
sl@0
   554
		    }
sl@0
   555
		  break;
sl@0
   556
		}
sl@0
   557
sl@0
   558
	      /*
sl@0
   559
	       * If we got here, c is not a legal character
sl@0
   560
	       * for a number.  Stop accumulating digits.
sl@0
   561
	       */
sl@0
   562
	      break;
sl@0
   563
	    ok:
sl@0
   564
	      /*
sl@0
   565
	       * c is legal: store it and look at the next.
sl@0
   566
	       */
sl@0
   567
	      *p++ = (char)c;
sl@0
   568
	      if (--fp->_r > 0)
sl@0
   569
		fp->_p++;
sl@0
   570
	      else
sl@0
   571
	      if (__srefill (fp))
sl@0
   572
		break;		/* EOF */
sl@0
   573
	    }
sl@0
   574
	  /*
sl@0
   575
	   * If we had only a sign, it is no good; push back the sign.
sl@0
   576
	   * If the number ends in `x', it was [sign] '0' 'x', so push back
sl@0
   577
	   * the x and treat it as [sign] '0'.
sl@0
   578
	   */
sl@0
   579
	  if (flags & NDIGITS)
sl@0
   580
	    {
sl@0
   581
	      if (p > buf)
sl@0
   582
		(void) ungetc (*(u_char *)-- p, fp);
sl@0
   583
	      goto match_failure;
sl@0
   584
	    }
sl@0
   585
	  c = ((u_char *) p)[-1];
sl@0
   586
	  if (c == 'x' || c == 'X')
sl@0
   587
	    {
sl@0
   588
	      --p;
sl@0
   589
	      /*(void)*/ ungetc (c, fp);
sl@0
   590
	    }
sl@0
   591
	  if ((flags & SUPPRESS) == 0)
sl@0
   592
	    {
sl@0
   593
	      u_long res;
sl@0
   594
sl@0
   595
	      *p = 0;
sl@0
   596
	      res = (*ccfn) (buf, (char **) NULL, base);
sl@0
   597
	      if (flags & POINTER)
sl@0
   598
		*(va_arg (ap, void* *)) = (void*) res;
sl@0
   599
	      else if (flags & SHORT)
sl@0
   600
		{
sl@0
   601
		  sp = va_arg (ap, short *);
sl@0
   602
		  *sp = (short)res;
sl@0
   603
		}
sl@0
   604
	      else if (flags & LONG)
sl@0
   605
		{
sl@0
   606
		  lp = va_arg (ap, long *);
sl@0
   607
		  *lp = res;
sl@0
   608
		}
sl@0
   609
	      else
sl@0
   610
		{
sl@0
   611
		  ip = va_arg (ap, int *);
sl@0
   612
		  *ip = res;
sl@0
   613
		}
sl@0
   614
	      nassigned++;
sl@0
   615
	    }
sl@0
   616
	  nread += p - buf;
sl@0
   617
	  break;
sl@0
   618
sl@0
   619
	case CT_FLOAT:
sl@0
   620
	  /* scan a floating point number as if by strtod */
sl@0
   621
#ifdef hardway
sl@0
   622
	  if (width == 0 || width > sizeof (buf) - 1)
sl@0
   623
	    width = sizeof (buf) - 1;
sl@0
   624
#else
sl@0
   625
	  /* size_t is unsigned, hence this optimisation */
sl@0
   626
	  if (--width > sizeof (buf) - 2)
sl@0
   627
	    width = sizeof (buf) - 2;
sl@0
   628
	  width++;
sl@0
   629
#endif
sl@0
   630
	  flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
sl@0
   631
	  for (p = buf; width; width--)
sl@0
   632
	    {
sl@0
   633
	      c = *fp->_p;
sl@0
   634
	      /*
sl@0
   635
	       * This code mimicks the integer conversion
sl@0
   636
	       * code, but is much simpler.
sl@0
   637
	       */
sl@0
   638
	      switch (c)
sl@0
   639
		{
sl@0
   640
sl@0
   641
		case '0':
sl@0
   642
		case '1':
sl@0
   643
		case '2':
sl@0
   644
		case '3':
sl@0
   645
		case '4':
sl@0
   646
		case '5':
sl@0
   647
		case '6':
sl@0
   648
		case '7':
sl@0
   649
		case '8':
sl@0
   650
		case '9':
sl@0
   651
		  flags &= ~(SIGNOK | NDIGITS);
sl@0
   652
		  goto fok;
sl@0
   653
sl@0
   654
		case '+':
sl@0
   655
		case '-':
sl@0
   656
		  if (flags & SIGNOK)
sl@0
   657
		    {
sl@0
   658
		      flags &= ~SIGNOK;
sl@0
   659
		      goto fok;
sl@0
   660
		    }
sl@0
   661
		  break;
sl@0
   662
		case '.':
sl@0
   663
		  if (flags & DPTOK)
sl@0
   664
		    {
sl@0
   665
		      flags &= ~(SIGNOK | DPTOK);
sl@0
   666
		      goto fok;
sl@0
   667
		    }
sl@0
   668
		  break;
sl@0
   669
		case 'e':
sl@0
   670
		case 'E':
sl@0
   671
		  /* no exponent without some digits */
sl@0
   672
		  if ((flags & (NDIGITS | EXPOK)) == EXPOK)
sl@0
   673
		    {
sl@0
   674
		      flags =
sl@0
   675
			(flags & ~(EXPOK | DPTOK)) |
sl@0
   676
			SIGNOK | NDIGITS;
sl@0
   677
		      goto fok;
sl@0
   678
		    }
sl@0
   679
		  break;
sl@0
   680
		}
sl@0
   681
	      break;
sl@0
   682
	    fok:
sl@0
   683
	      *p++ = (char)c;
sl@0
   684
	      if (--fp->_r > 0)
sl@0
   685
		fp->_p++;
sl@0
   686
	      else
sl@0
   687
	      if (__srefill (fp))
sl@0
   688
		break;		/* EOF */
sl@0
   689
	    }
sl@0
   690
	  /*
sl@0
   691
	   * If no digits, might be missing exponent digits
sl@0
   692
	   * (just give back the exponent) or might be missing
sl@0
   693
	   * regular digits, but had sign and/or decimal point.
sl@0
   694
	   */
sl@0
   695
	  if (flags & NDIGITS)
sl@0
   696
	    {
sl@0
   697
	      if (flags & EXPOK)
sl@0
   698
		{
sl@0
   699
		  /* no digits at all */
sl@0
   700
		  while (p > buf)
sl@0
   701
		    ungetc (*(u_char *)-- p, fp);
sl@0
   702
		  goto match_failure;
sl@0
   703
		}
sl@0
   704
	      /* just a bad exponent (e and maybe sign) */
sl@0
   705
	      c = *(u_char *)-- p;
sl@0
   706
	      if (c != 'e' && c != 'E')
sl@0
   707
		{
sl@0
   708
		  (void) ungetc (c, fp);	/* sign */
sl@0
   709
		  c = *(u_char *)-- p;
sl@0
   710
		}
sl@0
   711
	      (void) ungetc (c, fp);
sl@0
   712
	    }
sl@0
   713
	  if ((flags & SUPPRESS) == 0)
sl@0
   714
	    {
sl@0
   715
	      double res;
sl@0
   716
sl@0
   717
	      *p = 0;
sl@0
   718
	      res = atof (buf);
sl@0
   719
	      if (flags & LONG)
sl@0
   720
		{
sl@0
   721
		  dp = va_arg (ap, double *);
sl@0
   722
		  *dp = res;
sl@0
   723
		}
sl@0
   724
	      else
sl@0
   725
		{
sl@0
   726
		  flp = va_arg (ap, float *);
sl@0
   727
		  *flp = (float)res;
sl@0
   728
		}
sl@0
   729
	      nassigned++;
sl@0
   730
	    }
sl@0
   731
	  nread += p - buf;
sl@0
   732
	  break;
sl@0
   733
	}
sl@0
   734
    }
sl@0
   735
input_failure:
sl@0
   736
  return nassigned ? nassigned : -1;
sl@0
   737
match_failure:
sl@0
   738
  return nassigned;
sl@0
   739
}
sl@0
   740
sl@0
   741
/*
sl@0
   742
 * Fill in the given table from the scanset at the given format
sl@0
   743
 * (just after `[').  Return a pointer to the character past the
sl@0
   744
 * closing `]'.  The table has a 1 wherever characters should be
sl@0
   745
 * considered part of the scanset.
sl@0
   746
 */
sl@0
   747
sl@0
   748
/*static*/
sl@0
   749
u_char *
sl@0
   750
__sccl (register char *tab,register u_char *fmt)
sl@0
   751
{
sl@0
   752
  register int c, n, v;
sl@0
   753
sl@0
   754
  /* first `clear' the whole table */
sl@0
   755
  c = *fmt++;			/* first char hat => negated scanset */
sl@0
   756
  if (c == '^')
sl@0
   757
    {
sl@0
   758
      v = 1;			/* default => accept */
sl@0
   759
      c = *fmt++;		/* get new first char */
sl@0
   760
    }
sl@0
   761
  else
sl@0
   762
    v = 0;			/* default => reject */
sl@0
   763
  /* should probably use memset here */
sl@0
   764
  for (n = 0; n < 256; n++)
sl@0
   765
    tab[n] = (char)v;
sl@0
   766
  if (c == 0)
sl@0
   767
    return fmt - 1;		/* format ended before closing ] */
sl@0
   768
sl@0
   769
  /*
sl@0
   770
   * Now set the entries corresponding to the actual scanset to the
sl@0
   771
   * opposite of the above.
sl@0
   772
   *
sl@0
   773
   * The first character may be ']' (or '-') without being special; the
sl@0
   774
   * last character may be '-'.
sl@0
   775
   */
sl@0
   776
sl@0
   777
  v = 1 - v;
sl@0
   778
  for (;;)
sl@0
   779
    {
sl@0
   780
      tab[c] = (char)v;		/* take character c */
sl@0
   781
    doswitch:
sl@0
   782
      n = *fmt++;		/* and examine the next */
sl@0
   783
      switch (n)
sl@0
   784
	{
sl@0
   785
sl@0
   786
	case 0:		/* format ended too soon */
sl@0
   787
	  return fmt - 1;
sl@0
   788
sl@0
   789
	case '-':
sl@0
   790
	  /*
sl@0
   791
	   * A scanset of the form [01+-] is defined as `the digit 0, the
sl@0
   792
	   * digit 1, the character +, the character -', but the effect of a
sl@0
   793
	   * scanset such as [a-zA-Z0-9] is implementation defined.  The V7
sl@0
   794
	   * Unix scanf treats `a-z' as `the letters a through z', but treats
sl@0
   795
	   * `a-a' as `the letter a, the character -, and the letter a'.
sl@0
   796
	   *
sl@0
   797
	   * For compatibility, the `-' is not considerd to define a range if
sl@0
   798
	   * the character following it is either a close bracket (required by
sl@0
   799
	   * ANSI) or is not numerically greater than the character we just
sl@0
   800
	   * stored in the table (c).
sl@0
   801
	   */
sl@0
   802
	  n = *fmt;
sl@0
   803
	  if (n == ']' || n < c)
sl@0
   804
	    {
sl@0
   805
	      c = '-';
sl@0
   806
	      break;		/* resume the for(;;) */
sl@0
   807
	    }
sl@0
   808
	  fmt++;
sl@0
   809
	  do
sl@0
   810
	    {			/* fill in the range */
sl@0
   811
	      tab[++c] = (char)v;
sl@0
   812
	    }
sl@0
   813
	  while (c < n);
sl@0
   814
#if 1			/* XXX another disgusting compatibility hack */
sl@0
   815
	  /*
sl@0
   816
	   * Alas, the V7 Unix scanf also treats formats such
sl@0
   817
	   * as [a-c-e] as `the letters a through e'. This too
sl@0
   818
	   * is permitted by the standard....
sl@0
   819
	   */
sl@0
   820
	  goto doswitch;
sl@0
   821
#else
sl@0
   822
	  c = *fmt++;
sl@0
   823
	  if (c == 0)
sl@0
   824
	    return fmt - 1;
sl@0
   825
	  if (c == ']')
sl@0
   826
	    return fmt;
sl@0
   827
sl@0
   828
	  break;
sl@0
   829
#endif
sl@0
   830
sl@0
   831
	case ']':		/* end of scanset */
sl@0
   832
	  return fmt;
sl@0
   833
sl@0
   834
	default:		/* just another character */
sl@0
   835
	  c = n;
sl@0
   836
	  break;
sl@0
   837
	}
sl@0
   838
    }
sl@0
   839
  /* NOTREACHED */
sl@0
   840
}