Exemplo n.º 1
0
/*
 * Internal (non-MPSAFE) version of fgetwc().  This version takes an
 * mbstate_t argument specifying the initial conversion state.  For
 * wide streams, this should always be fp->_mbstate.  On return, *nread
 * is set to the number of bytes read.
 */
wint_t 
__fgetwc_mbs(FILE *fp, mbstate_t *mbs, int *nread, locale_t locale)
{
	wchar_t wc;
	size_t nconv;
	struct xlocale_ctype *l = XLOCALE_CTYPE(locale);

	*nread = 0;
	if (fp->_r <= 0 && __srefill(fp))
		return (WEOF);
	do {
		nconv = l->__mbrtowc(&wc, fp->_p, fp->_r, mbs);
		if (nconv == (size_t)-1)
			break;
		else if (nconv == (size_t)-2)
			continue;
		else if (nconv == 0) {
			fp->_p++;
			fp->_r--;
			(*nread)++;
			return (L'\0');
		} else {
			fp->_p += nconv;
			fp->_r -= nconv;
			*nread += nconv;
			return (wc);
		}
	} while (__srefill(fp) == 0);
	fp->_flags |= __SERR;
	errno = EILSEQ;
	return (WEOF);
}
Exemplo n.º 2
0
static __inline int
convert_string(FILE *fp, char * p, int width)
{
	char *p0;
	int n;

	if (p == SUPPRESS_PTR) {
		n = 0;
		while (!isspace(*fp->_p)) {
			n++, fp->_r--, fp->_p++;
			if (--width == 0)
				break;
			if (fp->_r <= 0 && __srefill(fp))
				break;
		}
	} else {
		p0 = p;
		while (!isspace(*fp->_p)) {
			fp->_r--;
			*p++ = *fp->_p++;
			if (--width == 0)
				break;
			if (fp->_r <= 0 && __srefill(fp))
				break;
		}
		*p = 0;
		n = p - p0;
	}
	return (n);
}
Exemplo n.º 3
0
/**
Read block of data from a stream.
Read count number of items each one with a size of size bytes from the stream
and stores it in the specified buffer.
Stream's postion indicator is increased by the number of bytes readed.
Total amount of bytes read is (size x count).
@return   The total number of items readed is returned.
@param buf Pointer to the destination structure with a minimum size of (size*count) bytes. 
@param size Size in bytes of each item to be read. 
@param count Number of items, each one with a size of size bytes. 
@param fp pointer to an open file.
*/
EXPORT_C size_t
fread (void *buf, size_t size, size_t count, FILE * fp)
{
  register size_t resid;
  register char *p;
  register int r;
  size_t total;

  if ((resid = count * size) == 0)
    return 0;
  if (fp->_r < 0)
    fp->_r = 0;
  total = resid;
  p = (char*)buf;
  while ((int)resid > (r = fp->_r))
    {
      (void) memcpy ((void *) p, (void *) fp->_p, (size_t) r);
      fp->_p += r;
      /* fp->_r = 0 ... done in __srefill */
      p += r;
      resid -= r;
      if (__srefill (fp))
	{
	  /* no more input: return partial result */
	  return (total - resid) / size;
	}
    }
  (void) memcpy ((void *) p, (void *) fp->_p, resid);
  fp->_r -= resid;
  fp->_p += resid;
  return count;
}
Exemplo n.º 4
0
size_t fread(void *buf,size_t size,size_t count,FILE *fp)
{
	register size_t resid;
	register char *p;
	register int r;
	size_t total;

	/*
	 * The ANSI standard requires a return value of 0 for a count
	 * or a size of 0.  Peculiarily, it imposes no such requirements
	 * on fwrite; it only requires fread to be broken.
	 */
	if ((resid = count * size) == 0)
		return (0);
	if (TOFILE(fp)->_rcnt < 0)
		TOFILE(fp)->_rcnt = 0;
	total = resid;
	p = buf;
	while (resid > (size_t)(r = TOFILE(fp)->_rcnt)) {
		(void)memcpy((void *)p, (void *)TOFILE(fp)->_ptr, (size_t)r);
		TOFILE(fp)->_ptr += r;
		/* fp->_rcnt = 0 ... done in __srefill */
		p += r;
		resid -= r;
		if (__srefill((FILE *)TOFILE(fp))) {
			/* no more input: return partial result */
			return ((total - resid) / size);
		}
	}
	(void)memcpy((void *)p, (void *)TOFILE(fp)->_ptr, resid);
	TOFILE(fp)->_rcnt -= resid;
	TOFILE(fp)->_ptr += resid;
	return (count);
}
Exemplo n.º 5
0
static __inline int
convert_char(FILE *fp, char * p, int width)
{
	int n;

	if (p == SUPPRESS_PTR) {
		size_t sum = 0;
		for (;;) {
			if ((n = fp->_r) < width) {
				sum += n;
				width -= n;
				fp->_p += n;
				if (__srefill(fp)) {
					if (sum == 0)
						return (-1);
					break;
				}
			} else {
				sum += width;
				fp->_r -= width;
				fp->_p += width;
				break;
			}
		}
		return (sum);
	} else {
		size_t r = __fread(p, 1, width, fp);

		if (r == 0)
			return (-1);
		return (r);
	}
}
Exemplo n.º 6
0
/*
 * Read at most n-1 characters from the given file.
 * Stop when a newline has been read, or the count runs out.
 * Return first argument, or NULL if no characters were read.
 */
EXPORT_C char *
fgets(char *buf, int n,	FILE *fp)	
{
	size_t len;
	char *s;
	unsigned char *p, *t;

	if (n <= 0)		/* sanity check */
		return (NULL);

	FLOCKFILE(fp);
	ORIENT(fp, -1);
	s = buf;
	n--;			/* leave space for NUL */
	while (n != 0) {
		/*
		 * If the buffer is empty, refill it.
		 */
		if ((len = fp->_r) <= 0) {
			if (__srefill(fp)) {
				/* EOF/error: stop with partial or no line */
				if (s == buf) {
					FUNLOCKFILE(fp);
					return (NULL);
				}
				break;
			}
			len = fp->_r;
		}
		p = fp->_p;

		/*
		 * Scan through at most n bytes of the current buffer,
		 * looking for '\n'.  If found, copy up to and including
		 * newline, and stop.  Otherwise, copy entire chunk
		 * and loop.
		 */
		if (len > n)
			len = n;
		t = memchr((void *)p, '\n', len);
		if (t != NULL) {
			len = ++t - p;
			fp->_r -= len;
			fp->_p = t;
			(void)memcpy((void *)s, (void *)p, len);
			s[len] = 0;
			FUNLOCKFILE(fp);
			return (buf);
		}
		fp->_r -= len;
		fp->_p += len;
		(void)memcpy((void *)s, (void *)p, len);
		s += len;
		n -= len;
	}
	*s = 0;
	FUNLOCKFILE(fp);
	return (buf);
}
Exemplo n.º 7
0
/*
 * Handle getc() when the buffer ran out:
 * Refill, then return the first character
 * in the newly-filled buffer.
 */
int
__srget(FILE *fp)
{
	if (__srefill(fp) == 0) {
		fp->pub._r--;
		return (*fp->pub._p++);
	}
	return (EOF);
}
Exemplo n.º 8
0
int __srget(register FILE *fp)
{
    if (__srefill(fp) == 0)
    {
        fp->_r--;
        return *fp->_p++;
    }
    return EOF;
}
Exemplo n.º 9
0
I getdelim(S *s,size_t*n, I d, FILE *f)//target, current capacity, delimiter, file
{
  unsigned char *q;
  I w=0;

  flockfile(f);
  //ORIENT(f,-1)  //is this dangerous?

  if (!s) {errno = EINVAL; goto error;}

  if (f->_r <= 0 && __srefill(f))
  {
    /* If f is at EOF already, we just need space for the NUL. */
    if (__sferror(f) || expander(s, 1)) goto error;
    funlockfile(f);
    (*s)[0] = '\0';
    R *n=-1;
  }

  while ((q = memchr(f->_p, d, f->_r)) == NULL)
  {
    if (appender(s, &w, (S) f->_p, f->_r)) goto error;
    if (__srefill(f))
    {
      if (__sferror(f)) goto error;
      goto done;  /* hit EOF */
    }
  }
  q++;  /* snarf the delimiter, too */
  if (appender(s, &w, (S) f->_p, q - f->_p)) goto error;
  f->_r -= q - f->_p;
  f->_p = q;

  done:
    /* Invariant: *s has space for at least w+1 bytes. */
    (*s)[w] = '\0';
    funlockfile(f);
    R *n=w;

  error:
    f->_flags |= __SERR;
    funlockfile(f);
    R *n=-1;
}
Exemplo n.º 10
0
/*
 * Handle getc() when the buffer ran out:
 * Refill, then return the first character
 * in the newly-filled buffer.
 */
int
__srget(FILE *fp)
{
	_SET_ORIENTATION(fp, -1);
	if (__srefill(fp) == 0) {
		fp->_r--;
		return (*fp->_p++);
	}
	return (EOF);
}
Exemplo n.º 11
0
/*
 * Non-MT-safe version.
 */
wint_t
__fgetwc(FILE *fp, locale_t locale)
{
	wchar_t wc;
	size_t nconv;
	struct xlocale_ctype *l = XLOCALE_CTYPE(locale);

	if (fp->_r <= 0 && __srefill(fp))
		return (WEOF);
	if (MB_CUR_MAX == 1) {
		/* Fast path for single-byte encodings. */
		wc = *fp->_p++;
		fp->_r--;
		return (wc);
	}
	do {
		nconv = l->__mbrtowc(&wc, fp->_p, fp->_r, &fp->_mbstate);
		if (nconv == (size_t)-1)
			break;
		else if (nconv == (size_t)-2)
			continue;
		else if (nconv == 0) {
			/*
			 * Assume that the only valid representation of
			 * the null wide character is a single null byte.
			 */
			fp->_p++;
			fp->_r--;
			return (L'\0');
		} else {
			fp->_p += nconv;
			fp->_r -= nconv;
			return (wc);
		}
	} while (__srefill(fp) == 0);
	fp->_flags |= __SERR;
	errno = EILSEQ;
	return (WEOF);
}
Exemplo n.º 12
0
static __inline int
convert_ccl(FILE *fp, char * p, int width, const char *ccltab)
{
	char *p0;
	int n;

	if (p == SUPPRESS_PTR) {
		n = 0;
		while (ccltab[*fp->_p]) {
			n++, fp->_r--, fp->_p++;
			if (--width == 0)
				break;
			if (fp->_r <= 0 && __srefill(fp)) {
				if (n == 0)
					return (-1);
				break;
			}
		}
	} else {
		p0 = p;
		while (ccltab[*fp->_p]) {
			fp->_r--;
			*p++ = *fp->_p++;
			if (--width == 0)
				break;
			if (fp->_r <= 0 && __srefill(fp)) {
				if (p == p0)
					return (-1);
				break;
			}
		}
		n = p - p0;
		if (n == 0)
			return (0);
		*p = 0;
	}
	return (n);
}
Exemplo n.º 13
0
/*
 * Handle getc() when the buffer ran out:
 * Refill, then return the first character
 * in the newly-filled buffer.
 */
int
__srget(FILE *fp)
{
  _DIAGASSERT(fp != NULL);

  if(fp != NULL) {
  _SET_ORIENTATION(fp, -1);
  if (__srefill(fp) == 0) {
    fp->_r--;
    return (*fp->_p++);
    }
  }
  return (EOF);
}
Exemplo n.º 14
0
size_t
fread(void *buf, size_t size, size_t count, FILE *fp)
{
  size_t resid;
  char *p;
  int r;
  size_t total;

  _DIAGASSERT(fp != NULL);
  if(fp == NULL) {
    errno = EINVAL;
    return (0);
  }
  /*
   * The ANSI standard requires a return value of 0 for a count
   * or a size of 0.  Whilst ANSI imposes no such requirements on
   * fwrite, the SUSv2 does.
   */
  if ((resid = count * size) == 0)
    return (0);

  _DIAGASSERT(buf != NULL);

  FLOCKFILE(fp);
  if (fp->_r < 0)
    fp->_r = 0;
  total = resid;
  p = buf;
  while (resid > (size_t)(r = fp->_r)) {
    (void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
    fp->_p += r;
    /* fp->_r = 0 ... done in __srefill */
    p += r;
    resid -= r;
    if (__srefill(fp)) {
      /* no more input: return partial result */
      FUNLOCKFILE(fp);
      return ((total - resid) / size);
    }
  }
  (void)memcpy((void *)p, (void *)fp->_p, resid);
  fp->_r -= (int)resid;
  fp->_p += resid;
  FUNLOCKFILE(fp);
  return (count);
}
Exemplo n.º 15
0
size_t
__sfread(void *buf, size_t size, size_t count, FILE *fp)
{
	size_t resid;
	char *p;
	int r;
	size_t total;

	/*
	 * ANSI and SUSv2 require a return value of 0 if size or count are 0.
	 */
	if ((resid = count * size) == 0)
		return (0);
	/*FLOCKFILE(fp);*/
	_SET_ORIENTATION(fp, -1);
	if (fp->_r < 0)
		fp->_r = 0;
	total = resid;
	p = buf;
	while (resid > (r = fp->_r)) {
		(void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
		fp->_p += r;
		/* fp->_r = 0 ... done in __srefill */
		p += r;
		resid -= r;
		if (__srefill(fp)) {
			/* no more input: return partial result */
			/*FUNLOCKFILE(fp);*/
			return ((total - resid) / size);
		}
	}
	(void)memcpy((void *)p, (void *)fp->_p, resid);
	fp->_r -= resid;
	fp->_p += resid;
	/*FUNLOCKFILE(fp);*/
	return (count);
}
Exemplo n.º 16
0
/*
 * Get an input line.  The returned pointer often (but not always)
 * points into a stdio buffer.  Fgetln does not alter the text of
 * the returned line (which is thus not a C string because it will
 * not necessarily end with '\0'), but does allow callers to modify
 * it if they wish.  Thus, we set __SMOD in case the caller does.
 */
char *
fgetln(FILE *fp, size_t *lenp)
{
	unsigned char *p;
	size_t len;
	size_t off;

	FLOCKFILE(fp);
	ORIENT(fp, -1);
	/* make sure there is input */
	if (fp->pub._r <= 0 && __srefill(fp)) {
		*lenp = 0;
		FUNLOCKFILE(fp);
		return (NULL);
	}

	/* look for a newline in the input */
	if ((p = memchr((void *)fp->pub._p, '\n', (size_t)fp->pub._r)) != NULL) {
		char *ret;

		/*
		 * Found one.  Flag buffer as modified to keep fseek from
		 * `optimising' a backward seek, in case the user stomps on
		 * the text.
		 */
		p++;		/* advance over it */
		ret = (char *)fp->pub._p;
		*lenp = len = p - fp->pub._p;
		fp->pub._flags |= __SMOD;
		fp->pub._r -= len;
		fp->pub._p = p;
		FUNLOCKFILE(fp);
		return (ret);
	}

	/*
	 * We have to copy the current buffered data to the line buffer.
	 * As a bonus, though, we can leave off the __SMOD.
	 *
	 * OPTIMISTIC is length that we (optimistically) expect will
	 * accomodate the `rest' of the string, on each trip through the
	 * loop below.
	 */
#define OPTIMISTIC 80

	for (len = fp->pub._r, off = 0;; len += fp->pub._r) {
		size_t diff;

		/*
		 * Make sure there is room for more bytes.  Copy data from
		 * file buffer to line buffer, refill file and look for
		 * newline.  The loop stops only when we find a newline.
		 */
		if (__slbexpand(fp, len + OPTIMISTIC))
			goto error;
		memcpy((void *)(fp->_lb._base + off), (void *)fp->pub._p,
		    len - off);
		off = len;
		if (__srefill(fp))
			break;	/* EOF or error: return partial line */
		if ((p = memchr((void *)fp->pub._p, '\n', (size_t)fp->pub._r))
		    == NULL)
			continue;

		/* got it: finish up the line (like code above) */
		p++;
		diff = p - fp->pub._p;
		len += diff;
		if (__slbexpand(fp, len))
			goto error;
		memcpy((void *)(fp->_lb._base + off), (void *)fp->pub._p, diff);
		fp->pub._r -= diff;
		fp->pub._p = p;
		break;
	}
	*lenp = len;
#ifdef notdef
	fp->_lb._base[len] = 0;
#endif
	FUNLOCKFILE(fp);
	return ((char *)fp->_lb._base);

error:
	*lenp = 0;		/* ??? */
	FUNLOCKFILE(fp);
	return (NULL);		/* ??? */
}
Exemplo n.º 17
0
/*
 * Seek the given file to the given offset.
 * `Whence' must be one of the three SEEK_* macros.
 */
int
_fseeko(FILE *fp, off_t offset, int whence, int ltest)
{
	fpos_t (*seekfn)(void *, fpos_t, int);
	fpos_t target, curoff, ret;
	size_t n;
	struct stat st;
	int havepos;

	/*
	 * Have to be able to seek.
	 */
	if ((seekfn = fp->_seek) == NULL) {
		errno = ESPIPE;		/* historic practice */
		return (-1);
	}

	/*
	 * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
	 * After this, whence is either SEEK_SET or SEEK_END.
	 */
	switch (whence) {

	case SEEK_CUR:
		/*
		 * In order to seek relative to the current stream offset,
		 * we have to first find the current stream offset via
		 * ftell (see ftell for details).
		 */
		if (_ftello(fp, &curoff))
			return (-1);
		if (curoff < 0) {
			/* Unspecified position because of ungetc() at 0 */
			errno = ESPIPE;
			return (-1);
		}
		if (offset > 0 && curoff > OFF_MAX - offset) {
			errno = EOVERFLOW;
			return (-1);
		}
		offset += curoff;
		if (offset < 0) {
			errno = EINVAL;
			return (-1);
		}
		if (ltest && offset > LONG_MAX) {
			errno = EOVERFLOW;
			return (-1);
		}
		whence = SEEK_SET;
		havepos = 1;
		break;

	case SEEK_SET:
		if (offset < 0) {
			errno = EINVAL;
			return (-1);
		}
	case SEEK_END:
		curoff = 0;		/* XXX just to keep gcc quiet */
		havepos = 0;
		break;

	default:
		errno = EINVAL;
		return (-1);
	}

	/*
	 * Can only optimise if:
	 *	reading (and not reading-and-writing);
	 *	not unbuffered; and
	 *	this is a `regular' Unix file (and hence seekfn==__sseek).
	 * We must check __NBF first, because it is possible to have __NBF
	 * and __SOPT both set.
	 */
	if (fp->_bf._base == NULL)
		__smakebuf(fp);
	if (fp->pub._flags & (__SWR | __SRW | __SNBF | __SNPT))
		goto dumb;
	if ((fp->pub._flags & __SOPT) == 0) {
		if (seekfn != __sseek ||
		    fp->pub._fileno < 0 || _fstat(fp->pub._fileno, &st) ||
		    (st.st_mode & S_IFMT) != S_IFREG) {
			fp->pub._flags |= __SNPT;
			goto dumb;
		}
		fp->_blksize = st.st_blksize;
		fp->pub._flags |= __SOPT;
	}

	/*
	 * We are reading; we can try to optimise.
	 * Figure out where we are going and where we are now.
	 */
	if (whence == SEEK_SET)
		target = offset;
	else {
		if (_fstat(fp->pub._fileno, &st))
			goto dumb;
		if (offset > 0 && st.st_size > OFF_MAX - offset) {
			errno = EOVERFLOW;
			return (-1);
		}
		target = st.st_size + offset;
		if ((off_t)target < 0) {
			errno = EINVAL;
			return (-1);
		}
		if (ltest && (off_t)target > LONG_MAX) {
			errno = EOVERFLOW;
			return (-1);
		}
	}

	if (!havepos && _ftello(fp, &curoff))
		goto dumb;

	/*
	 * (If the buffer was modified, we have to
	 * skip this; see fgetln.c.)
	 */
	if (fp->pub._flags & __SMOD)
		goto abspos;

	/*
	 * Compute the number of bytes in the input buffer (pretending
	 * that any ungetc() input has been discarded).  Adjust current
	 * offset backwards by this count so that it represents the
	 * file offset for the first byte in the current input buffer.
	 */
	if (HASUB(fp)) {
		curoff += fp->pub._r;	/* kill off ungetc */
		n = fp->_up - fp->_bf._base;
		curoff -= n;
		n += fp->_ur;
	} else {
		n = fp->pub._p - fp->_bf._base;
		curoff -= n;
		n += fp->pub._r;
	}

	/*
	 * If the target offset is within the current buffer,
	 * simply adjust the pointers, clear EOF, undo ungetc(),
	 * and return.
	 */
	if (target >= curoff && target < curoff + n) {
		size_t o = target - curoff;

		fp->pub._p = fp->_bf._base + o;
		fp->pub._r = n - o;
		if (HASUB(fp))
			FREEUB(fp);
		fp->pub._flags &= ~__SEOF;
		memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data));
		return (0);
	}

abspos:
	/*
	 * The place we want to get to is not within the current buffer,
	 * but we can still be kind to the kernel copyout mechanism.
	 * By aligning the file offset to a block boundary, we can let
	 * the kernel use the VM hardware to map pages instead of
	 * copying bytes laboriously.  Using a block boundary also
	 * ensures that we only read one block, rather than two.
	 */
	curoff = target & ~(fp->_blksize - 1);
	if (_sseek(fp, curoff, SEEK_SET) == POS_ERR)
		goto dumb;
	fp->pub._r = 0;
	fp->pub._p = fp->_bf._base;
	if (HASUB(fp))
		FREEUB(fp);
	n = target - curoff;
	if (n) {
		if (__srefill(fp) || fp->pub._r < n)
			goto dumb;
		fp->pub._p += n;
		fp->pub._r -= n;
	}
	fp->pub._flags &= ~__SEOF;
	memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data));
	return (0);

	/*
	 * We get here if we cannot optimise the seek ... just
	 * do it.  Allow the seek function to change fp->_bf._base.
	 */
dumb:
	if (__sflush(fp) ||
	    (ret = _sseek(fp, (fpos_t)offset, whence)) == POS_ERR)
		return (-1);
	if (ltest && ret > LONG_MAX) {
		fp->pub._flags |= __SERR;
		errno = EOVERFLOW;
		return (-1);
	}
	/* success: clear EOF indicator and discard ungetc() data */
	if (HASUB(fp))
		FREEUB(fp);
	fp->pub._p = fp->_bf._base;
	fp->pub._r = 0;
	/* fp->pub._w = 0; */	/* unnecessary (I think...) */
	fp->pub._flags &= ~__SEOF;
	memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data));
	return (0);
}
Exemplo n.º 18
0
/*
 * __svfscanf - non-MT-safe version of __vfscanf
 */
int
__svfscanf(FILE* fp, const char* fmt0, va_list ap) {
    const u_char* fmt = (const u_char*)fmt0;
    int c;          /* character from format, or conversion */
    size_t width;       /* field width, or 0 */
    char* p;        /* points into all kinds of strings */
    int n;          /* handy integer */
    int flags;      /* flags as defined above */
    char* p0;       /* saves original value of p when necessary */
    int nassigned;      /* number of fields assigned */
    int nconversions;   /* number of conversions */
    int nread;      /* number of characters consumed from fp */
    int base;       /* base argument to conversion function */
    char ccltab[256];   /* character class table for %[...] */
    char buf[BUF];      /* buffer for numeric and mb conversions */
    wchar_t* wcp;       /* handy wide character pointer */
    size_t nconv;       /* length of multibyte sequence converted */
    static const mbstate_t initial;
    mbstate_t mbs;
    /* `basefix' is used to avoid `if' tests in the integer scanner */
    static short basefix[17] =
    { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
    ORIENT(fp, -1);
    nassigned = 0;
    nconversions = 0;
    nread = 0;

    for (;;) {
        c = *fmt++;

        if (c == 0) {
            return (nassigned);
        }

        if (isspace(c)) {
            while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) {
                nread++, fp->_r--, fp->_p++;
            }

            continue;
        }

        if (c != '%') {
            goto literal;
        }

        width = 0;
        flags = 0;
        /*
         * switch on the format.  continue if done;
         * break once format type is derived.
         */
    again:
        c = *fmt++;

        switch (c) {
        case '%':
        literal:
            if (fp->_r <= 0 && __srefill(fp)) {
                goto input_failure;
            }

            if (*fp->_p != c) {
                goto match_failure;
            }

            fp->_r--, fp->_p++;
            nread++;
            continue;

        case '*':
            flags |= SUPPRESS;
            goto again;

        case 'j':
            flags |= INTMAXT;
            goto again;

        case 'l':
            if (flags & LONG) {
                flags &= ~LONG;
                flags |= LONGLONG;
            } else {
                flags |= LONG;
            }

            goto again;

        case 'q':
            flags |= LONGLONG;  /* not quite */
            goto again;

        case 't':
            flags |= PTRDIFFT;
            goto again;

        case 'z':
            flags |= SIZET;
            goto again;

        case 'L':
            flags |= LONGDBL;
            goto again;

        case 'h':
            if (flags & SHORT) {
                flags &= ~SHORT;
                flags |= SHORTSHORT;
            } else {
                flags |= SHORT;
            }

            goto again;

        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            width = width * 10 + c - '0';
            goto again;

        /*
         * Conversions.
         */
        case 'd':
            c = CT_INT;
            base = 10;
            break;

        case 'i':
            c = CT_INT;
            base = 0;
            break;

        case 'o':
            c = CT_INT;
            flags |= UNSIGNED;
            base = 8;
            break;

        case 'u':
            c = CT_INT;
            flags |= UNSIGNED;
            base = 10;
            break;

        case 'X':
        case 'x':
            flags |= PFXOK; /* enable 0x prefixing */
            c = CT_INT;
            flags |= UNSIGNED;
            base = 16;
            break;
#ifndef NO_FLOATING_POINT

        case 'A':
        case 'E':
        case 'F':
        case 'G':
        case 'a':
        case 'e':
        case 'f':
        case 'g':
            c = CT_FLOAT;
            break;
#endif

        case 'S':
            flags |= LONG;

        /* FALLTHROUGH */
        case 's':
            c = CT_STRING;
            break;

        case '[':
            fmt = __sccl(ccltab, fmt);
            flags |= NOSKIP;
            c = CT_CCL;
            break;

        case 'C':
            flags |= LONG;

        /* FALLTHROUGH */
        case 'c':
            flags |= NOSKIP;
            c = CT_CHAR;
            break;

        case 'p':   /* pointer format is like hex */
            flags |= POINTER | PFXOK;
            c = CT_INT;     /* assumes sizeof(uintmax_t) */
            flags |= UNSIGNED;  /*      >= sizeof(uintptr_t) */
            base = 16;
            break;

        case 'n':
            nconversions++;

            if (flags & SUPPRESS) { /* ??? */
                continue;
            }

            if (flags & SHORTSHORT) {
                *va_arg(ap, char*) = nread;
            } else if (flags & SHORT) {
                *va_arg(ap, short*) = nread;
            } else if (flags & LONG) {
                *va_arg(ap, long*) = nread;
            } else if (flags & LONGLONG) {
                *va_arg(ap, long long*) = nread;
            } else if (flags & INTMAXT) {
                *va_arg(ap, intmax_t*) = nread;
            } else if (flags & SIZET) {
                *va_arg(ap, size_t*) = nread;
            } else if (flags & PTRDIFFT) {
                *va_arg(ap, ptrdiff_t*) = nread;
            } else {
                *va_arg(ap, int*) = nread;
            }

            continue;

        default:
            goto match_failure;

        /*
         * Disgusting backwards compatibility hack. XXX
         */
        case '\0':  /* compat */
            return (EOF);
        }

        /*
         * We have a conversion that requires input.
         */
        if (fp->_r <= 0 && __srefill(fp)) {
            goto input_failure;
        }

        /*
         * Consume leading white space, except for formats
         * that suppress this.
         */
        if ((flags & NOSKIP) == 0) {
            while (isspace(*fp->_p)) {
                nread++;

                if (--fp->_r > 0) {
                    fp->_p++;
                } else if (__srefill(fp)) {
                    goto input_failure;
                }
            }

            /*
             * Note that there is at least one character in
             * the buffer, so conversions that do not set NOSKIP
             * ca no longer result in an input failure.
             */
        }

        /*
         * Do the conversion.
         */
        switch (c) {
        case CT_CHAR:

            /* scan arbitrary characters (sets NOSKIP) */
            if (width == 0) {
                width = 1;
            }

            if (flags & LONG) {
                if ((flags & SUPPRESS) == 0) {
                    wcp = va_arg(ap, wchar_t*);
                } else {
                    wcp = NULL;
                }

                n = 0;

                while (width != 0) {
                    if (n == MB_CUR_MAX) {
                        fp->_flags |= __SERR;
                        goto input_failure;
                    }

                    buf[n++] = *fp->_p;
                    fp->_p++;
                    fp->_r--;
                    mbs = initial;
                    nconv = mbrtowc(wcp, buf, n, &mbs);

                    if (nconv == (size_t) - 1) {
                        fp->_flags |= __SERR;
                        goto input_failure;
                    }

                    if (nconv == 0 && !(flags & SUPPRESS)) {
                        *wcp = L'\0';
                    }

                    if (nconv != (size_t) - 2) {
                        nread += n;
                        width--;

                        if (!(flags & SUPPRESS)) {
                            wcp++;
                        }

                        n = 0;
                    }

                    if (fp->_r <= 0 && __srefill(fp)) {
                        if (n != 0) {
                            fp->_flags |= __SERR;
                            goto input_failure;
                        }

                        break;
                    }
                }

                if (!(flags & SUPPRESS)) {
                    nassigned++;
                }
            } else if (flags & SUPPRESS) {
Exemplo n.º 19
0
/*
 * vfscanf
 */
NA_EIDPROC
Int32
__svfscanf(SCANBUF* fp, NAWchar const* fmt0, va_list ap)
{
	register NAWchar *fmt = (NAWchar *)fmt0;
	register Int32 c;		/* character from format, or conversion */
	register UInt32 width;	/* field width, or 0 */
	register NAWchar *p;	/* points into all kinds of strings */
	register UInt32 n;		/* handy integer */
	register Int32 flags;	/* flags as defined above */
	register NAWchar *p0;	/* saves original value of p when necessary */
	Int32 nassigned;		/* number of fields assigned */
	Int32 nread;		/* number of characters consumed from fp */
	Int32 base;		/* base argument to strtoq/strtouq */
	ccfnT ccfn; /* conversion function (strtoq/strtouq) */
   
   NAWchar ccltab[256];	/* character class table for %[...] */
	NAWchar buf[BUF];		/* buffer for numeric conversions */
	char sb_buf[BUF];		/* single byte buffer for numeric conversions */

	/* `basefix' is used to avoid `if' tests in the integer scanner */
	/* static */ short basefix[17] =
		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

	nassigned = 0;
	nread = 0;
	base = 0;		/* XXX just to keep gcc happy */
   ccfn = NULL;
	
	for (;;) {
		c = *fmt++;
		if (c == 0)
			return (nassigned);
#pragma nowarn(1506)   // warning elimination 
		if (na_iswspace(c)) {
#pragma warn(1506)  // warning elimination 
			for (;;) {
				if (fp->_r <= 0 && __srefill(fp))
					return (nassigned);
				if (!na_iswspace(*fp->_p))
					break;
				nread++, fp->_r--, fp->_p++;
			}
			continue;
		}
		if (c != L'%')
			goto literal;
		width = 0;
		flags = 0;
		/*
		 * switch on the format.  continue if done;
		 * break once format type is derived.
		 */
again:		c = *fmt++;
		switch (c) {
		case L'%':
literal:
			if (fp->_r <= 0 && __srefill(fp))
				goto input_failure;
			if (*fp->_p != c)
				goto match_failure;
			fp->_r--, fp->_p++;
			nread++;
			continue;

		case L'*':
			flags |= SUPPRESS;
			goto again;
		case L'L':
			flags |= LONGDBL;
			goto again;
		case L'h':
			flags |= SHORT;
			goto again;
		case L'l':
			if (*fmt == L'l') {
				fmt++;
				flags |= QUAD;
			} else {
				flags |= LONG;
			}
			goto again;
		case L'q':
			flags |= QUAD;
			goto again;

		case L'0': case L'1': case L'2': case L'3': case L'4':
		case L'5': case L'6': case L'7': case L'8': case L'9':
			width = width * 10 + c - L'0';
			goto again;

		/*
		 * Conversions.
		 * Those marked `compat' are for 4.[123]BSD compatibility.
		 *
		 * (According to ANSI, E and X formats are supposed
		 * to the same as e and x.  Sorry about that.)
		 */
		case L'D':	/* compat */
			flags |= LONG;
			/* FALLTHROUGH */
		case L'd':
			c = CT_INT;
			if (flags & QUAD)
				ccfn = (ccfnT)na_wcstoll;
			else
				ccfn = (ccfnT)na_wcstol;
			base = 10;
			break;

		case L'i':
			c = CT_INT;
			ccfn = (ccfnT)na_wcstol;
			base = 0;
			break;

		case L'O':	/* compat */
			flags |= LONG;
			/* FALLTHROUGH */
		case L'o':
			c = CT_INT;
			ccfn = (ccfnT)na_wcstol;
			base = 8;
			break;

		case L'u':
			c = CT_INT;
			ccfn = (ccfnT)na_wcstol;
			base = 10;
			break;

		case L'X':
		case L'x':
			flags |= PFXOK;	/* enable 0x prefixing */
			c = CT_INT;
			ccfn = (ccfnT)na_wcstol;
			base = 16;
			break;

#ifdef FLOATING_POINT
		case L'E':
		case L'G':
		case L'e': 
		case L'f': 
		case L'g':
			c = CT_FLOAT;
         break;
#endif

		case L's':
			c = CT_STRING;
			break;

		case L'[':
			fmt = __sccl(ccltab, fmt);
			flags |= NOSKIP;
			c = CT_CCL;
			break;

		case L'c':
			flags |= NOSKIP;
			c = CT_CHAR;
			break;

		case L'p':	/* pointer format is like hex */
			flags |= POINTER | PFXOK;
			c = CT_INT;
			ccfn = (ccfnT)na_wcstol;
			base = 16;
			break;

		case L'n':
			if (flags & SUPPRESS)	/* ??? */
				continue;
			if (flags & SHORT)
#pragma nowarn(1506)   // warning elimination 
				*va_arg(ap, short *) = nread;
#pragma warn(1506)  // warning elimination 
			else if (flags & LONG)
				*va_arg(ap, Lng32 *) = nread;
			else
				*va_arg(ap, Int32 *) = nread;
			continue;

		/*
		 * Disgusting backwards compatibility hacks.	XXX
		 */
		case L'\0':	/* compat */
			//return (EOF);
         return -1;

		default:	/* compat */
			if ( L'A' <= c && c <= L'Z' )
				flags |= LONG;
			c = CT_INT;
			ccfn = (ccfnT)na_wcstol;
			base = 10;
			break;
		}

		/*
		 * We have a conversion that requires input.
		 */
		if (fp->_r <= 0 && __srefill(fp))
			goto input_failure;

		/*
		 * Consume leading white space, except for formats
		 * that suppress this.
		 */
		if ((flags & NOSKIP) == 0) {
			while (na_iswspace(*fp->_p)) {
				nread++;
				if (--fp->_r > 0)
					fp->_p++;
				else if (__srefill(fp))
					goto input_failure;
			}
			/*
			 * Note that there is at least one character in
			 * the buffer, so conversions that do not set NOSKIP
			 * ca no longer result in an input failure.
			 */
		}

		/*
		 * Do the conversion.
		 */
		switch (c) {

		case CT_CHAR:
			/* scan arbitrary characters (sets NOSKIP) */
			if (width == 0)
				width = 1;
			if (flags & SUPPRESS) {
				size_t sum = 0;
				for (;;) {
					if ((n = fp->_r) < width) {
						sum += n;
						width -= n;
						fp->_p += n;
						if (__srefill(fp)) {
							if (sum == 0)
							    goto input_failure;
							break;
						}
					} else {
						sum += width;
						fp->_r -= width;
						fp->_p += width;
						break;
					}
				}
				nread += sum;
			} else {
				//size_t r = fread((void *)va_arg(ap, char *), 1,
				//    width, fp);
            size_t r;
            if ( fp->_r >= width ) {
               na_wcsncpy((NAWchar*)va_arg(ap, NAWchar *), (NAWchar*)fp->_ptr, width);
               r = width;
            } else
               r = 0;

				if (r == 0)
					goto input_failure;
				nread += r;
				nassigned++;
			}
			break;

		case CT_CCL:
			/* scan a (nonempty) character class (sets NOSKIP) */
			if (width == 0)
				width = ~0;	/* `infinity' */
			/* take only those things in the class */
			if (flags & SUPPRESS) {
				n = 0;
				while (ccltab[*fp->_p]) {
					n++, fp->_r--, fp->_p++;
					if (--width == 0)
						break;
					if (fp->_r <= 0 && __srefill(fp)) {
						if (n == 0)
							goto input_failure;
						break;
					}
				}
				if (n == 0)
					goto match_failure;
			} else {
				p0 = p = va_arg(ap, NAWchar *);
				while (ccltab[*fp->_p]) {
					fp->_r--;
					*p++ = *fp->_p++;
					if (--width == 0)
						break;
					if (fp->_r <= 0 && __srefill(fp)) {
						if (p == p0)
							goto input_failure;
						break;
					}
				}
				n = p - p0;
				if (n == 0)
					goto match_failure;
				*p = 0;
				nassigned++;
			}
			nread += n;
			break;

		case CT_STRING:
			/* like CCL, but zero-length string OK, & no NOSKIP */
			if (width == 0)
				width = ~0;
			if (flags & SUPPRESS) {
				n = 0;
				while (!na_iswspace(*fp->_p)) {
					n++, fp->_r--, fp->_p++;
					if (--width == 0)
						break;
					if (fp->_r <= 0 && __srefill(fp))
						break;
				}
				nread += n;
			} else {
				p0 = p = va_arg(ap, NAWchar *);
				while (!na_iswspace(*fp->_p)) {
					fp->_r--;
					*p++ = *fp->_p++;
					if (--width == 0)
						break;
					if (fp->_r <= 0 && __srefill(fp))
						break;
				}
				*p = 0;
				nread += p - p0;
				nassigned++;
			}
			continue;

		case CT_INT:
			/* scan an integer as if by strtoq/strtouq */
#ifdef hardway
			if (width == 0 || width > sizeof(buf) - 1)
				width = sizeof(buf) - 1;
#else
			/* size_t is unsigned, hence this optimisation */
			if (--width > sizeof(buf) - 2)
				width = sizeof(buf) - 2;
			width++;
#endif
			flags |= SIGNOK | NDIGITS | NZDIGITS;
			for (p = buf; width; width--) {
				c = *fp->_p;
				/*
				 * Switch on the character; `goto ok'
				 * if we accept it as a part of number.
				 */
				switch (c) {

				/*
				 * The digit 0 is always legal, but is
				 * special.  For %i conversions, if no
				 * digits (zero or nonzero) have been
				 * scanned (only signs), we will have
				 * base==0.  In that case, we should set
				 * it to 8 and enable 0x prefixing.
				 * Also, if we have not scanned zero digits
				 * before this, do not turn off prefixing
				 * (someone else will turn it off if we
				 * have scanned any nonzero digits).
				 */
				case L'0':
					if (base == 0) {
						base = 8;
						flags |= PFXOK;
					}
					if (flags & NZDIGITS)
					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
					else
					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
					goto ok;

				/* 1 through 7 always legal */
				case L'1': case L'2': case L'3':
				case L'4': case L'5': case L'6': case L'7':
					base = basefix[base];
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
					goto ok;

				/* digits 8 and 9 ok iff decimal or hex */
				case L'8': case L'9':
					base = basefix[base];
					if (base <= 8)
						break;	/* not legal here */
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
					goto ok;

				/* letters ok iff hex */
				case L'A': case L'B': case L'C':
				case L'D': case L'E': case L'F':
				case L'a': case L'b': case L'c':
				case L'd': case L'e': case L'f':
					/* no need to fix base here */
					if (base <= 10)
						break;	/* not legal here */
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
					goto ok;

				/* sign ok only as first character */
				case L'+': case L'-':
					if (flags & SIGNOK) {
						flags &= ~SIGNOK;
						goto ok;
					}
					break;

				/* x ok iff flag still set & 2nd char */
				case L'x': case L'X':
					if (flags & PFXOK && p == buf + 1) {
						base = 16;	/* if %i */
						flags &= ~PFXOK;
						goto ok;
					}
					break;
				}

				/*
				 * If we got here, c is not a legal character
				 * for a number.  Stop accumulating digits.
				 */
				break;
		ok:
				/*
				 * c is legal: store it and look at the next.
				 */
#pragma nowarn(1506)   // warning elimination 
				*p++ = c;
#pragma warn(1506)  // warning elimination 
				if (--fp->_r > 0)
					fp->_p++;
				else if (__srefill(fp))
					break;		/* EOF */
			}
			/*
			 * If we had only a sign, it is no good; push
			 * back the sign.  If the number ends in `x',
			 * it was [sign] '0' 'x', so push back the x
			 * and treat it as [sign] '0'.
			 */
			if (flags & NDIGITS) {
				if (p > buf)
					(void) ungetc(*(NAWchar *)--p, fp);
				   goto match_failure;
			}
			c = ((NAWchar *)p)[-1];
			if (c == L'x' || c == L'X') {
				--p;
#pragma nowarn(1506)   // warning elimination 
				(void) ungetc(c, fp);
#pragma warn(1506)  // warning elimination 
            
			}
			if ((flags & SUPPRESS) == 0) {
				u_quad_t res = NULL;

				*p = 0;
            if ( ccfn )
				   res = (*ccfn)(buf); // only 10 based
               //res = (*ccfn)(buf);
				if (flags & POINTER)
					*va_arg(ap, void **) =
					    (void *)(Lng32)res;
				else if (flags & QUAD)
#pragma nowarn(1506)   // warning elimination 
					*va_arg(ap, quad_t *) = res;
#pragma warn(1506)  // warning elimination 
				else if (flags & LONG)
#pragma nowarn(1506)   // warning elimination 
					*va_arg(ap, Lng32 *) = (Lng32) res;
#pragma warn(1506)  // warning elimination 
				else if (flags & SHORT)
					*va_arg(ap, Int16 *) = (Int16) res;
				else
#pragma nowarn(1506)   // warning elimination 
					*va_arg(ap, Int32 *) = (Int32) res;
#pragma warn(1506)  // warning elimination 
				nassigned++;
			}
			nread += p - buf;
			break;

#ifdef FLOATING_POINT
		case CT_FLOAT:
			/* scan a floating point number as if by strtod */
#ifdef hardway
			if (width == 0 || width > sizeof(buf) - 1)
				width = sizeof(buf) - 1;
#else
			/* size_t is unsigned, hence this optimisation */
			if (--width > sizeof(buf) - 2)
				width = sizeof(buf) - 2;
			width++;
#endif
			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;

                        char* q = sb_buf;

			for (p = buf; width; width--) {
				c = *fp->_p;
				/*
				 * This code mimicks the integer conversion
				 * code, but is much simpler.
				 */
				switch (c) {

				case L'0': case L'1': case L'2': case L'3':
				case L'4': case L'5': case L'6': case L'7':
				case L'8': case L'9':
					flags &= ~(SIGNOK | NDIGITS);
					goto fok;

				case L'+': case L'-':
					if (flags & SIGNOK) {
						flags &= ~SIGNOK;
						goto fok;
					}
					break;
				case L'.':
					if (flags & DPTOK) {
						flags &= ~(SIGNOK | DPTOK);
						goto fok;
					}
					break;
				case L'e': case L'E':
					/* no exponent without some digits */
					if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
						flags =
						    (flags & ~(EXPOK|DPTOK)) |
						    SIGNOK | NDIGITS;
						goto fok;
					}
					break;
				}
				break;
		fok:
#pragma nowarn(1506)   // warning elimination 
				*p++ = c;
				*q++ = (char)c;
#pragma warn(1506)  // warning elimination 
				if (--fp->_r > 0)
					fp->_p++;
				else if (__srefill(fp))
					break;	/* EOF */
			}
			/*
			 * If no digits, might be missing exponent digits
			 * (just give back the exponent) or might be missing
			 * regular digits, but had sign and/or decimal point.
			 */
			if (flags & NDIGITS) {
				if (flags & EXPOK) {
					/* no digits at all */
					while (p > buf)
						ungetc(*(NAWchar *)--p, fp);
					goto match_failure;
				}
				/* just a bad exponent (e and maybe sign) */
				c = *(NAWchar *)--p;
				if (c != L'e' && c != L'E') {
#pragma nowarn(1506)   // warning elimination 
					(void) ungetc(c, fp);/* sign */
#pragma warn(1506)  // warning elimination 
               c = *(NAWchar *)--p;
				}
#pragma nowarn(1506)   // warning elimination 
				(void) ungetc(c, fp);
#pragma warn(1506)  // warning elimination 
			}
			if ((flags & SUPPRESS) == 0) {
				double res;

				*p = 0;
				//res = na_wcstod(buf, (NAWchar **) NULL);
				res = strtod(sb_buf, NULL);
				if (flags & LONGDBL)
#pragma nowarn(1255)   // warning elimination 
					*va_arg(ap, long double *) = res;
#pragma warn(1255)  // warning elimination 
				else if (flags & LONG)
					*va_arg(ap, double *) = res;
				else
					*va_arg(ap, float *) = (float) res;
				nassigned++;
			}
			nread += p - buf;
			break;
#endif /* FLOATING_POINT */
		}
Exemplo n.º 20
0
int fseek
    (
    FAST FILE *	fp,		/* stream */
    long	offset,		/* offset from <whence> */
    int		whence		/* position to offset from: */
				/* SEEK_SET = beginning */
				/* SEEK_CUR = current position */
				/* SEEK_END = end-of-file */
    )
    {
    fpos_t	target;
    fpos_t	curoff;
    size_t	n;
    struct stat st;
    int		havepos;
    BOOL	doStat;

    if (OBJ_VERIFY (fp, fpClassId) != OK)
	return (ERROR);

    /*
     * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
     * After this, whence is either SEEK_SET or SEEK_END.
     */

    switch (whence) 
	{
	case SEEK_CUR:
		/*
		 * In order to seek relative to the current stream offset,
		 * we have to first find the current stream offset a la
		 * ftell (see ftell for details).
		 */
		if (fp->_flags & __SOFF)
		    curoff = fp->_offset;
		else 
		    {
		    curoff = __sseek (fp, (fpos_t)0, SEEK_CUR);
		    if (curoff == -1L)
			return (EOF);
		    }

		if (fp->_flags & __SRD) 
		    {
		    curoff -= fp->_r;
		    if (HASUB(fp))
			curoff -= fp->_ur;
		    }
		else if (fp->_flags & __SWR && fp->_p != NULL)
		    curoff += fp->_p - fp->_bf._base;

		offset += curoff;
		whence	= SEEK_SET;
		havepos = 1;
		break;

	case SEEK_SET:
	case SEEK_END:
		curoff = 0;		/* XXX just to keep gcc quiet */
		havepos = 0;
		break;

	default:
		errno = EINVAL;
		return (EOF);
	}

    /*
     * Can only optimise if:
     *	reading (and not reading-and-writing);
     *	not unbuffered; and
     *	this is a `regular' Unix file (and hence seekfn==__sseek).
     * We must check __NBF first, because it is possible to have __NBF
     * and __SOPT both set.
     */

    if (fp->_bf._base == NULL)
	__smakebuf (fp);

    if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
	goto dumb;


    doStat = ioctl (fp->_file, FIOFSTATGET, (int)&st);

    if ((fp->_flags & __SOPT) == 0) 
	{
	if ((fp->_file < 0 || (doStat) ||
	    (st.st_mode & S_IFMT) != S_IFREG)) 
	    {
	    fp->_flags |= __SNPT;
	    goto dumb;
	    }

	fp->_blksize 	 = st.st_blksize;
	fp->_flags	|= __SOPT;
	}

    /*
     * We are reading; we can try to optimise.
     * Figure out where we are going and where we are now.
     */

    if (whence == SEEK_SET)
	target = offset;
    else 
	{
	if (doStat)
	    goto dumb;

	target = st.st_size + offset;
	}

    if (!havepos) 
	{
	if (fp->_flags & __SOFF)
	    curoff = fp->_offset;
	else 
	    {
	    curoff = __sseek (fp, 0L, SEEK_CUR);

	    if (curoff == POS_ERR)
		goto dumb;
	    }

	curoff -= fp->_r;

	if (HASUB(fp))
	    curoff -= fp->_ur;
	}

    /*
     * Compute the number of bytes in the input buffer (pretending
     * that any ungetc() input has been discarded).  Adjust current
     * offset backwards by this count so that it represents the
     * file offset for the first byte in the current input buffer.
     */

    if (HASUB(fp)) 
	{
	n	= fp->_up - fp->_bf._base;
	curoff -= n;
	n      += fp->_ur;
	} 
    else 
	{
	n	= fp->_p - fp->_bf._base;
	curoff -= n;
	n      += fp->_r;
	}

    /*
     * If the target offset is within the current buffer,
     * simply adjust the pointers, clear EOF, undo ungetc(),
     * and return.  (If the buffer was modified, we have to
     * skip this; see fgetline.c.)
     */

    if (((fp->_flags & __SMOD) == 0) && 
	(target >= curoff) && 
	(target < (curoff + n))) 
	{
	FAST int o = target - curoff;

	fp->_p = fp->_bf._base + o;
	fp->_r = n - o;

	if (HASUB(fp))
	    FREEUB(fp);

	fp->_flags &= ~__SEOF;

	return (0);
	}

    /*
     * The place we want to get to is not within the current buffer,
     * but we can still be kind to the kernel copyout mechanism.
     * By aligning the file offset to a block boundary, we can let
     * the kernel use the VM hardware to map pages instead of
     * copying bytes laboriously.  Using a block boundary also
     * ensures that we only read one block, rather than two.
     */

    curoff = target & ~(fp->_blksize - 1);

    if (__sseek (fp, curoff, SEEK_SET) == POS_ERR)
	goto dumb;

    fp->_r = 0;

    if (HASUB(fp))
	FREEUB(fp);

    fp->_flags &= ~__SEOF;
    n = target - curoff;

    if (n) 
	{
	if (__srefill (fp) || fp->_r < n)
	    goto dumb;
	fp->_p += n;
	fp->_r -= n;
	}

    return (0);

    /*
     * We get here if we cannot optimise the seek ... just
     * do it.  Allow the seek function to change fp->_bf._base.
     */
dumb:
    if ((__sflush (fp)) || (__sseek (fp, offset, whence) == POS_ERR)) 
	return (EOF);

    /* success: clear EOF indicator and discard ungetc() data */

    if (HASUB(fp))
	FREEUB(fp);

    fp->_p = fp->_bf._base;
    fp->_r = 0;

    /* fp->_w = 0; */	/* unnecessary (I think...) */

    fp->_flags &= ~__SEOF;

    return (0);
    }
Exemplo n.º 21
0
/*
 * Internal, unlocked version of vfscanf
 */
int
__svfscanf(FILE *fp, const char *fmt0, __va_list ap)
{
	u_char *fmt = (u_char *)fmt0;
	int c;		/* character from format, or conversion */
	size_t width;	/* field width, or 0 */
	char *p;	/* points into all kinds of strings */
	int n;		/* handy integer */
	int flags;	/* flags as defined above */
	char *p0;	/* saves original value of p when necessary */
	int nassigned;		/* number of fields assigned */
	int nread;		/* number of characters consumed from fp */
	int base;		/* base argument to strtoimax/strtouimax */
	char ccltab[256];	/* character class table for %[...] */
	char buf[BUF];		/* buffer for numeric conversions */
#ifdef SCANF_WIDE_CHAR
	wchar_t *wcp;		/* handy wide character pointer */
	size_t nconv;		/* length of multibyte sequence converted */
	mbstate_t mbs;
#endif

	/* `basefix' is used to avoid `if' tests in the integer scanner */
	static short basefix[17] =
		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

	_SET_ORIENTATION(fp, -1);

	nassigned = 0;
	nread = 0;
	base = 0;		/* XXX just to keep gcc happy */
	for (;;) {
		c = *fmt++;
		if (c == 0)
			return (nassigned);
		if (isspace(c)) {
			while ((fp->_r > 0 || __srefill(fp) == 0) &&
			    isspace(*fp->_p))
				nread++, fp->_r--, fp->_p++;
			continue;
		}
		if (c != '%')
			goto literal;
		width = 0;
		flags = 0;
		/*
		 * switch on the format.  continue if done;
		 * break once format type is derived.
		 */
again:		c = *fmt++;
		switch (c) {
		case '%':
literal:
			if (fp->_r <= 0 && __srefill(fp))
				goto input_failure;
			if (*fp->_p != c)
				goto match_failure;
			fp->_r--, fp->_p++;
			nread++;
			continue;

		case '*':
			flags |= SUPPRESS;
			goto again;
		case 'j':
			flags |= MAXINT;
			goto again;
		case 'L':
			flags |= LONGDBL;
			goto again;
		case 'h':
			if (*fmt == 'h') {
				fmt++;
				flags |= SHORTSHORT;
			} else {
				flags |= SHORT;
			}
			goto again;
		case 'l':
			if (*fmt == 'l') {
				fmt++;
				flags |= LLONG;
			} else {
				flags |= LONG;
			}
			goto again;
		case 'q':
			flags |= LLONG;		/* deprecated */
			goto again;
		case 't':
			flags |= PTRINT;
			goto again;
		case 'z':
			flags |= SIZEINT;
			goto again;

		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			width = width * 10 + c - '0';
			goto again;

		/*
		 * Conversions.
		 * Those marked `compat' are for 4.[123]BSD compatibility.
		 *
		 * (According to ANSI, E and X formats are supposed
		 * to the same as e and x.  Sorry about that.)
		 */
		case 'D':	/* compat */
			flags |= LONG;
			/* FALLTHROUGH */
		case 'd':
			c = CT_INT;
			base = 10;
			break;

		case 'i':
			c = CT_INT;
			base = 0;
			break;

		case 'O':	/* compat */
			flags |= LONG;
			/* FALLTHROUGH */
		case 'o':
			c = CT_INT;
			flags |= UNSIGNED;
			base = 8;
			break;

		case 'u':
			c = CT_INT;
			flags |= UNSIGNED;
			base = 10;
			break;

		case 'X':
		case 'x':
			flags |= PFXOK;	/* enable 0x prefixing */
			c = CT_INT;
			flags |= UNSIGNED;
			base = 16;
			break;

#ifdef FLOATING_POINT
		case 'e': case 'E':
		case 'f': case 'F':
		case 'g': case 'G':
		case 'a': case 'A':
			c = CT_FLOAT;
			break;
#endif

		case 's':
			c = CT_STRING;
			break;

		case '[':
			fmt = __sccl(ccltab, fmt);
			flags |= NOSKIP;
			c = CT_CCL;
			break;

		case 'c':
			flags |= NOSKIP;
			c = CT_CHAR;
			break;

		case 'p':	/* pointer format is like hex */
			flags |= POINTER | PFXOK;
			c = CT_INT;
			flags |= UNSIGNED;
			base = 16;
			break;

		case 'n':
			if (flags & SUPPRESS)
				continue;
			if (flags & SHORTSHORT)
				*va_arg(ap, signed char *) = nread;
			else if (flags & SHORT)
				*va_arg(ap, short *) = nread;
			else if (flags & LONG)
				*va_arg(ap, long *) = nread;
			else if (flags & SIZEINT)
				*va_arg(ap, ssize_t *) = nread;
			else if (flags & PTRINT)
				*va_arg(ap, ptrdiff_t *) = nread;
			else if (flags & LLONG)
				*va_arg(ap, long long *) = nread;
			else if (flags & MAXINT)
				*va_arg(ap, intmax_t *) = nread;
			else
				*va_arg(ap, int *) = nread;
			continue;

		/*
		 * Disgusting backwards compatibility hacks.	XXX
		 */
		case '\0':	/* compat */
			return (EOF);

		default:	/* compat */
			if (isupper(c))
				flags |= LONG;
			c = CT_INT;
			base = 10;
			break;
		}

		/*
		 * We have a conversion that requires input.
		 */
		if (fp->_r <= 0 && __srefill(fp))
			goto input_failure;

		/*
		 * Consume leading white space, except for formats
		 * that suppress this.
		 */
		if ((flags & NOSKIP) == 0) {
			while (isspace(*fp->_p)) {
				nread++;
				if (--fp->_r > 0)
					fp->_p++;
				else if (__srefill(fp))
					goto input_failure;
			}
			/*
			 * Note that there is at least one character in
			 * the buffer, so conversions that do not set NOSKIP
			 * ca no longer result in an input failure.
			 */
		}

		/*
		 * Do the conversion.
		 */
		switch (c) {

		case CT_CHAR:
			/* scan arbitrary characters (sets NOSKIP) */
			if (width == 0)
				width = 1;
#ifdef SCANF_WIDE_CHAR
			if (flags & LONG) {
				if ((flags & SUPPRESS) == 0)
					wcp = va_arg(ap, wchar_t *);
				else
					wcp = NULL;
				n = 0;
				while (width != 0) {
					if (n == MB_CUR_MAX) {
						fp->_flags |= __SERR;
						goto input_failure;
					}
					buf[n++] = *fp->_p;
					fp->_p++;
					fp->_r--;
					bzero(&mbs, sizeof(mbs));
					nconv = mbrtowc(wcp, buf, n, &mbs);
					if (nconv == (size_t)-1) {
						fp->_flags |= __SERR;
						goto input_failure;
					}
					if (nconv == 0 && !(flags & SUPPRESS))
						*wcp = L'\0';
					if (nconv != (size_t)-2) {
						nread += n;
						width--;
						if (!(flags & SUPPRESS))
							wcp++;
						n = 0;
					}
					if (fp->_r <= 0 && __srefill(fp)) {
						if (n != 0) {
							fp->_flags |= __SERR;
							goto input_failure;
						}
						break;
					}
				}
				if (!(flags & SUPPRESS))
					nassigned++;
			} else
#endif /* SCANF_WIDE_CHAR */
			if (flags & SUPPRESS) {
				size_t sum = 0;
				for (;;) {
					if ((n = fp->_r) < width) {
						sum += n;
						width -= n;
						fp->_p += n;
						if (__srefill(fp)) {
							if (sum == 0)
							    goto input_failure;
							break;
						}
					} else {
						sum += width;
						fp->_r -= width;
						fp->_p += width;
						break;
					}
				}
				nread += sum;
			} else {
				size_t r = fread((void *)va_arg(ap, char *), 1,
				    width, fp);

				if (r == 0)
					goto input_failure;
				nread += r;
				nassigned++;
			}
			break;

		case CT_CCL:
			/* scan a (nonempty) character class (sets NOSKIP) */
			if (width == 0)
				width = (size_t)~0;	/* `infinity' */
#ifdef SCANF_WIDE_CHAR
			/* take only those things in the class */
			if (flags & LONG) {
				wchar_t twc;
				int nchars;

				if ((flags & SUPPRESS) == 0)
					wcp = va_arg(ap, wchar_t *);
				else
Exemplo n.º 22
0
/*
 * Seek the given file to the given offset.
 * `Whence' must be one of the three SEEK_* macros.
 */
int
fseeko(FILE *fp, off_t offset, int whence)
{
	fpos_t (*seekfn)(void *, fpos_t, int);
	fpos_t target, curoff;
	size_t n;
	struct stat st;
	int havepos;

	/* make sure stdio is set up */
	if (!__sdidinit)
		__sinit();

	/*
	 * Have to be able to seek.
	 */
	if ((seekfn = fp->_seek) == NULL || isatty(__sfileno(fp))) {
		__sseterr(fp, ESPIPE);			/* historic practice */
		return (EOF);
	}

	/*
	 * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
	 * After this, whence is either SEEK_SET or SEEK_END.
	 */
	FLOCKFILE(fp);
	switch (whence) {

	case SEEK_CUR:
		/*
		 * In order to seek relative to the current stream offset,
		 * we have to first find the current stream offset a la
		 * ftell (see ftell for details).
		 */
		__sflush(fp);	/* may adjust seek offset on append stream */
		if (fp->_flags & __SOFF)
			curoff = fp->_offset;
		else {
			curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR);
			if (curoff == (fpos_t)-1) {
				FUNLOCKFILE(fp);
				return (EOF);
			}
		}
		if (fp->_flags & __SRD) {
			curoff -= fp->_r;
			if (HASUB(fp))
				curoff -= fp->_ur;
		} else if (fp->_flags & __SWR && fp->_p != NULL)
			curoff += fp->_p - fp->_bf._base;

		offset += curoff;
		whence = SEEK_SET;
		havepos = 1;
		break;

	case SEEK_SET:
	case SEEK_END:
		curoff = 0;		/* XXX just to keep gcc quiet */
		havepos = 0;
		break;

	default:
		FUNLOCKFILE(fp);
		__sseterr(fp, EINVAL);
		return (EOF);
	}

	/*
	 * Can only optimise if:
	 *	reading (and not reading-and-writing);
	 *	not unbuffered; and
	 *	this is a `regular' Unix file (and hence seekfn==__sseek).
	 * We must check __NBF first, because it is possible to have __NBF
	 * and __SOPT both set.
	 */
	if (fp->_bf._base == NULL)
		__smakebuf(fp);
	if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
		goto dumb;
	if ((fp->_flags & __SOPT) == 0) {
		if (seekfn != __sseek ||
		    fp->_file < 0 || __libc_fstat(fp->_file, &st) ||
		    (st.st_mode & S_IFMT) != S_IFREG) {
			fp->_flags |= __SNPT;
			goto dumb;
		}
		fp->_blksize = st.st_blksize;
		fp->_flags |= __SOPT;
	}

	/*
	 * We are reading; we can try to optimise.
	 * Figure out where we are going and where we are now.
	 */
	if (whence == SEEK_SET)
		target = offset;
	else {
		if (__libc_fstat(fp->_file, &st))
			goto dumb;
		target = st.st_size + offset;
	}

	if (!havepos) {
		if (fp->_flags & __SOFF)
			curoff = fp->_offset;
		else {
			curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR);
			if (curoff == POS_ERR)
				goto dumb;
		}
		curoff -= fp->_r;
		if (HASUB(fp))
			curoff -= fp->_ur;
	}

	/*
	 * Compute the number of bytes in the input buffer (pretending
	 * that any ungetc() input has been discarded).  Adjust current
	 * offset backwards by this count so that it represents the
	 * file offset for the first byte in the current input buffer.
	 */
	if (HASUB(fp)) {
		curoff += fp->_r;	/* kill off ungetc */
		n = fp->_up - fp->_bf._base;
		curoff -= n;
		n += fp->_ur;
	} else {
		n = fp->_p - fp->_bf._base;
		curoff -= n;
		n += fp->_r;
	}

	/*
	 * If the target offset is within the current buffer,
	 * simply adjust the pointers, clear EOF, undo ungetc(),
	 * and return.  (If the buffer was modified, we have to
	 * skip this; see fgetln.c.)
	 */
	if ((fp->_flags & __SMOD) == 0 &&
	    target >= curoff && target < curoff + n) {
		int o = target - curoff;

		fp->_p = fp->_bf._base + o;
		fp->_r = n - o;
		if (HASUB(fp))
			FREEUB(fp);
		fp->_flags &= ~__SEOF;
		FUNLOCKFILE(fp);
		return (0);
	}

	/*
	 * The place we want to get to is not within the current buffer,
	 * but we can still be kind to the kernel copyout mechanism.
	 * By aligning the file offset to a block boundary, we can let
	 * the kernel use the VM hardware to map pages instead of
	 * copying bytes laboriously.  Using a block boundary also
	 * ensures that we only read one block, rather than two.
	 */
	curoff = target & ~(fp->_blksize - 1);
	if ((*seekfn)(fp->_cookie, curoff, SEEK_SET) == POS_ERR)
		goto dumb;
	fp->_r = 0;
 	fp->_p = fp->_bf._base;
	if (HASUB(fp))
		FREEUB(fp);
	fp->_flags &= ~__SEOF;
	n = target - curoff;
	if (n) {
		if (__srefill(fp) || fp->_r < n)
			goto dumb;
		fp->_p += n;
		fp->_r -= n;
	}
	FUNLOCKFILE(fp);
	return (0);

	/*
	 * We get here if we cannot optimise the seek ... just
	 * do it.  Allow the seek function to change fp->_bf._base.
	 */
dumb:
	if (__sflush(fp) ||
	    (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) {
		FUNLOCKFILE(fp);
		return (EOF);
	}
	/* success: clear EOF indicator and discard ungetc() data */
	if (HASUB(fp))
		FREEUB(fp);
	fp->_p = fp->_bf._base;
	fp->_r = 0;
	/* fp->_w = 0; */	/* unnecessary (I think...) */
	fp->_flags &= ~__SEOF;
	FUNLOCKFILE(fp);
	return (0);
}
Exemplo n.º 23
0
/*
 * vfscanf
 */
int
VFSCANF(FILE *fp, const char *fmt0, __va_list ap)
{
	u_char *fmt = (u_char *)fmt0;
	int c;		/* character from format, or conversion */
	size_t width;	/* field width, or 0 */
	char *p;	/* points into all kinds of strings */
	int n;		/* handy integer */
	int flags;	/* flags as defined above */
	char *p0;	/* saves original value of p when necessary */
	int nassigned;		/* number of fields assigned */
	int nread;		/* number of characters consumed from fp */
	int base;		/* base argument to strtoimax/strtouimax */
	char ccltab[256];	/* character class table for %[...] */
	char buf[BUF];		/* buffer for numeric conversions */

	/* `basefix' is used to avoid `if' tests in the integer scanner */
	static short basefix[17] =
		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };

	FLOCKFILE(fp);
	_SET_ORIENTATION(fp, -1);

	nassigned = 0;
	nread = 0;
	base = 0;		/* XXX just to keep gcc happy */
	for (;;) {
		c = *fmt++;
		if (c == 0) {
			FUNLOCKFILE(fp);
			return (nassigned);
		}
		if (isspace(c)) {
			while ((fp->_r > 0 || __srefill(fp) == 0) &&
			    isspace(*fp->_p))
				nread++, fp->_r--, fp->_p++;
			continue;
		}
		if (c != '%')
			goto literal;
		width = 0;
		flags = 0;
		/*
		 * switch on the format.  continue if done;
		 * break once format type is derived.
		 */
again:		c = *fmt++;
		switch (c) {
		case '%':
literal:
			if (fp->_r <= 0 && __srefill(fp))
				goto input_failure;
			if (*fp->_p != c)
				goto match_failure;
			fp->_r--, fp->_p++;
			nread++;
			continue;

		case '*':
			flags |= SUPPRESS;
			goto again;
		case 'j':
			flags |= MAXINT;
			goto again;
		case 'L':
			flags |=
				(*fmt == 'd') ? LLONG :
				(*fmt == 'i') ? LLONG :
				(*fmt == 'o') ? LLONG :
				(*fmt == 'u') ? LLONG :
				(*fmt == 'x') ? LLONG :
				LONGDBL;
			goto again;
		case 'h':
			if (*fmt == 'h') {
				fmt++;
				flags |= SHORTSHORT;
			} else {
				flags |= SHORT;
			}
			goto again;
		case 'l':
			if (*fmt == 'l') {
				fmt++;
				flags |= LLONG;
			} else {
				flags |= LONG;
			}
			goto again;
		case 'q':
			flags |= LLONG;		/* deprecated */
			goto again;
		case 't':
			flags |= PTRINT;
			goto again;
		case 'z':
			flags |= SIZEINT;
			goto again;

		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			width = width * 10 + c - '0';
			goto again;

		/*
		 * Conversions.
		 * Those marked `compat' are for 4.[123]BSD compatibility.
		 *
		 * (According to ANSI, E and X formats are supposed
		 * to the same as e and x.  Sorry about that.)
		 */
		case 'D':	/* compat */
			flags |= LONG;
			/* FALLTHROUGH */
		case 'd':
			c = CT_INT;
			base = 10;
			break;

		case 'i':
			c = CT_INT;
			base = 0;
			break;

		case 'O':	/* compat */
			flags |= LONG;
			/* FALLTHROUGH */
		case 'o':
			c = CT_INT;
			flags |= UNSIGNED;
			base = 8;
			break;

		case 'u':
			c = CT_INT;
			flags |= UNSIGNED;
			base = 10;
			break;

		case 'X':
		case 'x':
			flags |= PFXOK;	/* enable 0x prefixing */
			c = CT_INT;
			flags |= UNSIGNED;
			base = 16;
			break;

#ifdef FLOATING_POINT
		case 'E':
		case 'G':
		case 'e': 
		case 'f': 
		case 'g':
			c = CT_FLOAT;
			break;
#endif

		case 's':
			c = CT_STRING;
			break;

		case '[':
			fmt = __sccl(ccltab, fmt);
			flags |= NOSKIP;
			c = CT_CCL;
			break;

		case 'c':
			flags |= NOSKIP;
			c = CT_CHAR;
			break;

		case 'p':	/* pointer format is like hex */
			flags |= POINTER | PFXOK;
			c = CT_INT;
			flags |= UNSIGNED;
			base = 16;
			break;

		case 'n':
			if (flags & SUPPRESS)
				continue;
			if (flags & SHORTSHORT)
				*va_arg(ap, __signed char *) = nread;
			else if (flags & SHORT)
				*va_arg(ap, short *) = nread;
			else if (flags & LONG)
				*va_arg(ap, long *) = nread;
			else if (flags & SIZEINT)
				*va_arg(ap, ssize_t *) = nread;
			else if (flags & PTRINT)
				*va_arg(ap, ptrdiff_t *) = nread;
			else if (flags & LLONG)
				*va_arg(ap, long long *) = nread;
			else if (flags & MAXINT)
				*va_arg(ap, intmax_t *) = nread;
			else
				*va_arg(ap, int *) = nread;
			continue;

		/*
		 * Disgusting backwards compatibility hacks.	XXX
		 */
		case '\0':	/* compat */
			FUNLOCKFILE(fp);
			return (EOF);

		default:	/* compat */
			if (isupper(c))
				flags |= LONG;
			c = CT_INT;
			base = 10;
			break;
		}

		/*
		 * We have a conversion that requires input.
		 */
		if (fp->_r <= 0 && __srefill(fp))
			goto input_failure;

		/*
		 * Consume leading white space, except for formats
		 * that suppress this.
		 */
		if ((flags & NOSKIP) == 0) {
			while (isspace(*fp->_p)) {
				nread++;
				if (--fp->_r > 0)
					fp->_p++;
				else if (__srefill(fp))
					goto input_failure;
			}
			/*
			 * Note that there is at least one character in
			 * the buffer, so conversions that do not set NOSKIP
			 * ca no longer result in an input failure.
			 */
		}

		/*
		 * Do the conversion.
		 */
		switch (c) {

		case CT_CHAR:
			/* scan arbitrary characters (sets NOSKIP) */
			if (width == 0)
				width = 1;
			if (flags & SUPPRESS) {
				size_t sum = 0;
				for (;;) {
					if ((n = fp->_r) < (int)width) {
						sum += n;
						width -= n;
						fp->_p += n;
						if (__srefill(fp)) {
							if (sum == 0)
							    goto input_failure;
							break;
						}
					} else {
						sum += width;
						fp->_r -= width;
						fp->_p += width;
						break;
					}
				}
				nread += sum;
			} else {
				size_t r = fread((void *)va_arg(ap, char *), 1,
				    width, fp);

				if (r == 0)
					goto input_failure;
				nread += r;
				nassigned++;
			}
			break;

		case CT_CCL:
			/* scan a (nonempty) character class (sets NOSKIP) */
			if (width == 0)
				width = (size_t)~0;	/* `infinity' */
			/* take only those things in the class */
			if (flags & SUPPRESS) {
				n = 0;
				while (ccltab[*fp->_p]) {
					n++, fp->_r--, fp->_p++;
					if (--width == 0)
						break;
					if (fp->_r <= 0 && __srefill(fp)) {
						if (n == 0)
							goto input_failure;
						break;
					}
				}
				if (n == 0)
					goto match_failure;
			} else {
				p0 = p = va_arg(ap, char *);
				while (ccltab[*fp->_p]) {
					fp->_r--;
					*p++ = *fp->_p++;
					if (--width == 0)
						break;
					if (fp->_r <= 0 && __srefill(fp)) {
						if (p == p0)
							goto input_failure;
						break;
					}
				}
				n = p - p0;
				if (n == 0)
					goto match_failure;
				*p = '\0';
				nassigned++;
			}
			nread += n;
			break;

		case CT_STRING:
			/* like CCL, but zero-length string OK, & no NOSKIP */
			if (width == 0)
				width = (size_t)~0;
			if (flags & SUPPRESS) {
				n = 0;
				while (!isspace(*fp->_p)) {
					n++, fp->_r--, fp->_p++;
					if (--width == 0)
						break;
					if (fp->_r <= 0 && __srefill(fp))
						break;
				}
				nread += n;
			} else {
				p0 = p = va_arg(ap, char *);
				while (!isspace(*fp->_p)) {
					fp->_r--;
					*p++ = *fp->_p++;
					if (--width == 0)
						break;
					if (fp->_r <= 0 && __srefill(fp))
						break;
				}
				*p = '\0';
				nread += p - p0;
				nassigned++;
			}
			continue;

		case CT_INT:
			/* scan an integer as if by strtoimax/strtoumax */
#ifdef hardway
			if (width == 0 || width > sizeof(buf) - 1)
				width = sizeof(buf) - 1;
#else
			/* size_t is unsigned, hence this optimisation */
			if (--width > sizeof(buf) - 2)
				width = sizeof(buf) - 2;
			width++;
#endif
			flags |= SIGNOK | NDIGITS | NZDIGITS;
			for (p = buf; width; width--) {
				c = *fp->_p;
				/*
				 * Switch on the character; `goto ok'
				 * if we accept it as a part of number.
				 */
				switch (c) {

				/*
				 * The digit 0 is always legal, but is
				 * special.  For %i conversions, if no
				 * digits (zero or nonzero) have been
				 * scanned (only signs), we will have
				 * base==0.  In that case, we should set
				 * it to 8 and enable 0x prefixing.
				 * Also, if we have not scanned zero digits
				 * before this, do not turn off prefixing
				 * (someone else will turn it off if we
				 * have scanned any nonzero digits).
				 */
				case '0':
					if (base == 0) {
						base = 8;
						flags |= PFXOK;
					}
					if (flags & NZDIGITS)
					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
					else
					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
					goto ok;

				/* 1 through 7 always legal */
				case '1': case '2': case '3':
				case '4': case '5': case '6': case '7':
					base = basefix[base];
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
					goto ok;

				/* digits 8 and 9 ok iff decimal or hex */
				case '8': case '9':
					base = basefix[base];
					if (base <= 8)
						break;	/* not legal here */
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
					goto ok;

				/* letters ok iff hex */
				case 'A': case 'B': case 'C':
				case 'D': case 'E': case 'F':
				case 'a': case 'b': case 'c':
				case 'd': case 'e': case 'f':
					/* no need to fix base here */
					if (base <= 10)
						break;	/* not legal here */
					flags &= ~(SIGNOK | PFXOK | NDIGITS);
					goto ok;

				/* sign ok only as first character */
				case '+': case '-':
					if (flags & SIGNOK) {
						flags &= ~SIGNOK;
						flags |= HAVESIGN;
						goto ok;
					}
					break;

				/*
				 * x ok iff flag still set and 2nd char (or
				 * 3rd char if we have a sign).
				 */
				case 'x': case 'X':
					if ((flags & PFXOK) && p ==
					    buf + 1 + !!(flags & HAVESIGN)) {
						base = 16;	/* if %i */
						flags &= ~PFXOK;
						goto ok;
					}
					break;
				}

				/*
				 * If we got here, c is not a legal character
				 * for a number.  Stop accumulating digits.
				 */
				break;
		ok:
				/*
				 * c is legal: store it and look at the next.
				 */
				*p++ = c;
				if (--fp->_r > 0)
					fp->_p++;
				else if (__srefill(fp))
					break;		/* EOF */
			}
			/*
			 * If we had only a sign, it is no good; push
			 * back the sign.  If the number ends in `x',
			 * it was [sign] '0' 'x', so push back the x
			 * and treat it as [sign] '0'.
			 */
			if (flags & NDIGITS) {
				if (p > buf)
					(void) ungetc(*(u_char *)--p, fp);
				goto match_failure;
			}
			c = ((u_char *)p)[-1];
			if (c == 'x' || c == 'X') {
				--p;
				(void) ungetc(c, fp);
			}
			if ((flags & SUPPRESS) == 0) {
				uintmax_t res;

				*p = '\0';
				if (flags & UNSIGNED)
					res = strtoumax(buf, NULL, base);
				else
					res = strtoimax(buf, NULL, base);
				if (flags & POINTER)
					*va_arg(ap, void **) =
					    (void *)(uintptr_t)res;
				else if (flags & MAXINT)
					*va_arg(ap, intmax_t *) = res;
				else if (flags & LLONG)
					*va_arg(ap, long long *) = res;
				else if (flags & SIZEINT)
					*va_arg(ap, ssize_t *) = res;
				else if (flags & PTRINT)
					*va_arg(ap, ptrdiff_t *) = res;
				else if (flags & LONG)
					*va_arg(ap, long *) = res;
				else if (flags & SHORT)
					*va_arg(ap, short *) = res;
				else if (flags & SHORTSHORT)
					*va_arg(ap, __signed char *) = res;
				else
					*va_arg(ap, int *) = res;
				nassigned++;
			}
			nread += p - buf;
			break;

#ifdef FLOATING_POINT
		case CT_FLOAT:
			/* scan a floating point number as if by strtod */
#ifdef hardway
			if (width == 0 || width > sizeof(buf) - 1)
				width = sizeof(buf) - 1;
#else
			/* size_t is unsigned, hence this optimisation */
			if (--width > sizeof(buf) - 2)
				width = sizeof(buf) - 2;
			width++;
#endif
			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
			for (p = buf; width; width--) {
				c = *fp->_p;
				/*
				 * This code mimicks the integer conversion
				 * code, but is much simpler.
				 */
				switch (c) {

				case '0': case '1': case '2': case '3':
				case '4': case '5': case '6': case '7':
				case '8': case '9':
					flags &= ~(SIGNOK | NDIGITS);
					goto fok;

				case '+': case '-':
					if (flags & SIGNOK) {
						flags &= ~SIGNOK;
						goto fok;
					}
					break;
				case '.':
					if (flags & DPTOK) {
						flags &= ~(SIGNOK | DPTOK);
						goto fok;
					}
					break;
				case 'e': case 'E':
					/* no exponent without some digits */
					if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
						flags =
						    (flags & ~(EXPOK|DPTOK)) |
						    SIGNOK | NDIGITS;
						goto fok;
					}
					break;
				}
				break;
		fok:
				*p++ = c;
				if (--fp->_r > 0)
					fp->_p++;
				else if (__srefill(fp))
					break;	/* EOF */
			}
			/*
			 * If no digits, might be missing exponent digits
			 * (just give back the exponent) or might be missing
			 * regular digits, but had sign and/or decimal point.
			 */
			if (flags & NDIGITS) {
				if (flags & EXPOK) {
					/* no digits at all */
					while (p > buf)
						ungetc(*(u_char *)--p, fp);
					goto match_failure;
				}
				/* just a bad exponent (e and maybe sign) */
				c = *(u_char *)--p;
				if (c != 'e' && c != 'E') {
					(void) ungetc(c, fp);/* sign */
					c = *(u_char *)--p;
				}
				(void) ungetc(c, fp);
			}
			if ((flags & SUPPRESS) == 0) {
				double res;

				*p = '\0';
				res = strtod(buf, (char **) NULL);
				if (flags & LONGDBL)
					*va_arg(ap, long double *) = res;
				else if (flags & LONG)
					*va_arg(ap, double *) = res;
				else
					*va_arg(ap, float *) = res;
				nassigned++;
			}
			nread += p - buf;
			break;
#endif /* FLOATING_POINT */
		}
	}
input_failure:
	if (nassigned == 0)
		nassigned = -1;
match_failure:
	FUNLOCKFILE(fp);
	return (nassigned);
}