Example #1
0
/*
 * Write `count' objects (each size `size') from memory to the given file.
 * Return the number of whole objects written.
 */
size_t
fwrite(const void *buf, size_t size, size_t count, FILE *fp)
{
	size_t n;
	struct __suio uio;
	struct __siov iov;
	int ret;

	/*
	 * ANSI and SUSv2 require a return value of 0 if size or count are 0.
	 */
	if ((n = count * size) == 0)
		return (0);

	iov.iov_base = (void *)buf;
	uio.uio_resid = iov.iov_len = n;
	uio.uio_iov = &iov;
	uio.uio_iovcnt = 1;

	/*
	 * The usual case is success (__sfvwrite returns 0);
	 * skip the divide if this happens, since divides are
	 * generally slow and since this occurs whenever size==0.
	 */
	FLOCKFILE(fp);
	_SET_ORIENTATION(fp, -1);
	ret = __sfvwrite(fp, &uio);
	FUNLOCKFILE(fp);
	if (ret == 0)
		return (count);
	return ((n - uio.uio_resid) / size);
}
Example #2
0
/*
 * Write the given string to the given file.
 */
int
fputs(const char *s, FILE *fp)
{
  struct __suio uio;
  struct __siov iov;
  int r;

  _DIAGASSERT(s != NULL);
  _DIAGASSERT(fp != NULL);
  if(fp == NULL) {
    errno = EINVAL;
    return (EOF);
  }

  if (s == NULL)
    s = "(null)";

  iov.iov_base = __UNCONST(s);
  uio.uio_resid = (int)(iov.iov_len = strlen(s));
  uio.uio_iov = &iov;
  uio.uio_iovcnt = 1;
  FLOCKFILE(fp);
  _SET_ORIENTATION(fp, -1);
  r = __sfvwrite(fp, &uio);
  FUNLOCKFILE(fp);
  return r;
}
Example #3
0
wint_t
__ungetwc(wint_t wc, FILE *fp, locale_t locale)
{
	struct wchar_io_data *wcio;
	char buf[MB_LEN_MAX];
	size_t len;
	struct xlocale_ctype *l = XLOCALE_CTYPE(locale);

	if (wc == WEOF)
		return (WEOF);

	_SET_ORIENTATION(fp, 1);

	wcio = WCIO_GET(fp);
	if (wcio == 0) {
		errno = ENOMEM; /* XXX */
		return (WEOF);
	}

	len = l->__wcrtomb(buf, wc, &wcio->wcio_mbstate_in);
	if (len == (size_t)-1)
		return (WEOF);
	while (len--) {
		if (__ungetc(buf[len], fp) == EOF)
			return (WEOF);
	}
	__sclearerr(fp);
	return wc;
}
Example #4
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.
 * Do not return NULL if n == 1.
 */
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);
	_SET_ORIENTATION(fp, -1);
	s = buf;
	n--;			/* leave space for NUL */
	while (n != 0) {
		/*
		 * If the buffer is empty, refill it.
		 */
		if (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 ((int)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);
}
Example #5
0
int
putc_unlocked(int c, FILE *fp)
{
	if (cantwrite(fp)) {
		errno = EBADF;
		return (EOF);
	}
	_SET_ORIENTATION(fp, -1);
	return (__sputc(c, fp));
}
Example #6
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);
}
Example #7
0
wint_t
__fgetwc_unlock(FILE *fp)
{
    struct wchar_io_data *wcio;
    mbstate_t *st;
    wchar_t wc;
    size_t size;

    _DIAGASSERT(fp != NULL);
    if(fp == NULL) {
        errno = ENOSTR;
        return WEOF;
    }

    _SET_ORIENTATION(fp, 1);
    wcio = WCIO_GET(fp);
    if (wcio == 0) {
        errno = ENOMEM;
        return WEOF;
    }

    /* if there're ungetwc'ed wchars, use them */
    if (wcio->wcio_ungetwc_inbuf) {
        wc = wcio->wcio_ungetwc_buf[--wcio->wcio_ungetwc_inbuf];

        return wc;
    }

    st = &wcio->wcio_mbstate_in;

    do {
        char c;
        int ch = __sgetc(fp);

        if (ch == EOF) {
            return WEOF;
        }

        c = (char)ch;
        size = mbrtowc(&wc, &c, 1, st);
        if (size == (size_t)-1) {
            errno = EILSEQ;
            fp->_flags |= __SERR;
            return WEOF;
        }
    } while (size == (size_t)-2);

    _DIAGASSERT(size == 1);

    return wc;
}
Example #8
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);
}
Example #9
0
/*
 * Write the given character into the (probably full) buffer for
 * the given file.  Flush the buffer out if it is or becomes full,
 * or if c=='\n' and the file is line buffered.
 */
int
__swbuf(int c, FILE *fp)
{
  int n;

  //_DIAGASSERT(fp != NULL);
  if(fp == NULL) {
    errno = EINVAL;
    return (EOF);
  }

  _SET_ORIENTATION(fp, -1);

  /*
   * In case we cannot write, or longjmp takes us out early,
   * make sure _w is 0 (if fully- or un-buffered) or -_bf._size
   * (if line buffered) so that we will get called again.
   * If we did not do this, a sufficient number of putc()
   * calls might wrap _w from negative to positive.
   */
  fp->_w = fp->_lbfsize;
  if (cantwrite(fp)) {
    errno = EBADF;
    return (EOF);
  }
  c = (unsigned char)c;

  /*
   * If it is completely full, flush it out.  Then, in any case,
   * stuff c into the buffer.  If this causes the buffer to fill
   * completely, or if c is '\n' and the file is line buffered,
   * flush it (perhaps a second time).  The second flush will always
   * happen on unbuffered streams, where _bf._size==1; fflush()
   * guarantees that putc() will always call wbuf() by setting _w
   * to 0, so we need not do anything else.
   */
  n = (int)(fp->_p - fp->_bf._base);
  if (n >= fp->_bf._size) {
    if (fflush(fp))
      return (EOF);
    n = 0;
  }
  fp->_w--;
  *fp->_p++ = (unsigned char)c;
  if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n'))
    if (fflush(fp))
      return (EOF);
  return (c);
}
FILE *
open_wmemstream(wchar_t **pbuf, size_t *psize)
{
	struct state	*st;
	FILE		*fp;

	if (pbuf == NULL || psize == NULL) {
		errno = EINVAL;
		return (NULL);
	}

	if ((st = malloc(sizeof(*st))) == NULL)
		return (NULL);

	if ((fp = __sfp()) == NULL) {
		free(st);
		return (NULL);
	}

	st->size = BUFSIZ * sizeof(wchar_t);
	if ((st->string = calloc(1, st->size)) == NULL) {
		free(st);
		fp->_flags = 0;
		return (NULL);
	}

	*st->string = L'\0';
	st->pos = 0;
	st->len = 0;
	st->pbuf = pbuf;
	st->psize = psize;
	bzero(&st->mbs, sizeof(st->mbs));

	*pbuf = st->string;
	*psize = st->len;

	fp->_flags = __SWR;
	fp->_file = -1;
	fp->_cookie = st;
	fp->_read = NULL;
	fp->_write = wmemstream_write;
	fp->_seek = wmemstream_seek;
	fp->_close = wmemstream_close;
	_SET_ORIENTATION(fp, 1);

	return (fp);
}
Example #11
0
wint_t
__fputwc_unlock(wchar_t wc, FILE *fp)
{
  struct wchar_io_data *wcio;
  mbstate_t *st;
  size_t size;
  char buf[MB_LEN_MAX];
  struct __suio uio;
  struct __siov iov;

  _DIAGASSERT(fp != NULL);
  if(fp == NULL) {
    errno = EINVAL;
    return (WEOF);
  }

  /* LINTED we don't play with buf */
  iov.iov_base = (void *)buf;
  uio.uio_iov = &iov;
  uio.uio_iovcnt = 1;

  _SET_ORIENTATION(fp, 1);
  wcio = WCIO_GET(fp);
  if (wcio == 0) {
    errno = ENOMEM;
    return WEOF;
  }

  wcio->wcio_ungetwc_inbuf = 0;
  st = &wcio->wcio_mbstate_out;

  size = wcrtomb(buf, wc, st);
  if (size == (size_t)-1) {
    errno = EILSEQ;
    return WEOF;
  }

  _DIAGASSERT(size != 0);

  uio.uio_resid = (int)(iov.iov_len = size);
  if (__sfvwrite(fp, &uio)) {
    return WEOF;
  }

  return (wint_t)wc;
}
Example #12
0
/*
 * Write the given string to the given file.
 */
int
fputs(const char *s, FILE *fp)
{
	struct __suio uio;
	struct __siov iov;
	int ret;

	iov.iov_base = (void *)s;
	iov.iov_len = uio.uio_resid = strlen(s);
	uio.uio_iov = &iov;
	uio.uio_iovcnt = 1;
	FLOCKFILE(fp);
	_SET_ORIENTATION(fp, -1);
	ret = __sfvwrite(fp, &uio);
	FUNLOCKFILE(fp);
	return (ret);
}
Example #13
0
/*
 * Write the given string to stdout, appending a newline.
 */
int
puts(const char *s)
{
	size_t c = strlen(s);
	struct __suio uio;
	struct __siov iov[2];
	int ret;

	iov[0].iov_base = (void *)s;
	iov[0].iov_len = c;
	iov[1].iov_base = "\n";
	iov[1].iov_len = 1;
	uio.uio_resid = c + 1;
	uio.uio_iov = &iov[0];
	uio.uio_iovcnt = 2;
	FLOCKFILE(stdout);
	_SET_ORIENTATION(stdout, -1);
	ret = __sfvwrite(stdout, &uio);
	FUNLOCKFILE(stdout);
	return (ret ? EOF : '\n');
}
Example #14
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);
}
Example #15
0
wint_t
ungetwc(wint_t wc, FILE *fp)
{
  struct wchar_io_data *wcio;

  _DIAGASSERT(fp);

  if (wc == WEOF)
    return WEOF;

  FLOCKFILE(fp);
  _SET_ORIENTATION(fp, 1);
  /*
   * XXX since we have no way to transform a wchar string to
   * a char string in reverse order, we can't use ungetc.
   */
  /* XXX should we flush ungetc buffer? */

  wcio = WCIO_GET(fp);
  if (wcio == 0) {
    FUNLOCKFILE(fp);
    errno = ENOMEM; /* XXX */
    return WEOF;
  }

  if (wcio->wcio_ungetwc_inbuf >= WCIO_UNGETWC_BUFSIZE) {
    FUNLOCKFILE(fp);
    return WEOF;
  }

  wcio->wcio_ungetwc_buf[wcio->wcio_ungetwc_inbuf++] = (wchar_t)wc;
  __sclearerr(fp);
  FUNLOCKFILE(fp);

  return wc;
}
Example #16
0
/*
 * __svfscanf_unlocked - non-MT-safe version of __svfscanf
 */
int
__svfscanf_unlocked(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 */
  size_t n;   /* handy size_t */
  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 = { 0 };
  mbstate_t mbs;

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

  _DIAGASSERT(fp != NULL);
  _DIAGASSERT(fmt0 != NULL);
  if(fp == NULL) {
    errno = EINVAL;
    return (EOF);
  }

  _SET_ORIENTATION(fp, -1);

//Print(L"%a( %d, \"%a\", ...)\n", __func__, fp->_file, fmt0);
  nassigned = 0;
  nconversions = 0;
  nread = 0;
  base = 0;
  for (;;) {
    c = (unsigned char)*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;
    }
//Print(L"%a: %d\n", __func__, __LINE__);
    if (c != '%')
      goto literal;
    width = 0;
    flags = 0;
    /*
     * switch on the format.  continue if done;
     * break once format type is derived.
     */
again:    c = *fmt++;
//Print(L"%a: %d\n", __func__, __LINE__);
    switch (c) {
    case '%':
literal:
//Print(L"%a: %d\n", __func__, __LINE__);
      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 *) = (char)nread;
      else if (flags & SHORT)
        *va_arg(ap, short *) = (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);
    }
//Print(L"%a: %d\n", __func__, __LINE__);

    /*
     * We have a conversion that requires input.
     */
    if (fp->_r <= 0 && __srefill(fp))
    {
//Print(L"%a: %d\n", __func__, __LINE__);
      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))
        {
//Print(L"%a: %d\n", __func__, __LINE__);
          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.
     */
//Print(L"%a: %d\n", __func__, __LINE__);
    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 += (int)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) {
        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 -= (int)width;
            fp->_p += width;
            break;
          }
        }
        nread += (int)sum;
      } else {
        size_t r = fread(va_arg(ap, char *), 1,
            width, fp);

        if (r == 0)
          goto input_failure;
        nread += (int)r;
        nassigned++;
      }
      nconversions++;
      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 & LONG) {
        wchar_t twc;
        int nchars;

        if ((flags & SUPPRESS) == 0)
          wcp = va_arg(ap, wchar_t *);
        else
Example #17
0
int
__sungetc(int c, FILE *fp)
{
	if (c == EOF)
		return (EOF);
	if (!__sdidinit)
		__sinit();
	/*FLOCKFILE(fp);*/
	_SET_ORIENTATION(fp, -1);
	if ((fp->_flags & __SRD) == 0) {
		/*
		 * Not already reading: no good unless reading-and-writing.
		 * Otherwise, flush any current write stuff.
		 */
		if ((fp->_flags & __SRW) == 0) {
error:			/*FUNLOCKFILE(fp);*/
			return (EOF);
		}
		if (fp->_flags & __SWR) {
			if (__sflush(fp))
				goto error;
			fp->_flags &= ~__SWR;
			fp->_w = 0;
			fp->_lbfsize = 0;
		}
		fp->_flags |= __SRD;
	}
	c = (unsigned char)c;

	/*
	 * If we are in the middle of ungetc'ing, just continue.
	 * This may require expanding the current ungetc buffer.
	 */
	if (HASUB(fp)) {
		if (fp->_r >= _UB(fp)._size && __submore(fp))
			goto error;
		*--fp->_p = c;
inc_ret:	fp->_r++;
		/*FUNLOCKFILE(fp);*/
		return (c);
	}
	fp->_flags &= ~__SEOF;

	/*
	 * If we can handle this by simply backing up, do so,
	 * but never replace the original character.
	 * (This makes sscanf() work when scanning `const' data.)
	 */
	if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
	    fp->_p[-1] == c) {
		fp->_p--;
		goto inc_ret;
	}

	/*
	 * Create an ungetc buffer.
	 * Initially, we will use the `reserve' buffer.
	 */
	fp->_ur = fp->_r;
	fp->_up = fp->_p;
	_UB(fp)._base = fp->_ubuf;
	_UB(fp)._size = sizeof(fp->_ubuf);
	fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
	fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
	fp->_r = 1;
	/*FUNLOCKFILE(fp);*/
	return (c);
}
Example #18
0
int
__vfprintf(FILE *fp, const char *fmt0, __va_list ap)
{
	char *fmt;		/* format string */
	int ch;			/* character from fmt */
	int n, n2;		/* handy integers (short term usage) */
	char *cp;		/* handy char pointer (short term usage) */
	struct __siov *iovp;	/* for PRINT macro */
	int flags;		/* flags as above */
	int ret;		/* return value accumulator */
	int width;		/* width from format (%8d), or 0 */
	int prec;		/* precision from format; <0 for N/A */
	char sign;		/* sign prefix (' ', '+', '-', or \0) */
	wchar_t wc;
	mbstate_t ps;
#ifdef FLOATING_POINT
	/*
	 * We can decompose the printed representation of floating
	 * point numbers into several parts, some of which may be empty:
	 *
	 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
	 *    A       B     ---C---      D       E   F
	 *
	 * A:	'sign' holds this value if present; '\0' otherwise
	 * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
	 * C:	cp points to the string MMMNNN.  Leading and trailing
	 *	zeros are not in the string and must be added.
	 * D:	expchar holds this character; '\0' if no exponent, e.g. %f
	 * F:	at least two digits for decimal, at least one digit for hex
	 */
	char *decimal_point = NULL;
	int signflag;		/* true if float is negative */
	union {			/* floating point arguments %[aAeEfFgG] */
		double dbl;
		long double ldbl;
	} fparg;
	int expt;		/* integer value of exponent */
	char expchar;		/* exponent character: [eEpP\0] */
	char *dtoaend;		/* pointer to end of converted digits */
	int expsize;		/* character count for expstr */
	int lead;		/* sig figs before decimal or group sep */
	int ndig;		/* actual number of digits returned by dtoa */
	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
	char *dtoaresult = NULL;
#endif

	uintmax_t _umax;	/* integer arguments %[diouxX] */
	enum { OCT, DEC, HEX } base;	/* base for %[diouxX] conversion */
	int dprec;		/* a copy of prec if %[diouxX], 0 otherwise */
	int realsz;		/* field size expanded by dprec */
	int size;		/* size of converted field or string */
	const char *xdigs;	/* digits for %[xX] conversion */
#define NIOV 8
	struct __suio uio;	/* output information: summary */
	struct __siov iov[NIOV];/* ... and individual io vectors */
	char buf[BUF];		/* buffer with space for digits of uintmax_t */
	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
	union arg *argtable;	/* args, built due to positional arg */
	union arg statargtable[STATIC_ARG_TBL_SIZE];
	size_t argtablesiz;
	int nextarg;		/* 1-based argument index */
	va_list orgap;		/* original argument pointer */
#ifdef PRINTF_WIDE_CHAR
	char *convbuf;		/* buffer for wide to multi-byte conversion */
#endif

	/*
	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
	 * fields occur frequently, increase PADSIZE and make the initialisers
	 * below longer.
	 */
#define	PADSIZE	16		/* pad chunk size */
	static char blanks[PADSIZE] =
	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
	static char zeroes[PADSIZE] =
	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};

	static const char xdigs_lower[16] = "0123456789abcdef";
	static const char xdigs_upper[16] = "0123456789ABCDEF";

	/*
	 * BEWARE, these `goto error' on error, and PAD uses `n'.
	 */
#define	PRINT(ptr, len) do { \
	iovp->iov_base = (ptr); \
	iovp->iov_len = (len); \
	uio.uio_resid += (len); \
	iovp++; \
	if (++uio.uio_iovcnt >= NIOV) { \
		if (__sprint(fp, &uio)) \
			goto error; \
		iovp = iov; \
	} \
} while (0)
#define	PAD(howmany, with) do { \
	if ((n = (howmany)) > 0) { \
		while (n > PADSIZE) { \
			PRINT(with, PADSIZE); \
			n -= PADSIZE; \
		} \
		PRINT(with, n); \
	} \
} while (0)
#define	PRINTANDPAD(p, ep, len, with) do {	\
	n2 = (ep) - (p);       			\
	if (n2 > (len))				\
		n2 = (len);			\
	if (n2 > 0)				\
		PRINT((p), n2);			\
	PAD((len) - (n2 > 0 ? n2 : 0), (with));	\
} while(0)
#define	FLUSH() do { \
	if (uio.uio_resid && __sprint(fp, &uio)) \
		goto error; \
	uio.uio_iovcnt = 0; \
	iovp = iov; \
} while (0)

	/*
	 * To extend shorts properly, we need both signed and unsigned
	 * argument extraction methods.
	 */
#define	SARG() \
	((intmax_t)(flags&MAXINT ? GETARG(intmax_t) : \
	    flags&LLONGINT ? GETARG(long long) : \
	    flags&LONGINT ? GETARG(long) : \
	    flags&PTRINT ? GETARG(ptrdiff_t) : \
	    flags&SIZEINT ? GETARG(ssize_t) : \
	    flags&SHORTINT ? (short)GETARG(int) : \
	    flags&CHARINT ? (__signed char)GETARG(int) : \
	    GETARG(int)))
#define	UARG() \
	((uintmax_t)(flags&MAXINT ? GETARG(uintmax_t) : \
	    flags&LLONGINT ? GETARG(unsigned long long) : \
	    flags&LONGINT ? GETARG(unsigned long) : \
	    flags&PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */ \
	    flags&SIZEINT ? GETARG(size_t) : \
	    flags&SHORTINT ? (unsigned short)GETARG(int) : \
	    flags&CHARINT ? (unsigned char)GETARG(int) : \
	    GETARG(unsigned int)))

	/*
	 * Append a digit to a value and check for overflow.
	 */
#define APPEND_DIGIT(val, dig) do { \
	if ((val) > INT_MAX / 10) \
		goto overflow; \
	(val) *= 10; \
	if ((val) > INT_MAX - to_digit((dig))) \
		goto overflow; \
	(val) += to_digit((dig)); \
} while (0)

	 /*
	  * Get * arguments, including the form *nn$.  Preserve the nextarg
	  * that the argument can be gotten once the type is determined.
	  */
#define GETASTER(val) \
	n2 = 0; \
	cp = fmt; \
	while (is_digit(*cp)) { \
		APPEND_DIGIT(n2, *cp); \
		cp++; \
	} \
	if (*cp == '$') { \
		int hold = nextarg; \
		if (argtable == NULL) { \
			argtable = statargtable; \
			__find_arguments(fmt0, orgap, &argtable, &argtablesiz); \
		} \
		nextarg = n2; \
		val = GETARG(int); \
		nextarg = hold; \
		fmt = ++cp; \
	} else { \
		val = GETARG(int); \
	}

/*
* Get the argument indexed by nextarg.   If the argument table is
* built, use it to get the argument.  If its not, get the next
* argument (and arguments must be gotten sequentially).
*/
#define GETARG(type) \
	((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
		(nextarg++, va_arg(ap, type)))

	_SET_ORIENTATION(fp, -1);
	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
	if (cantwrite(fp)) {
		errno = EBADF;
		return (EOF);
	}

	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
	    fp->_file >= 0)
		return (__sbprintf(fp, fmt0, ap));

	fmt = (char *)fmt0;
	argtable = NULL;
	nextarg = 1;
	va_copy(orgap, ap);
	uio.uio_iov = iovp = iov;
	uio.uio_resid = 0;
	uio.uio_iovcnt = 0;
	ret = 0;
#ifdef PRINTF_WIDE_CHAR
	convbuf = NULL;
#endif

	memset(&ps, 0, sizeof(ps));
	/*
	 * Scan the format for conversions (`%' character).
	 */
	for (;;) {
		cp = fmt;
		while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
			fmt += n;
			if (wc == '%') {
				fmt--;
				break;
			}
		}
		if (fmt != cp) {
			ptrdiff_t m = fmt - cp;
			if (m < 0 || m > INT_MAX - ret)
				goto overflow;
			PRINT(cp, m);
			ret += m;
		}
		if (n <= 0)
			goto done;
		fmt++;		/* skip over '%' */

		flags = 0;
		dprec = 0;
		width = 0;
		prec = -1;
		sign = '\0';
		ox[1] = '\0';

rflag:		ch = *fmt++;
reswitch:	switch (ch) {
		case ' ':
			/*
			 * ``If the space and + flags both appear, the space
			 * flag will be ignored.''
			 *	-- ANSI X3J11
			 */
			if (!sign)
				sign = ' ';
			goto rflag;
		case '#':
			flags |= ALT;
			goto rflag;
		case '\'':
			/* grouping not implemented */
			goto rflag;
		case '*':
			/*
			 * ``A negative field width argument is taken as a
			 * - flag followed by a positive field width.''
			 *	-- ANSI X3J11
			 * They don't exclude field widths read from args.
			 */
			GETASTER(width);
			if (width >= 0)
				goto rflag;
			if (width == INT_MIN)
				goto overflow;
			width = -width;
			/* FALLTHROUGH */
		case '-':
			flags |= LADJUST;
			goto rflag;
		case '+':
			sign = '+';
			goto rflag;
		case '.':
			if ((ch = *fmt++) == '*') {
				GETASTER(n);
				prec = n < 0 ? -1 : n;
				goto rflag;
			}
			n = 0;
			while (is_digit(ch)) {
				APPEND_DIGIT(n, ch);
				ch = *fmt++;
			}
			if (ch == '$') {
				nextarg = n;
				if (argtable == NULL) {
					argtable = statargtable;
					__find_arguments(fmt0, orgap,
					    &argtable, &argtablesiz);
				}
				goto rflag;
			}
			prec = n;
			goto reswitch;
		case '0':
			/*
			 * ``Note that 0 is taken as a flag, not as the
			 * beginning of a field width.''
			 *	-- ANSI X3J11
			 */
			flags |= ZEROPAD;
			goto rflag;
		case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			n = 0;
			do {
				APPEND_DIGIT(n, ch);
				ch = *fmt++;
			} while (is_digit(ch));
			if (ch == '$') {
				nextarg = n;
				if (argtable == NULL) {
					argtable = statargtable;
					__find_arguments(fmt0, orgap,
					    &argtable, &argtablesiz);
				}
				goto rflag;
			}
			width = n;
			goto reswitch;
#ifdef FLOATING_POINT
		case 'L':
			flags |= LONGDBL;
			goto rflag;
#endif
		case 'h':
			if (*fmt == 'h') {
				fmt++;
				flags |= CHARINT;
			} else {
				flags |= SHORTINT;
			}
			goto rflag;
		case 'j':
			flags |= MAXINT;
			goto rflag;
		case 'l':
			if (*fmt == 'l') {
				fmt++;
				flags |= LLONGINT;
			} else {
				flags |= LONGINT;
			}
			goto rflag;
		case 'q':
			flags |= LLONGINT;
			goto rflag;
		case 't':
			flags |= PTRINT;
			goto rflag;
		case 'z':
			flags |= SIZEINT;
			goto rflag;
		case 'c':
#ifdef PRINTF_WIDE_CHAR
			if (flags & LONGINT) {
				mbstate_t mbs;
				size_t mbseqlen;

				memset(&mbs, 0, sizeof(mbs));
				mbseqlen = wcrtomb(buf,
				    (wchar_t)GETARG(wint_t), &mbs);
				if (mbseqlen == (size_t)-1) {
					fp->_flags |= __SERR;
					errno = EILSEQ;
					goto error;
				}
				cp = buf;
				size = (int)mbseqlen;
			} else {
#endif
				*(cp = buf) = GETARG(int);
				size = 1;
#ifdef PRINTF_WIDE_CHAR
			}
#endif
			sign = '\0';
			break;
		case 'D':
			flags |= LONGINT;
			/*FALLTHROUGH*/
		case 'd':
		case 'i':
			_umax = SARG();
			if ((intmax_t)_umax < 0) {
				_umax = -_umax;
				sign = '-';
			}
			base = DEC;
			goto number;
#ifdef FLOATING_POINT
		case 'a':
		case 'A':
			if (ch == 'a') {
				ox[1] = 'x';
				xdigs = xdigs_lower;
				expchar = 'p';
			} else {
				ox[1] = 'X';
				xdigs = xdigs_upper;
				expchar = 'P';
			}
			if (prec >= 0)
				prec++;
			if (dtoaresult)
				__freedtoa(dtoaresult);
			if (flags & LONGDBL) {
				fparg.ldbl = GETARG(long double);
				dtoaresult = cp =
				    __hldtoa(fparg.ldbl, xdigs, prec,
				    &expt, &signflag, &dtoaend);
				if (dtoaresult == NULL) {
					errno = ENOMEM;
					goto error;
				}
			} else {
				fparg.dbl = GETARG(double);
				dtoaresult = cp =
				    __hdtoa(fparg.dbl, xdigs, prec,
				    &expt, &signflag, &dtoaend);
				if (dtoaresult == NULL) {
					errno = ENOMEM;
					goto error;
				}
			}
			if (prec < 0)
				prec = dtoaend - cp;
			if (expt == INT_MAX)
				ox[1] = '\0';
			goto fp_common;
		case 'e':
		case 'E':
			expchar = ch;
			if (prec < 0)	/* account for digit before decpt */
				prec = DEFPREC + 1;
			else
				prec++;
			goto fp_begin;
		case 'f':
		case 'F':
			expchar = '\0';
			goto fp_begin;
		case 'g':
		case 'G':
			expchar = ch - ('g' - 'e');
 			if (prec == 0)
 				prec = 1;
fp_begin:
			if (prec < 0)
				prec = DEFPREC;
			if (dtoaresult)
				__freedtoa(dtoaresult);
			if (flags & LONGDBL) {
				fparg.ldbl = GETARG(long double);
				dtoaresult = cp =
				    __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
				    &expt, &signflag, &dtoaend);
				if (dtoaresult == NULL) {
					errno = ENOMEM;
					goto error;
				}
			} else {
Example #19
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
Example #20
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);
}
Example #21
0
/*
 * Non-MT-safe version
 */
int
__vfprintf(FILE *fp, locale_t locale, const char *fmt0, __va_list ap)
{
	char *fmt;		/* format string */
	int ch;			/* character from fmt */
	int n, n2;		/* handy integers (short term usage) */
	char *cp;		/* handy char pointer (short term usage) */
	int flags;		/* flags as above */
	int ret;		/* return value accumulator */
	int width;		/* width from format (%8d), or 0 */
	int prec;		/* precision from format; <0 for N/A */
	char sign;		/* sign prefix (' ', '+', '-', or \0) */
	struct grouping_state gs; /* thousands' grouping info */

#ifdef FLOATING_POINT
	/*
	 * We can decompose the printed representation of floating
	 * point numbers into several parts, some of which may be empty:
	 *
	 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
	 *    A       B     ---C---      D       E   F
	 *
	 * A:	'sign' holds this value if present; '\0' otherwise
	 * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
	 * C:	cp points to the string MMMNNN.  Leading and trailing
	 *	zeros are not in the string and must be added.
	 * D:	expchar holds this character; '\0' if no exponent, e.g. %f
	 * F:	at least two digits for decimal, at least one digit for hex
	 */
	char *decimal_point = NULL;	/* locale specific decimal point */
	int decpt_len;		/* length of decimal_point */
	int signflag;		/* true if float is negative */
	union {			/* floating point arguments %[aAeEfFgG] */
		double dbl;
		long double ldbl;
	} fparg;
	int expt;		/* integer value of exponent */
	char expchar;		/* exponent character: [eEpP\0] */
	char *dtoaend;		/* pointer to end of converted digits */
	int expsize;		/* character count for expstr */
	int ndig;		/* actual number of digits returned by dtoa */
	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
	char *dtoaresult = NULL;	/* buffer allocated by dtoa */
#endif
	u_long	ulval;		/* integer arguments %[diouxX] */
	uintmax_t ujval;	/* %j, %ll, %q, %t, %z integers */
	int base;		/* base for [diouxX] conversion */
	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
	int realsz;		/* field size expanded by dprec, sign, etc */
	int size;		/* size of converted field or string */
	const char *xdigs;     	/* digits for %[xX] conversion */
	struct io_state io;	/* I/O buffering state */
	char buf[BUF];		/* buffer with space for digits of uintmax_t */
	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
	union arg *argtable;    /* args, built due to positional arg */
	union arg statargtable [STATIC_ARG_TBL_SIZE];
	int nextarg;            /* 1-based argument index */
	va_list orgap;          /* original argument pointer */
	char *convbuf;		/* wide to multibyte conversion result */

	static const char xdigs_lower[16] = "0123456789abcdef";
	static const char xdigs_upper[16] = "0123456789ABCDEF";

	/* BEWARE, these `goto error' on error. */
#define	PRINT(ptr, len) { \
	if (io_print(&io, (ptr), (len), locale))	\
		goto error; \
}
#define	PAD(howmany, with) { \
	if (io_pad(&io, (howmany), (with), locale)) \
		goto error; \
}
#define	PRINTANDPAD(p, ep, len, with) {	\
	if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
		goto error; \
}
#define	FLUSH() { \
	if (io_flush(&io, locale)) \
		goto error; \
}
	/*
	 * Get the argument indexed by nextarg.   If the argument table is
	 * built, use it to get the argument.  If its not, get the next
	 * argument (and arguments must be gotten sequentially).
	 */
#define GETARG(type) \
	((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
	    (nextarg++, va_arg(ap, type)))

	/*
	 * To extend shorts properly, we need both signed and unsigned
	 * argument extraction methods.
	 */
#define	SARG() \
	(flags&LONGINT ? GETARG(long) : \
	    flags&SHORTINT ? (long)(short)GETARG(int) : \
	    flags&CHARINT ? (long)(signed char)GETARG(int) : \
	    (long)GETARG(int))
#define	UARG() \
	(flags&LONGINT ? GETARG(u_long) : \
	    flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
	    flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
	    (u_long)GETARG(u_int))
#define	INTMAX_SIZE	(INTMAXT|SIZET|PTRDIFFT|LLONGINT)
#define SJARG() \
	(flags&INTMAXT ? GETARG(intmax_t) : \
	    flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
	    flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
	    (intmax_t)GETARG(long long))
#define	UJARG() \
	(flags&INTMAXT ? GETARG(uintmax_t) : \
	    flags&SIZET ? (uintmax_t)GETARG(size_t) : \
	    flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
	    (uintmax_t)GETARG(unsigned long long))

	/*
	 * Append a digit to a value and check for overflow.
	 */
#define APPEND_DIGIT(val, dig) do { \
	if ((val) > INT_MAX / 10) \
		goto overflow; \
	(val) *= 10; \
	if ((val) > INT_MAX - to_digit((dig))) \
		goto overflow; \
	(val) += to_digit((dig)); \
} while (0)

	/*
	 * Get * arguments, including the form *nn$.  Preserve the nextarg
	 * that the argument can be gotten once the type is determined.
	 */
#define GETASTER(val) \
	n2 = 0; \
	cp = fmt; \
	while (is_digit(*cp)) { \
		APPEND_DIGIT(n2, *cp); \
		cp++; \
	} \
	if (*cp == '$') { \
		int hold = nextarg; \
		if (argtable == NULL) { \
			argtable = statargtable; \
			if (__find_arguments (fmt0, orgap, &argtable)) { \
				ret = EOF; \
				goto error; \
			} \
		} \
		nextarg = n2; \
		val = GETARG(int); \
		nextarg = hold; \
		fmt = ++cp; \
	} else { \
		val = GETARG(int); \
	}

	_SET_ORIENTATION(fp, -1);
	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
	if (cantwrite(fp)) {
		errno = EBADF;
		return (EOF);
	}

	fmt = (char *)fmt0;
	argtable = NULL;
	nextarg = 1;
	va_copy(orgap, ap);
	io_init(&io, fp);
	ret = 0;
#ifdef FLOATING_POINT
	decimal_point = localeconv_l(locale)->decimal_point;
	/* The overwhelmingly common case is decpt_len == 1. */
	decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
#endif
#ifdef PRINTF_WIDE_CHAR
	convbuf = NULL;
#endif

	/*
	 * Scan the format for conversions (`%' character).
	 */
	for (;;) {
		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
			/* void */;
		if (fmt != cp) {
			ptrdiff_t m = fmt - cp;
			if (m < 0 || m > INT_MAX - ret)
				goto overflow;
			PRINT(cp, m);
			ret += m;
		}
		if (ch == '\0')
			goto done;
		fmt++;		/* skip over '%' */

		flags = 0;
		dprec = 0;
		width = 0;
		prec = -1;
		gs.grouping = NULL;
		sign = '\0';
		ox[1] = '\0';

rflag:		ch = *fmt++;
reswitch:	switch (ch) {
		case ' ':
			/*
			 * ``If the space and + flags both appear, the space
			 * flag will be ignored.''
			 *	-- ANSI X3J11
			 */
			if (!sign)
				sign = ' ';
			goto rflag;
		case '#':
			flags |= ALT;
			goto rflag;
		case '*':
			/*
			 * ``A negative field width argument is taken as a
			 * - flag followed by a positive field width.''
			 *	-- ANSI X3J11
			 * They don't exclude field widths read from args.
			 */
			GETASTER(width);
			if (width >= 0)
				goto rflag;
			if (width == INT_MIN)
				goto overflow;
			width = -width;
			/* FALLTHROUGH */
		case '-':
			flags |= LADJUST;
			goto rflag;
		case '+':
			sign = '+';
			goto rflag;
		case '\'':
			flags |= GROUPING;
			goto rflag;
		case '.':
			if ((ch = *fmt++) == '*') {
				GETASTER(n);
				prec = n < 0 ? -1 : n;
				goto rflag;
			}
			n = 0;
			while (is_digit(ch)) {
				APPEND_DIGIT(n, ch);
				ch = *fmt++;
			}
			if (ch == '$') {
				nextarg = n;
				if (argtable == NULL) {
					argtable = statargtable;
					if (__find_arguments (fmt0, orgap,
							      &argtable)) {
						ret = EOF;
						goto error;
					}
				}
				goto rflag;
			}
			prec = n;
			goto reswitch;
		case '0':
			/*
			 * ``Note that 0 is taken as a flag, not as the
			 * beginning of a field width.''
			 *	-- ANSI X3J11
			 */
			flags |= ZEROPAD;
			goto rflag;
		case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			n = 0;
			do {
				APPEND_DIGIT(n, ch);
				ch = *fmt++;
			} while (is_digit(ch));
			if (ch == '$') {
				nextarg = n;
				if (argtable == NULL) {
					argtable = statargtable;
					if (__find_arguments (fmt0, orgap,
							      &argtable)) {
						ret = EOF;
						goto error;
					}
				}
				goto rflag;
			}
			width = n;
			goto reswitch;
#ifdef FLOATING_POINT
		case 'L':
			flags |= LONGDBL;
			goto rflag;
#endif
		case 'h':
			if (flags & SHORTINT) {
				flags &= ~SHORTINT;
				flags |= CHARINT;
			} else {
				flags |= SHORTINT;
			}
			goto rflag;
		case 'j':
			flags |= INTMAXT;
			goto rflag;
		case 'l':
			if (flags & LONGINT) {
				flags &= ~LONGINT;
				flags |= LLONGINT;
			} else {
				flags |= LONGINT;
			}
			goto rflag;
		case 'q':
			flags |= LLONGINT;	/* not necessarily */
			goto rflag;
		case 't':
			flags |= PTRDIFFT;
			goto rflag;
		case 'z':
			flags |= SIZET;
			goto rflag;
		case 'C':
			flags |= LONGINT;
			/*FALLTHROUGH*/
		case 'c':
#ifdef PRINTF_WIDE_CHAR
			if (flags & LONGINT) {
				mbstate_t mbs;
				size_t mbseqlen;

				memset(&mbs, 0, sizeof(mbs));
				mbseqlen = wcrtomb(buf,
				    (wchar_t)GETARG(wint_t), &mbs);
				if (mbseqlen == (size_t)-1) {
					fp->_flags |= __SERR;
					errno = EILSEQ;
					goto error;
				}
				cp = buf;
				size = (int)mbseqlen;
			} else {
#endif
				*(cp = buf) = GETARG(int);
				size = 1;
#ifdef PRINTF_WIDE_CHAR
			}
#endif
			sign = '\0';
			break;
		case 'D':
			flags |= LONGINT;
			/*FALLTHROUGH*/
		case 'd':
		case 'i':
			if (flags & INTMAX_SIZE) {
				ujval = SJARG();
				if ((intmax_t)ujval < 0) {
					ujval = -ujval;
					sign = '-';
				}
			} else {
				ulval = SARG();
				if ((long)ulval < 0) {
					ulval = -ulval;
					sign = '-';
				}
			}
			base = 10;
			goto number;
#ifdef FLOATING_POINT
		case 'a':
		case 'A':
			if (ch == 'a') {
				ox[1] = 'x';
				xdigs = xdigs_lower;
				expchar = 'p';
			} else {
				ox[1] = 'X';
				xdigs = xdigs_upper;
				expchar = 'P';
			}
			if (prec >= 0)
				prec++;
			if (dtoaresult != NULL)
				__freedtoa(dtoaresult);
			if (flags & LONGDBL) {
				fparg.ldbl = GETARG(long double);
				dtoaresult = cp =
				    __hldtoa(fparg.ldbl, xdigs, prec,
				    &expt, &signflag, &dtoaend);
				if (dtoaresult == NULL) {
					errno = ENOMEM;
					goto error;
				}
			} else {
				fparg.dbl = GETARG(double);
				dtoaresult = cp =
				    __hdtoa(fparg.dbl, xdigs, prec,
				    &expt, &signflag, &dtoaend);
				if (dtoaresult == NULL) {
					errno = ENOMEM;
					goto error;
				}
			}
			if (prec < 0)
				prec = dtoaend - cp;
			if (expt == INT_MAX)
				ox[1] = '\0';
			goto fp_common;
		case 'e':
		case 'E':
			expchar = ch;
			if (prec < 0)	/* account for digit before decpt */
				prec = DEFPREC + 1;
			else
				prec++;
			goto fp_begin;
		case 'f':
		case 'F':
			expchar = '\0';
			goto fp_begin;
		case 'g':
		case 'G':
			expchar = ch - ('g' - 'e');
			if (prec == 0)
				prec = 1;
fp_begin:
			if (prec < 0)
				prec = DEFPREC;
			if (dtoaresult != NULL)
				__freedtoa(dtoaresult);
			if (flags & LONGDBL) {
				fparg.ldbl = GETARG(long double);
				dtoaresult = cp =
				    __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
				    &expt, &signflag, &dtoaend);
				if (dtoaresult == NULL) {
					errno = ENOMEM;
					goto error;
				}
			} else {