提交 e480f9c5 编写于 作者: A Anton Perkov

stdio source code

上级 285c3233
#include "stdio_impl.h"
int __fclose_ca(FILE *f)
{
return f->close(f);
}
#include "stdio_impl.h"
#include "pthread_impl.h"
int __lockfile(FILE *f)
{
/*
int owner, tid = __pthread_self()->tid;
if (f->lock == tid)
return 0;
while ((owner = a_cas(&f->lock, 0, tid)))
__wait(&f->lock, &f->waiters, owner, 1);
return 1;
*/
}
void __unlockfile(FILE *f)
{
//a_store(&f->lock, 0);
/* The following read is technically invalid under situations
* of self-synchronized destruction. Another thread may have
* called fclose as soon as the above store has completed.
* Nonetheless, since FILE objects always live in memory
* obtained by malloc from the heap, it's safe to assume
* the dereferences below will not fault. In the worst case,
* a spurious syscall will be made. If the implementation of
* malloc changes, this assumption needs revisiting. */
//if (f->waiters) __wake(&f->lock, 1, 1);
}
#include "stdio_impl.h"
int __overflow(FILE *f, int _c)
{
unsigned char c = _c;
if (!f->wend && __towrite(f)) return EOF;
if (f->wpos < f->wend && c != f->lbf) return *f->wpos++ = c;
if (f->write(f, &c, 1)!=1) return EOF;
return c;
}
#include "stdio_impl.h"
static int dummy(int fd)
{
return fd;
}
weak_alias(dummy, __aio_close);
int __stdio_close(FILE *f)
{
/*
return syscall(SYS_close, __aio_close(f->fd));
*/
}
#include "stdio_impl.h"
static FILE *volatile dummy_file = 0;
weak_alias(dummy_file, __stdin_used);
weak_alias(dummy_file, __stdout_used);
weak_alias(dummy_file, __stderr_used);
static void close_file(FILE *f)
{
if (!f) return;
FFINALLOCK(f);
if (f->wpos > f->wbase) f->write(f, 0, 0);
if (f->rpos < f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR);
}
void __stdio_exit(void)
{
FILE *f;
for (f=*__ofl_lock(); f; f=f->next) close_file(f);
close_file(__stdin_used);
close_file(__stdout_used);
}
weak_alias(__stdio_exit, __stdio_exit_needed);
#include "stdio_impl.h"
//include <sys/uio.h>
size_t __stdio_read(FILE *f, unsigned char *buf, size_t len)
{
/*
struct iovec iov[2] = {
{ .iov_base = buf, .iov_len = len - !!f->buf_size },
{ .iov_base = f->buf, .iov_len = f->buf_size }
};
ssize_t cnt;
cnt = syscall(SYS_readv, f->fd, iov, 2);
if (cnt <= 0) {
f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt);
return cnt;
}
if (cnt <= iov[0].iov_len) return cnt;
cnt -= iov[0].iov_len;
f->rpos = f->buf;
f->rend = f->buf + cnt;
if (f->buf_size) buf[len-1] = *f->rpos++;
return len;
*/
}
#include "stdio_impl.h"
off_t __stdio_seek(FILE *f, off_t off, int whence)
{
abort();
/*
off_t ret;
#ifdef SYS__llseek
if (syscall(SYS__llseek, f->fd, off>>32, off, &ret, whence)<0)
ret = -1;
#else
ret = syscall(SYS_lseek, f->fd, off, whence);
#endif
return ret;
*/
}
#include "stdio_impl.h"
//include <sys/uio.h>
size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
{
/*
struct iovec iovs[2] = {
{ .iov_base = f->wbase, .iov_len = f->wpos-f->wbase },
{ .iov_base = (void *)buf, .iov_len = len }
};
struct iovec *iov = iovs;
size_t rem = iov[0].iov_len + iov[1].iov_len;
int iovcnt = 2;
ssize_t cnt;
for (;;) {
cnt = syscall(SYS_writev, f->fd, iov, iovcnt);
if (cnt == rem) {
f->wend = f->buf + f->buf_size;
f->wpos = f->wbase = f->buf;
return len;
}
if (cnt < 0) {
f->wpos = f->wbase = f->wend = 0;
f->flags |= F_ERR;
return iovcnt == 2 ? 0 : len-iov[0].iov_len;
}
rem -= cnt;
if (cnt > iov[0].iov_len) {
cnt -= iov[0].iov_len;
iov++; iovcnt--;
}
iov[0].iov_base = (char *)iov[0].iov_base + cnt;
iov[0].iov_len -= cnt;
}
*/
}
#include "stdio_impl.h"
//include <sys/ioctl.h>
size_t __stdout_write(FILE *f, const unsigned char *buf, size_t len)
{
/*
struct winsize wsz;
f->write = __stdio_write;
if (!(f->flags & F_SVB) && __syscall(SYS_ioctl, f->fd, TIOCGWINSZ, &wsz))
f->lbf = -1;
return __stdio_write(f, buf, len);
*/
}
#include "stdio_impl.h"
#include <string.h>
size_t __string_read(FILE *f, unsigned char *buf, size_t len)
{
char *src = f->cookie;
size_t k = len+256;
char *end = memchr(src, 0, k);
if (end) k = end-src;
if (k < len) len = k;
memcpy(buf, src, len);
f->rpos = (void *)(src+len);
f->rend = (void *)(src+k);
f->cookie = src+k;
return len;
}
#include <stdio_impl.h>
int __toread(FILE *f)
{
f->mode |= f->mode-1;
if (f->wpos > f->wbase) f->write(f, 0, 0);
f->wpos = f->wbase = f->wend = 0;
if (f->flags & F_NORD) {
f->flags |= F_ERR;
return EOF;
}
f->rpos = f->rend = f->buf + f->buf_size;
return (f->flags & F_EOF) ? EOF : 0;
}
void __stdio_exit_needed(void);
void __toread_needs_stdio_exit()
{
__stdio_exit_needed();
}
#include "stdio_impl.h"
int __towrite(FILE *f)
{
f->mode |= f->mode-1;
if (f->flags & (F_NOWR)) {
f->flags |= F_ERR;
return EOF;
}
/* Clear read buffer (easier than summoning nasal demons) */
f->rpos = f->rend = 0;
/* Activate write through the buffer. */
f->wpos = f->wbase = f->buf;
f->wend = f->buf + f->buf_size;
return 0;
}
void __stdio_exit_needed(void);
void __towrite_needs_stdio_exit()
{
__stdio_exit_needed();
}
#include "stdio_impl.h"
/* This function assumes it will never be called if there is already
* data buffered for reading. */
int __uflow(FILE *f)
{
unsigned char c;
if (!__toread(f) && f->read(f, &c, 1)==1) return c;
return EOF;
}
#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h>
int asprintf(char **s, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vasprintf(s, fmt, ap);
va_end(ap);
return ret;
}
#include "stdio_impl.h"
void clearerr(FILE *f)
{
FLOCK(f);
f->flags &= ~(F_EOF|F_ERR);
FUNLOCK(f);
}
weak_alias(clearerr, clearerr_unlocked);
#include <stdio.h>
#include <stdarg.h>
int dprintf(int fd, const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vdprintf(fd, fmt, ap);
va_end(ap);
return ret;
}
#define _GNU_SOURCE
#include "stdio_impl.h"
#include <stdio_ext.h>
void _flushlbf(void)
{
fflush(0);
}
int __fsetlocking(FILE *f, int type)
{
return 0;
}
int __fwriting(FILE *f)
{
return (f->flags & F_NORD) || f->wend;
}
int __freading(FILE *f)
{
return (f->flags & F_NOWR) || f->rend;
}
int __freadable(FILE *f)
{
return !(f->flags & F_NORD);
}
int __fwritable(FILE *f)
{
return !(f->flags & F_NOWR);
}
int __flbf(FILE *f)
{
return f->lbf >= 0;
}
size_t __fbufsize(FILE *f)
{
return f->buf_size;
}
size_t __fpending(FILE *f)
{
return f->wend ? f->wpos - f->wbase : 0;
}
int __fpurge(FILE *f)
{
f->wpos = f->wbase = f->wend = 0;
f->rpos = f->rend = 0;
return 0;
}
weak_alias(__fpurge, fpurge);
#include "stdio_impl.h"
size_t __freadahead(FILE *f)
{
return f->rend - f->rpos;
}
const char *__freadptr(FILE *f, size_t *sizep)
{
size_t size = f->rend - f->rpos;
if (!size) return 0;
*sizep = size;
return (const char *)f->rpos;
}
void __freadptrinc(FILE *f, size_t inc)
{
f->rpos += inc;
}
void __fseterr(FILE *f)
{
f->flags |= F_ERR;
}
#include "stdio_impl.h"
#include "libc.h"
static void dummy(FILE *f) { }
weak_alias(dummy, __unlist_locked_file);
int fclose(FILE *f)
{
int r;
int perm;
FLOCK(f);
__unlist_locked_file(f);
if (!(perm = f->flags & F_PERM)) {
FILE **head = __ofl_lock();
if (f->prev) f->prev->next = f->next;
if (f->next) f->next->prev = f->prev;
if (*head == f) *head = f->next;
__ofl_unlock();
}
r = fflush(f);
r |= f->close(f);
if (f->getln_buf) free(f->getln_buf);
if (!perm) free(f);
else FUNLOCK(f);
return r;
}
#include "stdio_impl.h"
#undef feof
int feof(FILE *f)
{
FLOCK(f);
int ret = !!(f->flags & F_EOF);
FUNLOCK(f);
return ret;
}
weak_alias(feof, feof_unlocked);
weak_alias(feof, _IO_feof_unlocked);
#include "stdio_impl.h"
#undef ferror
int ferror(FILE *f)
{
FLOCK(f);
int ret = !!(f->flags & F_ERR);
FUNLOCK(f);
return ret;
}
weak_alias(ferror, ferror_unlocked);
weak_alias(ferror, _IO_ferror_unlocked);
#include "stdio_impl.h"
/* stdout.c will override this if linked */
static FILE *volatile dummy = 0;
weak_alias(dummy, __stdout_used);
int fflush(FILE *f)
{
if (!f) {
int r = __stdout_used ? fflush(__stdout_used) : 0;
for (f=*__ofl_lock(); f; f=f->next) {
FLOCK(f);
if (f->wpos > f->wbase) r |= fflush(f);
FUNLOCK(f);
}
__ofl_unlock();
return r;
}
FLOCK(f);
/* If writing, flush output */
if (f->wpos > f->wbase) {
f->write(f, 0, 0);
if (!f->wpos) {
FUNLOCK(f);
return EOF;
}
}
/* If reading, sync position, per POSIX */
if (f->rpos < f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR);
/* Clear read and write modes */
f->wpos = f->wbase = f->wend = 0;
f->rpos = f->rend = 0;
FUNLOCK(f);
return 0;
}
weak_alias(fflush, fflush_unlocked);
#include "stdio_impl.h"
int fgetc(FILE *f)
{
int c;
if (f->lock < 0 || !__lockfile(f))
return getc_unlocked(f);
c = getc_unlocked(f);
__unlockfile(f);
return c;
}
#define _GNU_SOURCE
#include "stdio_impl.h"
#include <string.h>
char *fgetln(FILE *f, size_t *plen)
{
char *ret = 0, *z;
ssize_t l;
FLOCK(f);
ungetc(getc_unlocked(f), f);
if ((z=memchr(f->rpos, '\n', f->rend - f->rpos))) {
ret = (char *)f->rpos;
*plen = ++z - ret;
f->rpos = (void *)z;
} else if ((l = getline(&f->getln_buf, (size_t[]){0}, f)) > 0) {
*plen = l;
ret = f->getln_buf;
}
FUNLOCK(f);
return ret;
}
#include "stdio_impl.h"
int fgetpos(FILE *restrict f, fpos_t *restrict pos)
{
off_t off = __ftello(f);
if (off < 0) return -1;
*(off_t *)pos = off;
return 0;
}
LFS64(fgetpos);
#include "stdio_impl.h"
#include <string.h>
#define MIN(a,b) ((a)<(b) ? (a) : (b))
char *fgets(char *restrict s, int n, FILE *restrict f)
{
char *p = s;
unsigned char *z;
size_t k;
int c;
FLOCK(f);
if (n--<=1) {
f->mode |= f->mode-1;
FUNLOCK(f);
if (n) return 0;
*s = 0;
return s;
}
while (n) {
z = memchr(f->rpos, '\n', f->rend - f->rpos);
k = z ? z - f->rpos + 1 : f->rend - f->rpos;
k = MIN(k, n);
memcpy(p, f->rpos, k);
f->rpos += k;
p += k;
n -= k;
if (z || !n) break;
if ((c = getc_unlocked(f)) < 0) {
if (p==s || !feof(f)) s = 0;
break;
}
n--;
if ((*p++ = c) == '\n') break;
}
if (s) *p = 0;
FUNLOCK(f);
return s;
}
weak_alias(fgets, fgets_unlocked);
#include "stdio_impl.h"
#include "locale_impl.h"
#include <wchar.h>
#include <errno.h>
static wint_t __fgetwc_unlocked_internal(FILE *f)
{
wchar_t wc;
int c;
size_t l;
/* Convert character from buffer if possible */
if (f->rpos < f->rend) {
l = mbtowc(&wc, (void *)f->rpos, f->rend - f->rpos);
if (l+1 >= 1) {
f->rpos += l + !l; /* l==0 means 1 byte, null */
return wc;
}
}
/* Convert character byte-by-byte */
mbstate_t st = { 0 };
unsigned char b;
int first = 1;
do {
b = c = getc_unlocked(f);
if (c < 0) {
if (!first) errno = EILSEQ;
return WEOF;
}
l = mbrtowc(&wc, (void *)&b, 1, &st);
if (l == -1) {
if (!first) ungetc(b, f);
return WEOF;
}
first = 0;
} while (l == -2);
return wc;
}
wint_t __fgetwc_unlocked(FILE *f)
{
locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
if (f->mode <= 0) fwide(f, 1);
*ploc = f->locale;
wchar_t wc = __fgetwc_unlocked_internal(f);
*ploc = loc;
return wc;
}
wint_t fgetwc(FILE *f)
{
wint_t c;
FLOCK(f);
c = __fgetwc_unlocked(f);
FUNLOCK(f);
return c;
}
weak_alias(__fgetwc_unlocked, fgetwc_unlocked);
weak_alias(__fgetwc_unlocked, getwc_unlocked);
#include "stdio_impl.h"
#include <wchar.h>
#include <errno.h>
wint_t __fgetwc_unlocked(FILE *);
wchar_t *fgetws(wchar_t *restrict s, int n, FILE *restrict f)
{
wchar_t *p = s;
if (!n--) return s;
FLOCK(f);
/* Setup a dummy errno so we can detect EILSEQ. This is
* the only way to catch encoding errors in the form of a
* partial character just before EOF. */
errno = EAGAIN;
for (; n; n--) {
wint_t c = __fgetwc_unlocked(f);
if (c == WEOF) break;
*p++ = c;
if (c == '\n') break;
}
*p = 0;
if (ferror(f) || errno==EILSEQ) p = s;
FUNLOCK(f);
return (p == s) ? NULL : s;
}
weak_alias(fgetws, fgetws_unlocked);
#include "stdio_impl.h"
int fileno(FILE *f)
{
/* f->fd never changes, but the lock must be obtained and released
* anyway since this function cannot return while another thread
* holds the lock. */
FLOCK(f);
FUNLOCK(f);
return f->fd;
}
weak_alias(fileno, fileno_unlocked);
#include "stdio_impl.h"
#include <errno.h>
#include <string.h>
#include <inttypes.h>
struct cookie {
size_t pos, len, size;
unsigned char *buf;
int mode;
};
static off_t mseek(FILE *f, off_t off, int whence)
{
ssize_t base;
struct cookie *c = f->cookie;
if (whence>2U) {
fail:
errno = EINVAL;
return -1;
}
base = (size_t [3]){0, c->pos, c->len}[whence];
if (off < -base || off > (ssize_t)c->size-base) goto fail;
return c->pos = base+off;
}
static size_t mread(FILE *f, unsigned char *buf, size_t len)
{
struct cookie *c = f->cookie;
size_t rem = c->len - c->pos;
if (c->pos > c->len) rem = 0;
if (len > rem) {
len = rem;
f->flags |= F_EOF;
}
memcpy(buf, c->buf+c->pos, len);
c->pos += len;
rem -= len;
if (rem > f->buf_size) rem = f->buf_size;
f->rpos = f->buf;
f->rend = f->buf + rem;
memcpy(f->rpos, c->buf+c->pos, rem);
c->pos += rem;
return len;
}
static size_t mwrite(FILE *f, const unsigned char *buf, size_t len)
{
struct cookie *c = f->cookie;
size_t rem;
size_t len2 = f->wpos - f->wbase;
if (len2) {
f->wpos = f->wbase;
if (mwrite(f, f->wpos, len2) < len2) return 0;
}
if (c->mode == 'a') c->pos = c->len;
rem = c->size - c->pos;
if (len > rem) len = rem;
memcpy(c->buf+c->pos, buf, len);
c->pos += len;
if (c->pos > c->len) {
c->len = c->pos;
if (c->len < c->size) c->buf[c->len] = 0;
else if ((f->flags&F_NORD) && c->size) c->buf[c->size-1] = 0;
}
return len;
}
static int mclose(FILE *m)
{
return 0;
}
FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode)
{
FILE *f;
struct cookie *c;
int plus = !!strchr(mode, '+');
if (!size || !strchr("rwa", *mode)) {
errno = EINVAL;
return 0;
}
if (!buf && size > SIZE_MAX-sizeof(FILE)-BUFSIZ-UNGET) {
errno = ENOMEM;
return 0;
}
f = calloc(sizeof *f + sizeof *c + UNGET + BUFSIZ + (buf?0:size), 1);
if (!f) return 0;
f->cookie = c = (void *)(f+1);
f->fd = -1;
f->lbf = EOF;
f->buf = (unsigned char *)(c+1) + UNGET;
f->buf_size = BUFSIZ;
if (!buf) buf = f->buf + BUFSIZ;
c->buf = buf;
c->size = size;
c->mode = *mode;
if (!plus) f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
if (*mode == 'r') c->len = size;
else if (*mode == 'a') c->len = c->pos = strnlen(buf, size);
f->read = mread;
f->write = mwrite;
f->seek = mseek;
f->close = mclose;
if (!libc.threaded) f->lock = -1;
return __ofl_add(f);
}
#define _GNU_SOURCE
#include "stdio_impl.h"
#include <stdlib.h>
//include <sys/ioctl.h>
//include <fcntl.h>
#include <errno.h>
#include <string.h>
struct fcookie {
void *cookie;
cookie_io_functions_t iofuncs;
};
struct cookie_FILE {
FILE f;
struct fcookie fc;
unsigned char buf[UNGET+BUFSIZ];
};
static size_t cookieread(FILE *f, unsigned char *buf, size_t len)
{
struct fcookie *fc = f->cookie;
ssize_t ret = -1;
size_t remain = len, readlen = 0;
size_t len2 = len - !!f->buf_size;
if (!fc->iofuncs.read) goto bail;
if (len2) {
ret = fc->iofuncs.read(fc->cookie, (char *) buf, len2);
if (ret <= 0) goto bail;
readlen += ret;
remain -= ret;
}
if (!f->buf_size || remain > !!f->buf_size) return readlen;
f->rpos = f->buf;
ret = fc->iofuncs.read(fc->cookie, (char *) f->rpos, f->buf_size);
if (ret <= 0) goto bail;
f->rend = f->rpos + ret;
buf[readlen++] = *f->rpos++;
return readlen;
bail:
f->flags |= ret == 0 ? F_EOF : F_ERR;
f->rpos = f->rend = f->buf;
return readlen;
}
static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len)
{
struct fcookie *fc = f->cookie;
ssize_t ret;
size_t len2 = f->wpos - f->wbase;
if (!fc->iofuncs.write) return len;
if (len2) {
f->wpos = f->wbase;
if (cookiewrite(f, f->wpos, len2) < len2) return 0;
}
ret = fc->iofuncs.write(fc->cookie, (const char *) buf, len);
if (ret < 0) {
f->wpos = f->wbase = f->wend = 0;
f->flags |= F_ERR;
return 0;
}
return ret;
}
static off_t cookieseek(FILE *f, off_t off, int whence)
{
struct fcookie *fc = f->cookie;
int res;
if (whence > 2U) {
errno = EINVAL;
return -1;
}
if (!fc->iofuncs.seek) {
errno = ENOTSUP;
return -1;
}
res = fc->iofuncs.seek(fc->cookie, &off, whence);
if (res < 0)
return res;
return off;
}
static int cookieclose(FILE *f)
{
struct fcookie *fc = f->cookie;
if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie);
return 0;
}
FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs)
{
struct cookie_FILE *f;
/* Check for valid initial mode character */
if (!strchr("rwa", *mode)) {
errno = EINVAL;
return 0;
}
/* Allocate FILE+fcookie+buffer or fail */
if (!(f=malloc(sizeof *f))) return 0;
/* Zero-fill only the struct, not the buffer */
memset(&f->f, 0, sizeof f->f);
/* Impose mode restrictions */
if (!strchr(mode, '+')) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD;
/* Set up our fcookie */
f->fc.cookie = cookie;
f->fc.iofuncs.read = iofuncs.read;
f->fc.iofuncs.write = iofuncs.write;
f->fc.iofuncs.seek = iofuncs.seek;
f->fc.iofuncs.close = iofuncs.close;
f->f.fd = -1;
f->f.cookie = &f->fc;
f->f.buf = f->buf + UNGET;
f->f.buf_size = BUFSIZ;
f->f.lbf = EOF;
/* Initialize op ptrs. No problem if some are unneeded. */
f->f.read = cookieread;
f->f.write = cookiewrite;
f->f.seek = cookieseek;
f->f.close = cookieclose;
/* Add new FILE to open file list */
return __ofl_add(&f->f);
}
#include <stdio.h>
#include <stdarg.h>
int fprintf(FILE *restrict f, const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf(f, fmt, ap);
va_end(ap);
return ret;
}
#include "stdio_impl.h"
int fputc(int c, FILE *f)
{
if (f->lock < 0 || !__lockfile(f))
return putc_unlocked(c, f);
c = putc_unlocked(c, f);
__unlockfile(f);
return c;
}
#include "stdio_impl.h"
#include <string.h>
int fputs(const char *restrict s, FILE *restrict f)
{
size_t l = strlen(s);
return (fwrite(s, 1, l, f)==l) - 1;
}
weak_alias(fputs, fputs_unlocked);
#include "stdio_impl.h"
#include "locale_impl.h"
#include <wchar.h>
#include <limits.h>
#include <ctype.h>
wint_t __fputwc_unlocked(wchar_t c, FILE *f)
{
char mbc[MB_LEN_MAX];
int l;
locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
if (f->mode <= 0) fwide(f, 1);
*ploc = f->locale;
if (isascii(c)) {
c = putc_unlocked(c, f);
} else if (f->wpos + MB_LEN_MAX < f->wend) {
l = wctomb((void *)f->wpos, c);
if (l < 0) c = WEOF;
else f->wpos += l;
} else {
l = wctomb(mbc, c);
if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF;
}
if (c==WEOF) f->flags |= F_ERR;
*ploc = loc;
return c;
}
wint_t fputwc(wchar_t c, FILE *f)
{
FLOCK(f);
c = __fputwc_unlocked(c, f);
FUNLOCK(f);
return c;
}
weak_alias(__fputwc_unlocked, fputwc_unlocked);
weak_alias(__fputwc_unlocked, putwc_unlocked);
#include "stdio_impl.h"
#include "locale_impl.h"
#include <wchar.h>
int fputws(const wchar_t *restrict ws, FILE *restrict f)
{
unsigned char buf[BUFSIZ];
size_t l=0;
locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
FLOCK(f);
fwide(f, 1);
*ploc = f->locale;
while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1)
if (__fwritex(buf, l, f) < l) {
FUNLOCK(f);
*ploc = loc;
return -1;
}
FUNLOCK(f);
*ploc = loc;
return l; /* 0 or -1 */
}
weak_alias(fputws, fputws_unlocked);
#include "stdio_impl.h"
#include <string.h>
#define MIN(a,b) ((a)<(b) ? (a) : (b))
size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f)
{
unsigned char *dest = destv;
size_t len = size*nmemb, l = len, k;
if (!size) nmemb = 0;
FLOCK(f);
f->mode |= f->mode-1;
if (f->rend - f->rpos > 0) {
/* First exhaust the buffer. */
k = MIN(f->rend - f->rpos, l);
memcpy(dest, f->rpos, k);
f->rpos += k;
dest += k;
l -= k;
}
/* Read the remainder directly */
for (; l; l-=k, dest+=k) {
k = __toread(f) ? 0 : f->read(f, dest, l);
if (k+1<=1) {
FUNLOCK(f);
return (len-l)/size;
}
}
FUNLOCK(f);
return nmemb;
}
weak_alias(fread, fread_unlocked);
#include <stdio.h>
#include <stdarg.h>
#include "libc.h"
int fscanf(FILE *restrict f, const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfscanf(f, fmt, ap);
va_end(ap);
return ret;
}
weak_alias(fscanf, __isoc99_fscanf);
#include "stdio_impl.h"
int __fseeko_unlocked(FILE *f, off_t off, int whence)
{
/* Adjust relative offset for unread data in buffer, if any. */
if (whence == SEEK_CUR) off -= f->rend - f->rpos;
/* Flush write buffer, and report error on failure. */
if (f->wpos > f->wbase) {
f->write(f, 0, 0);
if (!f->wpos) return -1;
}
/* Leave writing mode */
f->wpos = f->wbase = f->wend = 0;
/* Perform the underlying seek. */
if (f->seek(f, off, whence) < 0) return -1;
/* If seek succeeded, file is seekable and we discard read buffer. */
f->rpos = f->rend = 0;
f->flags &= ~F_EOF;
return 0;
}
int __fseeko(FILE *f, off_t off, int whence)
{
int result;
FLOCK(f);
result = __fseeko_unlocked(f, off, whence);
FUNLOCK(f);
return result;
}
int fseek(FILE *f, long off, int whence)
{
return __fseeko(f, off, whence);
}
weak_alias(__fseeko, fseeko);
LFS64(fseeko);
#include "stdio_impl.h"
int fsetpos(FILE *f, const fpos_t *pos)
{
return __fseeko(f, *(const off_t *)pos, SEEK_SET);
}
LFS64(fsetpos);
#include "stdio_impl.h"
#include <limits.h>
#include <errno.h>
off_t __ftello_unlocked(FILE *f)
{
off_t pos = f->seek(f, 0,
(f->flags & F_APP) && f->wpos > f->wbase
? SEEK_END : SEEK_CUR);
if (pos < 0) return pos;
/* Adjust for data in buffer. */
return pos - (f->rend - f->rpos) + (f->wpos - f->wbase);
}
off_t __ftello(FILE *f)
{
off_t pos;
FLOCK(f);
pos = __ftello_unlocked(f);
FUNLOCK(f);
return pos;
}
long ftell(FILE *f)
{
off_t pos = __ftello(f);
if (pos > LONG_MAX) {
errno = EOVERFLOW;
return -1;
}
return pos;
}
weak_alias(__ftello, ftello);
LFS64(ftello);
#include "stdio_impl.h"
#include "pthread_impl.h"
void __unlist_locked_file(FILE *);
void funlockfile(FILE *f)
{
if (f->lockcount == 1) {
__unlist_locked_file(f);
f->lockcount = 0;
__unlockfile(f);
} else {
f->lockcount--;
}
}
#include "stdio_impl.h"
#include "locale_impl.h"
int fwide(FILE *f, int mode)
{
FLOCK(f);
if (mode) {
if (!f->locale) f->locale = MB_CUR_MAX==1
? C_LOCALE : UTF8_LOCALE;
if (!f->mode) f->mode = mode>0 ? 1 : -1;
}
mode = f->mode;
FUNLOCK(f);
return mode;
}
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
int fwprintf(FILE *restrict f, const wchar_t *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfwprintf(f, fmt, ap);
va_end(ap);
return ret;
}
#include "stdio_impl.h"
#include <string.h>
size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f)
{
size_t i=0;
if (!f->wend && __towrite(f)) return 0;
if (l > f->wend - f->wpos) return f->write(f, s, l);
if (f->lbf >= 0) {
/* Match /^(.*\n|)/ */
for (i=l; i && s[i-1] != '\n'; i--);
if (i) {
size_t n = f->write(f, s, i);
if (n < i) return n;
s += i;
l -= i;
}
}
memcpy(f->wpos, s, l);
f->wpos += l;
return l+i;
}
size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f)
{
size_t k, l = size*nmemb;
if (!size) nmemb = 0;
FLOCK(f);
k = __fwritex(src, l, f);
FUNLOCK(f);
return k==l ? nmemb : k/size;
}
weak_alias(fwrite, fwrite_unlocked);
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
#include "libc.h"
int fwscanf(FILE *restrict f, const wchar_t *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfwscanf(f, fmt, ap);
va_end(ap);
return ret;
}
weak_alias(fwscanf,__isoc99_fwscanf);
#include "stdio_impl.h"
int getc(FILE *f)
{
int c;
if (f->lock < 0 || !__lockfile(f))
return getc_unlocked(f);
c = getc_unlocked(f);
__unlockfile(f);
return c;
}
weak_alias(getc, _IO_getc);
#include "stdio_impl.h"
int (getc_unlocked)(FILE *f)
{
return getc_unlocked(f);
}
weak_alias (getc_unlocked, fgetc_unlocked);
weak_alias (getc_unlocked, _IO_getc_unlocked);
#include <stdio.h>
int getchar(void)
{
return fgetc(stdin);
}
#include "stdio_impl.h"
int getchar_unlocked(void)
{
return getc_unlocked(stdin);
}
#include "stdio_impl.h"
#include <string.h>
#include <inttypes.h>
#include <errno.h>
#define MIN(a,b) ((a)<(b) ? (a) : (b))
ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restrict f)
{
char *tmp;
unsigned char *z;
size_t k;
size_t i=0;
int c;
FLOCK(f);
if (!n || !s) {
f->flags |= F_ERR;
FUNLOCK(f);
errno = EINVAL;
return -1;
}
if (!*s) *n=0;
for (;;) {
z = memchr(f->rpos, delim, f->rend - f->rpos);
k = z ? z - f->rpos + 1 : f->rend - f->rpos;
if (i+k+1 >= *n) {
if (k >= SIZE_MAX/2-i) goto oom;
size_t m = i+k+2;
if (!z && m < SIZE_MAX/4) m += m/2;
tmp = realloc(*s, m);
if (!tmp) {
m = i+k+2;
tmp = realloc(*s, m);
if (!tmp) goto oom;
}
*s = tmp;
*n = m;
}
memcpy(*s+i, f->rpos, k);
f->rpos += k;
i += k;
if (z) break;
if ((c = getc_unlocked(f)) == EOF) {
if (!i || !feof(f)) {
FUNLOCK(f);
return -1;
}
break;
}
if (((*s)[i++] = c) == delim) break;
}
(*s)[i] = 0;
FUNLOCK(f);
return i;
oom:
f->flags |= F_ERR;
FUNLOCK(f);
errno = ENOMEM;
return -1;
}
weak_alias(getdelim, __getdelim);
#include <stdio.h>
ssize_t getline(char **restrict s, size_t *restrict n, FILE *restrict f)
{
return getdelim(s, n, '\n', f);
}
#include "stdio_impl.h"
#include <limits.h>
#include <string.h>
char *gets(char *s)
{
char *ret = fgets(s, INT_MAX, stdin);
if (ret && s[strlen(s)-1] == '\n') s[strlen(s)-1] = 0;
return ret;
}
#define _GNU_SOURCE
#include <stdio.h>
int getw(FILE *f)
{
int x;
return fread(&x, sizeof x, 1, f) ? x : EOF;
}
#include "stdio_impl.h"
#include <wchar.h>
wint_t getwc(FILE *f)
{
return fgetwc(f);
}
#include "stdio_impl.h"
#include <wchar.h>
wint_t getwchar(void)
{
return fgetwc(stdin);
}
weak_alias(getwchar, getwchar_unlocked);
#include "stdio_impl.h"
#include "libc.h"
static FILE *ofl_head;
static volatile int ofl_lock[2];
FILE **__ofl_lock()
{
LOCK(ofl_lock);
return &ofl_head;
}
void __ofl_unlock()
{
UNLOCK(ofl_lock);
}
#include "stdio_impl.h"
FILE *__ofl_add(FILE *f)
{
FILE **head = __ofl_lock();
f->next = *head;
if (*head) (*head)->prev = f;
*head = f;
__ofl_unlock();
return f;
}
#include "stdio_impl.h"
#include <errno.h>
#include <limits.h>
#include <string.h>
struct cookie {
char **bufp;
size_t *sizep;
size_t pos;
char *buf;
size_t len;
size_t space;
};
static off_t ms_seek(FILE *f, off_t off, int whence)
{
ssize_t base;
struct cookie *c = f->cookie;
if (whence>2U) {
fail:
errno = EINVAL;
return -1;
}
base = (size_t [3]){0, c->pos, c->len}[whence];
if (off < -base || off > SSIZE_MAX-base) goto fail;
return c->pos = base+off;
}
static size_t ms_write(FILE *f, const unsigned char *buf, size_t len)
{
struct cookie *c = f->cookie;
size_t len2 = f->wpos - f->wbase;
char *newbuf;
if (len2) {
f->wpos = f->wbase;
if (ms_write(f, f->wbase, len2) < len2) return 0;
}
if (len + c->pos >= c->space) {
len2 = 2*c->space+1 | c->pos+len+1;
newbuf = realloc(c->buf, len2);
if (!newbuf) return 0;
*c->bufp = c->buf = newbuf;
memset(c->buf + c->space, 0, len2 - c->space);
c->space = len2;
}
memcpy(c->buf+c->pos, buf, len);
c->pos += len;
if (c->pos >= c->len) c->len = c->pos;
*c->sizep = c->pos;
return len;
}
static int ms_close(FILE *f)
{
return 0;
}
FILE *open_memstream(char **bufp, size_t *sizep)
{
FILE *f;
struct cookie *c;
char *buf;
if (!(f=malloc(sizeof *f + sizeof *c + BUFSIZ))) return 0;
if (!(buf=malloc(sizeof *buf))) {
free(f);
return 0;
}
memset(f, 0, sizeof *f + sizeof *c);
f->cookie = c = (void *)(f+1);
c->bufp = bufp;
c->sizep = sizep;
c->pos = c->len = c->space = *sizep = 0;
c->buf = *bufp = buf;
*buf = 0;
f->flags = F_NORD;
f->fd = -1;
f->buf = (void *)(c+1);
f->buf_size = BUFSIZ;
f->lbf = EOF;
f->write = ms_write;
f->seek = ms_seek;
f->close = ms_close;
if (!libc.threaded) f->lock = -1;
return __ofl_add(f);
}
#include "stdio_impl.h"
#include <wchar.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
struct cookie {
wchar_t **bufp;
size_t *sizep;
size_t pos;
wchar_t *buf;
size_t len;
size_t space;
mbstate_t mbs;
};
static off_t wms_seek(FILE *f, off_t off, int whence)
{
ssize_t base;
struct cookie *c = f->cookie;
if (whence>2U) {
fail:
errno = EINVAL;
return -1;
}
base = (size_t [3]){0, c->pos, c->len}[whence];
if (off < -base || off > SSIZE_MAX/4-base) goto fail;
memset(&c->mbs, 0, sizeof c->mbs);
return c->pos = base+off;
}
static size_t wms_write(FILE *f, const unsigned char *buf, size_t len)
{
struct cookie *c = f->cookie;
size_t len2;
wchar_t *newbuf;
if (len + c->pos >= c->space) {
len2 = 2*c->space+1 | c->pos+len+1;
if (len2 > SSIZE_MAX/4) return 0;
newbuf = realloc(c->buf, len2*4);
if (!newbuf) return 0;
*c->bufp = c->buf = newbuf;
memset(c->buf + c->space, 0, 4*(len2 - c->space));
c->space = len2;
}
len2 = mbsnrtowcs(c->buf+c->pos, (void *)&buf, len, c->space-c->pos, &c->mbs);
if (len2 == -1) return 0;
c->pos += len2;
if (c->pos >= c->len) c->len = c->pos;
*c->sizep = c->pos;
return len;
}
static int wms_close(FILE *f)
{
return 0;
}
FILE *open_wmemstream(wchar_t **bufp, size_t *sizep)
{
FILE *f;
struct cookie *c;
wchar_t *buf;
if (!(f=malloc(sizeof *f + sizeof *c))) return 0;
if (!(buf=malloc(sizeof *buf))) {
free(f);
return 0;
}
memset(f, 0, sizeof *f + sizeof *c);
f->cookie = c = (void *)(f+1);
c->bufp = bufp;
c->sizep = sizep;
c->pos = c->len = c->space = *sizep = 0;
c->buf = *bufp = buf;
*buf = 0;
f->flags = F_NORD;
f->fd = -1;
f->buf = (void *)(c+1);
f->buf_size = 0;
f->lbf = EOF;
f->write = wms_write;
f->seek = wms_seek;
f->close = wms_close;
if (!libc.threaded) f->lock = -1;
return __ofl_add(f);
}
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "stdio_impl.h"
void perror(const char *msg)
{
FILE *f = stderr;
char *errstr = strerror(errno);
FLOCK(f);
if (msg && *msg) {
fwrite(msg, strlen(msg), 1, f);
fputc(':', f);
fputc(' ', f);
}
fwrite(errstr, strlen(errstr), 1, f);
fputc('\n', f);
FUNLOCK(f);
}
#include <stdio.h>
#include <stdarg.h>
int printf(const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf(stdout, fmt, ap);
va_end(ap);
return ret;
}
#include "stdio_impl.h"
int putc(int c, FILE *f)
{
if (f->lock < 0 || !__lockfile(f))
return putc_unlocked(c, f);
c = putc_unlocked(c, f);
__unlockfile(f);
return c;
}
weak_alias(putc, _IO_putc);
#include "stdio_impl.h"
int (putc_unlocked)(int c, FILE *f)
{
return putc_unlocked(c, f);
}
weak_alias(putc_unlocked, fputc_unlocked);
weak_alias(putc_unlocked, _IO_putc_unlocked);
#include <stdio.h>
int putchar(int c)
{
return fputc(c, stdout);
}
#include "stdio_impl.h"
int putchar_unlocked(int c)
{
return putc_unlocked(c, stdout);
}
#include "stdio_impl.h"
int puts(const char *s)
{
int r;
FLOCK(stdout);
r = -(fputs(s, stdout) < 0 || putc_unlocked('\n', stdout) < 0);
FUNLOCK(stdout);
return r;
}
#define _GNU_SOURCE
#include <stdio.h>
int putw(int x, FILE *f)
{
return (int)fwrite(&x, sizeof x, 1, f)-1;
}
#include "stdio_impl.h"
#include <wchar.h>
wint_t putwc(wchar_t c, FILE *f)
{
return fputwc(c, f);
}
#include "stdio_impl.h"
#include <wchar.h>
wint_t putwchar(wchar_t c)
{
return fputwc(c, stdout);
}
weak_alias(putwchar, putwchar_unlocked);
#include "stdio_impl.h"
void rewind(FILE *f)
{
FLOCK(f);
__fseeko_unlocked(f, 0, SEEK_SET);
f->flags &= ~F_ERR;
FUNLOCK(f);
}
#include <stdio.h>
#include <stdarg.h>
#include "libc.h"
int scanf(const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vscanf(fmt, ap);
va_end(ap);
return ret;
}
weak_alias(scanf,__isoc99_scanf);
#include <stdio.h>
void setbuf(FILE *restrict f, char *restrict buf)
{
setvbuf(f, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
}
#define _GNU_SOURCE
#include <stdio.h>
void setbuffer(FILE *f, char *buf, size_t size)
{
setvbuf(f, buf, buf ? _IOFBF : _IONBF, size);
}
#define _GNU_SOURCE
#include <stdio.h>
void setlinebuf(FILE *f)
{
setvbuf(f, 0, _IOLBF, 0);
}
#include "stdio_impl.h"
/* This function makes no attempt to protect the user from his/her own
* stupidity. If called any time but when then ISO C standard specifically
* allows it, all hell can and will break loose, especially with threads!
*
* This implementation ignores all arguments except the buffering type,
* and uses the existing buffer allocated alongside the FILE object.
* In the case of stderr where the preexisting buffer is length 1, it
* is not possible to set line buffering or full buffering. */
int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size)
{
f->lbf = EOF;
if (type == _IONBF)
f->buf_size = 0;
else if (type == _IOLBF)
f->lbf = '\n';
f->flags |= F_SVB;
return 0;
}
#include <stdio.h>
#include <stdarg.h>
int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vsnprintf(s, n, fmt, ap);
va_end(ap);
return ret;
}
#include <stdio.h>
#include <stdarg.h>
int sprintf(char *restrict s, const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vsprintf(s, fmt, ap);
va_end(ap);
return ret;
}
#include <stdio.h>
#include <stdarg.h>
#include "libc.h"
int sscanf(const char *restrict s, const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vsscanf(s, fmt, ap);
va_end(ap);
return ret;
}
weak_alias(sscanf,__isoc99_sscanf);
#include "stdio_impl.h"
static unsigned char buf[UNGET];
static FILE f = {
.buf = buf+UNGET,
.buf_size = 0,
.fd = 2,
.flags = F_PERM | F_NORD,
.lbf = -1,
.write = __stdio_write,
.seek = __stdio_seek,
.close = __stdio_close,
.lock = -1,
};
FILE *const stderr = &f;
FILE *volatile __stderr_used = &f;
#include "stdio_impl.h"
static unsigned char buf[BUFSIZ+UNGET];
static FILE f = {
.buf = buf+UNGET,
.buf_size = sizeof buf-UNGET,
.fd = 0,
.flags = F_PERM | F_NOWR,
.read = __stdio_read,
.seek = __stdio_seek,
.close = __stdio_close,
.lock = -1,
};
FILE *const stdin = &f;
FILE *volatile __stdin_used = &f;
#include "stdio_impl.h"
static unsigned char buf[BUFSIZ+UNGET];
static FILE f = {
.buf = buf+UNGET,
.buf_size = sizeof buf-UNGET,
.fd = 1,
.flags = F_PERM | F_NORD,
.lbf = '\n',
.write = __stdout_write,
.seek = __stdio_seek,
.close = __stdio_close,
.lock = -1,
};
FILE *const stdout = &f;
FILE *volatile __stdout_used = &f;
#include <stdarg.h>
#include <wchar.h>
int swprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vswprintf(s, n, fmt, ap);
va_end(ap);
return ret;
}
#include <stdarg.h>
#include <wchar.h>
#include "libc.h"
int swscanf(const wchar_t *restrict s, const wchar_t *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vswscanf(s, fmt, ap);
va_end(ap);
return ret;
}
weak_alias(swscanf,__isoc99_swscanf);
#include "stdio_impl.h"
int ungetc(int c, FILE *f)
{
if (c == EOF) return c;
FLOCK(f);
if (!f->rpos) __toread(f);
if (!f->rpos || f->rpos <= f->buf - UNGET) {
FUNLOCK(f);
return EOF;
}
*--f->rpos = c;
f->flags &= ~F_EOF;
FUNLOCK(f);
return c;
}
#include "stdio_impl.h"
#include "locale_impl.h"
#include <wchar.h>
#include <limits.h>
#include <ctype.h>
#include <string.h>
wint_t ungetwc(wint_t c, FILE *f)
{
unsigned char mbc[MB_LEN_MAX];
int l;
locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
FLOCK(f);
if (f->mode <= 0) fwide(f, 1);
*ploc = f->locale;
if (!f->rpos) __toread(f);
if (!f->rpos || c == WEOF || (l = wcrtomb((void *)mbc, c, 0)) < 0 ||
f->rpos < f->buf - UNGET + l) {
FUNLOCK(f);
*ploc = loc;
return WEOF;
}
if (isascii(c)) *--f->rpos = c;
else memcpy(f->rpos -= l, mbc, l);
f->flags &= ~F_EOF;
FUNLOCK(f);
*ploc = loc;
return c;
}
#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
int vasprintf(char **s, const char *fmt, va_list ap)
{
va_list ap2;
va_copy(ap2, ap);
int l = vsnprintf(0, 0, fmt, ap2);
va_end(ap2);
if (l<0 || !(*s=malloc(l+1U))) return -1;
return vsnprintf(*s, l+1U, fmt, ap);
}
#include "stdio_impl.h"
static size_t wrap_write(FILE *f, const unsigned char *buf, size_t len)
{
return __stdio_write(f, buf, len);
}
int vdprintf(int fd, const char *restrict fmt, va_list ap)
{
FILE f = {
.fd = fd, .lbf = EOF, .write = wrap_write,
.buf = (void *)fmt, .buf_size = 0,
.lock = -1
};
return vfprintf(&f, fmt, ap);
}
#include "stdio_impl.h"
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdarg.h>
#include <stddef.h>
#include <wchar.h>
#include <inttypes.h>
#include <math.h>
#include <float.h>
/* Some useful macros */
#define MAX(a,b) ((a)>(b) ? (a) : (b))
#define MIN(a,b) ((a)<(b) ? (a) : (b))
/* Convenient bit representation for modifier flags, which all fall
* within 31 codepoints of the space character. */
#define ALT_FORM (1U<<'#'-' ')
#define ZERO_PAD (1U<<'0'-' ')
#define LEFT_ADJ (1U<<'-'-' ')
#define PAD_POS (1U<<' '-' ')
#define MARK_POS (1U<<'+'-' ')
#define GROUPED (1U<<'\''-' ')
#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
/* State machine to accept length modifiers + conversion specifiers.
* Result is 0 on failure, or an argument type to pop on success. */
enum {
BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
ZTPRE, JPRE,
STOP,
PTR, INT, UINT, ULLONG,
LONG, ULONG,
SHORT, USHORT, CHAR, UCHAR,
LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
DBL, LDBL,
NOARG,
MAXSTATE
};
#define S(x) [(x)-'A']
static const unsigned char states[]['z'-'A'+1] = {
{ /* 0: bare types */
S('d') = INT, S('i') = INT,
S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
S('c') = CHAR, S('C') = INT,
S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
S('m') = NOARG,
S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
}, { /* 1: l-prefixed */
S('d') = LONG, S('i') = LONG,
S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
S('c') = INT, S('s') = PTR, S('n') = PTR,
S('l') = LLPRE,
}, { /* 2: ll-prefixed */
S('d') = LLONG, S('i') = LLONG,
S('o') = ULLONG, S('u') = ULLONG,
S('x') = ULLONG, S('X') = ULLONG,
S('n') = PTR,
}, { /* 3: h-prefixed */
S('d') = SHORT, S('i') = SHORT,
S('o') = USHORT, S('u') = USHORT,
S('x') = USHORT, S('X') = USHORT,
S('n') = PTR,
S('h') = HHPRE,
}, { /* 4: hh-prefixed */
S('d') = CHAR, S('i') = CHAR,
S('o') = UCHAR, S('u') = UCHAR,
S('x') = UCHAR, S('X') = UCHAR,
S('n') = PTR,
}, { /* 5: L-prefixed */
S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
S('n') = PTR,
}, { /* 6: z- or t-prefixed (assumed to be same size) */
S('d') = PDIFF, S('i') = PDIFF,
S('o') = SIZET, S('u') = SIZET,
S('x') = SIZET, S('X') = SIZET,
S('n') = PTR,
}, { /* 7: j-prefixed */
S('d') = IMAX, S('i') = IMAX,
S('o') = UMAX, S('u') = UMAX,
S('x') = UMAX, S('X') = UMAX,
S('n') = PTR,
}
};
#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
union arg
{
uintmax_t i;
long double f;
void *p;
};
static void pop_arg(union arg *arg, int type, va_list *ap)
{
switch (type) {
case PTR: arg->p = va_arg(*ap, void *);
break; case INT: arg->i = va_arg(*ap, int);
break; case UINT: arg->i = va_arg(*ap, unsigned int);
break; case LONG: arg->i = va_arg(*ap, long);
break; case ULONG: arg->i = va_arg(*ap, unsigned long);
break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
break; case SHORT: arg->i = (short)va_arg(*ap, int);
break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int);
break; case CHAR: arg->i = (signed char)va_arg(*ap, int);
break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int);
break; case LLONG: arg->i = va_arg(*ap, long long);
break; case SIZET: arg->i = va_arg(*ap, size_t);
break; case IMAX: arg->i = va_arg(*ap, intmax_t);
break; case UMAX: arg->i = va_arg(*ap, uintmax_t);
break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t);
break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *);
break; case DBL: arg->f = va_arg(*ap, double);
break; case LDBL: arg->f = va_arg(*ap, long double);
}
}
static void out(FILE *f, const char *s, size_t l)
{
if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f);
}
static void pad(FILE *f, char c, int w, int l, int fl)
{
char pad[256];
if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return;
l = w - l;
memset(pad, c, l>sizeof pad ? sizeof pad : l);
for (; l >= sizeof pad; l -= sizeof pad)
out(f, pad, sizeof pad);
out(f, pad, l);
}
static const char xdigits[16] = {
"0123456789ABCDEF"
};
static char *fmt_x(uintmax_t x, char *s, int lower)
{
for (; x; x>>=4) *--s = xdigits[(x&15)]|lower;
return s;
}
static char *fmt_o(uintmax_t x, char *s)
{
for (; x; x>>=3) *--s = '0' + (x&7);
return s;
}
static char *fmt_u(uintmax_t x, char *s)
{
unsigned long y;
for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
for (y=x; y; y/=10) *--s = '0' + y%10;
return s;
}
/* Do not override this check. The floating point printing code below
* depends on the float.h constants being right. If they are wrong, it
* may overflow the stack. */
#if LDBL_MANT_DIG == 53
typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
#endif
static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
{
uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
+ (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
uint32_t *a, *d, *r, *z;
int e2=0, e, i, j, l;
char buf[9+LDBL_MANT_DIG/4], *s;
const char *prefix="-0X+0X 0X-0x+0x 0x";
int pl;
char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr;
pl=1;
if (signbit(y)) {
y=-y;
} else if (fl & MARK_POS) {
prefix+=3;
} else if (fl & PAD_POS) {
prefix+=6;
} else prefix++, pl=0;
if (!isfinite(y)) {
char *s = (t&32)?"inf":"INF";
if (y!=y) s=(t&32)?"nan":"NAN";
pad(f, ' ', w, 3+pl, fl&~ZERO_PAD);
out(f, prefix, pl);
out(f, s, 3);
pad(f, ' ', w, 3+pl, fl^LEFT_ADJ);
return MAX(w, 3+pl);
}
y = frexpl(y, &e2) * 2;
if (y) e2--;
if ((t|32)=='a') {
long double round = 8.0;
int re;
if (t&32) prefix += 9;
pl += 2;
if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
else re=LDBL_MANT_DIG/4-1-p;
if (re) {
while (re--) round*=16;
if (*prefix=='-') {
y=-y;
y-=round;
y+=round;
y=-y;
} else {
y+=round;
y-=round;
}
}
estr=fmt_u(e2<0 ? -e2 : e2, ebuf);
if (estr==ebuf) *--estr='0';
*--estr = (e2<0 ? '-' : '+');
*--estr = t+('p'-'a');
s=buf;
do {
int x=y;
*s++=xdigits[x]|(t&32);
y=16*(y-x);
if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
} while (y);
if (p > INT_MAX-2-(ebuf-estr)-pl)
return -1;
if (p && s-buf-2 < p)
l = (p+2) + (ebuf-estr);
else
l = (s-buf) + (ebuf-estr);
pad(f, ' ', w, pl+l, fl);
out(f, prefix, pl);
pad(f, '0', w, pl+l, fl^ZERO_PAD);
out(f, buf, s-buf);
pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0);
out(f, estr, ebuf-estr);
pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
return MAX(w, pl+l);
}
if (p<0) p=6;
if (y) y *= 0x1p28, e2-=28;
if (e2<0) a=r=z=big;
else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1;
do {
*z = y;
y = 1000000000*(y-*z++);
} while (y);
while (e2>0) {
uint32_t carry=0;
int sh=MIN(29,e2);
for (d=z-1; d>=a; d--) {
uint64_t x = ((uint64_t)*d<<sh)+carry;
*d = x % 1000000000;
carry = x / 1000000000;
}
if (carry) *--a = carry;
while (z>a && !z[-1]) z--;
e2-=sh;
}
while (e2<0) {
uint32_t carry=0, *b;
int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3U+8)/9;
for (d=a; d<z; d++) {
uint32_t rm = *d & (1<<sh)-1;
*d = (*d>>sh) + carry;
carry = (1000000000>>sh) * rm;
}
if (!*a) a++;
if (carry) *z++ = carry;
/* Avoid (slow!) computation past requested precision */
b = (t|32)=='f' ? r : a;
if (z-b > need) z = b+need;
e2+=sh;
}
if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
else e=0;
/* Perform rounding: j is precision after the radix (possibly neg) */
j = p - ((t|32)!='f')*e - ((t|32)=='g' && p);
if (j < 9*(z-r-1)) {
uint32_t x;
/* We avoid C's broken division of negative numbers */
d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP);
j += 9*LDBL_MAX_EXP;
j %= 9;
for (i=10, j++; j<9; i*=10, j++);
x = *d % i;
/* Are there any significant digits past j? */
if (x || d+1!=z) {
long double round = 2/LDBL_EPSILON;
long double small;
if ((*d/i & 1) || (i==1000000000 && d>a && (d[-1]&1)))
round += 2;
if (x<i/2) small=0x0.8p0;
else if (x==i/2 && d+1==z) small=0x1.0p0;
else small=0x1.8p0;
if (pl && *prefix=='-') round*=-1, small*=-1;
*d -= x;
/* Decide whether to round by probing round+small */
if (round+small != round) {
*d = *d + i;
while (*d > 999999999) {
*d--=0;
if (d<a) *--a=0;
(*d)++;
}
for (i=10, e=9*(r-a); *a>=i; i*=10, e++);
}
}
if (z>d+1) z=d+1;
}
for (; z>a && !z[-1]; z--);
if ((t|32)=='g') {
if (!p) p++;
if (p>e && e>=-4) {
t--;
p-=e+1;
} else {
t-=2;
p--;
}
if (!(fl&ALT_FORM)) {
/* Count trailing zeros in last place */
if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++);
else j=9;
if ((t|32)=='f')
p = MIN(p,MAX(0,9*(z-r-1)-j));
else
p = MIN(p,MAX(0,9*(z-r-1)+e-j));
}
}
if (p > INT_MAX-1-(p || (fl&ALT_FORM)))
return -1;
l = 1 + p + (p || (fl&ALT_FORM));
if ((t|32)=='f') {
if (e > INT_MAX-l) return -1;
if (e>0) l+=e;
} else {
estr=fmt_u(e<0 ? -e : e, ebuf);
while(ebuf-estr<2) *--estr='0';
*--estr = (e<0 ? '-' : '+');
*--estr = t;
if (ebuf-estr > INT_MAX-l) return -1;
l += ebuf-estr;
}
if (l > INT_MAX-pl) return -1;
pad(f, ' ', w, pl+l, fl);
out(f, prefix, pl);
pad(f, '0', w, pl+l, fl^ZERO_PAD);
if ((t|32)=='f') {
if (a>r) a=r;
for (d=a; d<=r; d++) {
char *s = fmt_u(*d, buf+9);
if (d!=a) while (s>buf) *--s='0';
else if (s==buf+9) *--s='0';
out(f, s, buf+9-s);
}
if (p || (fl&ALT_FORM)) out(f, ".", 1);
for (; d<z && p>0; d++, p-=9) {
char *s = fmt_u(*d, buf+9);
while (s>buf) *--s='0';
out(f, s, MIN(9,p));
}
pad(f, '0', p+9, 9, 0);
} else {
if (z<=a) z=a+1;
for (d=a; d<z && p>=0; d++) {
char *s = fmt_u(*d, buf+9);
if (s==buf+9) *--s='0';
if (d!=a) while (s>buf) *--s='0';
else {
out(f, s++, 1);
if (p>0||(fl&ALT_FORM)) out(f, ".", 1);
}
out(f, s, MIN(buf+9-s, p));
p -= buf+9-s;
}
pad(f, '0', p+18, 18, 0);
out(f, estr, ebuf-estr);
}
pad(f, ' ', w, pl+l, fl^LEFT_ADJ);
return MAX(w, pl+l);
}
static int getint(char **s) {
int i;
for (i=0; isdigit(**s); (*s)++) {
if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1;
else i = 10*i + (**s-'0');
}
return i;
}
static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
{
char *a, *z, *s=(char *)fmt;
unsigned l10n=0, fl;
int w, p, xp;
union arg arg;
int argpos;
unsigned st, ps;
int cnt=0, l=0;
size_t i;
char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
const char *prefix;
int t, pl;
wchar_t wc[2], *ws;
char mb[4];
for (;;) {
/* This error is only specified for snprintf, but since it's
* unspecified for other forms, do the same. Stop immediately
* on overflow; otherwise %n could produce wrong results. */
if (l > INT_MAX - cnt) goto overflow;
/* Update output count, end loop when fmt is exhausted */
cnt += l;
if (!*s) break;
/* Handle literal text and %% format specifiers */
for (a=s; *s && *s!='%'; s++);
for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
if (z-a > INT_MAX-cnt) goto overflow;
l = z-a;
if (f) out(f, a, l);
if (l) continue;
if (isdigit(s[1]) && s[2]=='$') {
l10n=1;
argpos = s[1]-'0';
s+=3;
} else {
argpos = -1;
s++;
}
/* Read modifier flags */
for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
fl |= 1U<<*s-' ';
/* Read field width */
if (*s=='*') {
if (isdigit(s[1]) && s[2]=='$') {
l10n=1;
nl_type[s[1]-'0'] = INT;
w = nl_arg[s[1]-'0'].i;
s+=3;
} else if (!l10n) {
w = f ? va_arg(*ap, int) : 0;
s++;
} else goto inval;
if (w<0) fl|=LEFT_ADJ, w=-w;
} else if ((w=getint(&s))<0) goto overflow;
/* Read precision */
if (*s=='.' && s[1]=='*') {
if (isdigit(s[2]) && s[3]=='$') {
nl_type[s[2]-'0'] = INT;
p = nl_arg[s[2]-'0'].i;
s+=4;
} else if (!l10n) {
p = f ? va_arg(*ap, int) : 0;
s+=2;
} else goto inval;
xp = (p>=0);
} else if (*s=='.') {
s++;
p = getint(&s);
xp = 1;
} else {
p = -1;
xp = 0;
}
/* Format specifier state machine */
st=0;
do {
if (OOB(*s)) goto inval;
ps=st;
st=states[st]S(*s++);
} while (st-1<STOP);
if (!st) goto inval;
/* Check validity of argument type (nl/normal) */
if (st==NOARG) {
if (argpos>=0) goto inval;
} else {
if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
else if (f) pop_arg(&arg, st, ap);
else return 0;
}
if (!f) continue;
z = buf + sizeof(buf);
prefix = "-+ 0X0x";
pl = 0;
t = s[-1];
/* Transform ls,lc -> S,C */
if (ps && (t&15)==3) t&=~32;
/* - and 0 flags are mutually exclusive */
if (fl & LEFT_ADJ) fl &= ~ZERO_PAD;
switch(t) {
case 'n':
switch(ps) {
case BARE: *(int *)arg.p = cnt; break;
case LPRE: *(long *)arg.p = cnt; break;
case LLPRE: *(long long *)arg.p = cnt; break;
case HPRE: *(unsigned short *)arg.p = cnt; break;
case HHPRE: *(unsigned char *)arg.p = cnt; break;
case ZTPRE: *(size_t *)arg.p = cnt; break;
case JPRE: *(uintmax_t *)arg.p = cnt; break;
}
continue;
case 'p':
p = MAX(p, 2*sizeof(void*));
t = 'x';
fl |= ALT_FORM;
case 'x': case 'X':
a = fmt_x(arg.i, z, t&32);
if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2;
if (0) {
case 'o':
a = fmt_o(arg.i, z);
if ((fl&ALT_FORM) && p<z-a+1) prefix+=5, pl=1;
} if (0) {
case 'd': case 'i':
pl=1;
if (arg.i>INTMAX_MAX) {
arg.i=-arg.i;
} else if (fl & MARK_POS) {
prefix++;
} else if (fl & PAD_POS) {
prefix+=2;
} else pl=0;
case 'u':
a = fmt_u(arg.i, z);
}
if (xp && p<0) goto overflow;
if (p>=0) fl &= ~ZERO_PAD;
if (!arg.i && !p) {
a=z;
break;
}
p = MAX(p, z-a + !arg.i);
break;
case 'c':
*(a=z-(p=1))=arg.i;
fl &= ~ZERO_PAD;
break;
case 'm':
if (1) a = strerror(errno); else
case 's':
a = arg.p ? arg.p : "(null)";
z = a + strnlen(a, p<0 ? INT_MAX : p);
if (p<0 && *z) goto overflow;
p = z-a;
fl &= ~ZERO_PAD;
break;
case 'C':
wc[0] = arg.i;
wc[1] = 0;
arg.p = wc;
p = -1;
case 'S':
ws = arg.p;
for (i=l=0; i<p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=p-i; i+=l);
if (l<0) return -1;
if (i > INT_MAX) goto overflow;
p = i;
pad(f, ' ', w, p, fl);
ws = arg.p;
for (i=0; i<0U+p && *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l)
out(f, mb, l);
pad(f, ' ', w, p, fl^LEFT_ADJ);
l = w>p ? w : p;
continue;
case 'e': case 'f': case 'g': case 'a':
case 'E': case 'F': case 'G': case 'A':
if (xp && p<0) goto overflow;
l = fmt_fp(f, arg.f, w, p, fl, t);
if (l<0) goto overflow;
continue;
}
if (p < z-a) p = z-a;
if (p > INT_MAX-pl) goto overflow;
if (w < pl+p) w = pl+p;
if (w > INT_MAX-cnt) goto overflow;
pad(f, ' ', w, pl+p, fl);
out(f, prefix, pl);
pad(f, '0', w, pl+p, fl^ZERO_PAD);
pad(f, '0', p, z-a, 0);
out(f, a, z-a);
pad(f, ' ', w, pl+p, fl^LEFT_ADJ);
l = w;
}
if (f) return cnt;
if (!l10n) return 0;
for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
pop_arg(nl_arg+i, nl_type[i], ap);
for (; i<=NL_ARGMAX && !nl_type[i]; i++);
if (i<=NL_ARGMAX) goto inval;
return 1;
inval:
errno = EINVAL;
return -1;
overflow:
errno = EOVERFLOW;
return -1;
}
int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
{
va_list ap2;
int nl_type[NL_ARGMAX+1] = {0};
union arg nl_arg[NL_ARGMAX+1];
unsigned char internal_buf[80], *saved_buf = 0;
int olderr;
int ret;
/* the copy allows passing va_list* even if va_list is an array */
va_copy(ap2, ap);
if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
va_end(ap2);
return -1;
}
FLOCK(f);
olderr = f->flags & F_ERR;
if (f->mode < 1) f->flags &= ~F_ERR;
if (!f->buf_size) {
saved_buf = f->buf;
f->wpos = f->wbase = f->buf = internal_buf;
f->buf_size = sizeof internal_buf;
f->wend = internal_buf + sizeof internal_buf;
}
ret = printf_core(f, fmt, &ap2, nl_arg, nl_type);
if (saved_buf) {
f->write(f, 0, 0);
if (!f->wpos) ret = -1;
f->buf = saved_buf;
f->buf_size = 0;
f->wpos = f->wbase = f->wend = 0;
}
if (f->flags & F_ERR) ret = -1;
f->flags |= olderr;
FUNLOCK(f);
va_end(ap2);
return ret;
}
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <wchar.h>
#include <wctype.h>
#include <limits.h>
#include <string.h>
#include <stdint.h>
#include "stdio_impl.h"
#include "shgetc.h"
#include "intscan.h"
#include "floatscan.h"
#define SIZE_hh -2
#define SIZE_h -1
#define SIZE_def 0
#define SIZE_l 1
#define SIZE_L 2
#define SIZE_ll 3
static void store_int(void *dest, int size, unsigned long long i)
{
if (!dest) return;
switch (size) {
case SIZE_hh:
*(char *)dest = i;
break;
case SIZE_h:
*(short *)dest = i;
break;
case SIZE_def:
*(int *)dest = i;
break;
case SIZE_l:
*(long *)dest = i;
break;
case SIZE_ll:
*(long long *)dest = i;
break;
}
}
static void *arg_n(va_list ap, unsigned int n)
{
void *p;
unsigned int i;
va_list ap2;
va_copy(ap2, ap);
for (i=n; i>1; i--) va_arg(ap2, void *);
p = va_arg(ap2, void *);
va_end(ap2);
return p;
}
int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
{
int width;
int size;
int alloc;
int base;
const unsigned char *p;
int c, t;
char *s;
wchar_t *wcs;
mbstate_t st;
void *dest=NULL;
int invert;
int matches=0;
unsigned long long x;
long double y;
off_t pos = 0;
unsigned char scanset[257];
size_t i, k;
wchar_t wc;
FLOCK(f);
for (p=(const unsigned char *)fmt; *p; p++) {
alloc = 0;
if (isspace(*p)) {
while (isspace(p[1])) p++;
shlim(f, 0);
while (isspace(shgetc(f)));
shunget(f);
pos += shcnt(f);
continue;
}
if (*p != '%' || p[1] == '%') {
shlim(f, 0);
if (*p == '%') {
p++;
while (isspace((c=shgetc(f))));
} else {
c = shgetc(f);
}
if (c!=*p) {
shunget(f);
if (c<0) goto input_fail;
goto match_fail;
}
pos += shcnt(f);
continue;
}
p++;
if (*p=='*') {
dest = 0; p++;
} else if (isdigit(*p) && p[1]=='$') {
dest = arg_n(ap, *p-'0'); p+=2;
} else {
dest = va_arg(ap, void *);
}
for (width=0; isdigit(*p); p++) {
width = 10*width + *p - '0';
}
if (*p=='m') {
wcs = 0;
s = 0;
alloc = !!dest;
p++;
} else {
alloc = 0;
}
size = SIZE_def;
switch (*p++) {
case 'h':
if (*p == 'h') p++, size = SIZE_hh;
else size = SIZE_h;
break;
case 'l':
if (*p == 'l') p++, size = SIZE_ll;
else size = SIZE_l;
break;
case 'j':
size = SIZE_ll;
break;
case 'z':
case 't':
size = SIZE_l;
break;
case 'L':
size = SIZE_L;
break;
case 'd': case 'i': case 'o': case 'u': case 'x':
case 'a': case 'e': case 'f': case 'g':
case 'A': case 'E': case 'F': case 'G': case 'X':
case 's': case 'c': case '[':
case 'S': case 'C':
case 'p': case 'n':
p--;
break;
default:
goto fmt_fail;
}
t = *p;
/* C or S */
if ((t&0x2f) == 3) {
t |= 32;
size = SIZE_l;
}
switch (t) {
case 'c':
if (width < 1) width = 1;
case '[':
break;
case 'n':
store_int(dest, size, pos);
/* do not increment match count, etc! */
continue;
default:
shlim(f, 0);
while (isspace(shgetc(f)));
shunget(f);
pos += shcnt(f);
}
shlim(f, width);
if (shgetc(f) < 0) goto input_fail;
shunget(f);
switch (t) {
case 's':
case 'c':
case '[':
if (t == 'c' || t == 's') {
memset(scanset, -1, sizeof scanset);
scanset[0] = 0;
if (t == 's') {
scanset[1+'\t'] = 0;
scanset[1+'\n'] = 0;
scanset[1+'\v'] = 0;
scanset[1+'\f'] = 0;
scanset[1+'\r'] = 0;
scanset[1+' '] = 0;
}
} else {
if (*++p == '^') p++, invert = 1;
else invert = 0;
memset(scanset, invert, sizeof scanset);
scanset[0] = 0;
if (*p == '-') p++, scanset[1+'-'] = 1-invert;
else if (*p == ']') p++, scanset[1+']'] = 1-invert;
for (; *p != ']'; p++) {
if (!*p) goto fmt_fail;
if (*p=='-' && p[1] && p[1] != ']')
for (c=p++[-1]; c<*p; c++)
scanset[1+c] = 1-invert;
scanset[1+*p] = 1-invert;
}
}
wcs = 0;
s = 0;
i = 0;
k = t=='c' ? width+1U : 31;
if (size == SIZE_l) {
if (alloc) {
wcs = malloc(k*sizeof(wchar_t));
if (!wcs) goto alloc_fail;
} else {
wcs = dest;
}
st = (mbstate_t){0};
while (scanset[(c=shgetc(f))+1]) {
switch (mbrtowc(&wc, &(char){c}, 1, &st)) {
case -1:
goto input_fail;
case -2:
continue;
}
if (wcs) wcs[i++] = wc;
if (alloc && i==k) {
k+=k+1;
wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t));
if (!tmp) goto alloc_fail;
wcs = tmp;
}
}
if (!mbsinit(&st)) goto input_fail;
} else if (alloc) {
s = malloc(k);
if (!s) goto alloc_fail;
while (scanset[(c=shgetc(f))+1]) {
s[i++] = c;
if (i==k) {
k+=k+1;
char *tmp = realloc(s, k);
if (!tmp) goto alloc_fail;
s = tmp;
}
}
} else if ((s = dest)) {
while (scanset[(c=shgetc(f))+1])
s[i++] = c;
} else {
while (scanset[(c=shgetc(f))+1]);
}
shunget(f);
if (!shcnt(f)) goto match_fail;
if (t == 'c' && shcnt(f) != width) goto match_fail;
if (alloc) {
if (size == SIZE_l) *(wchar_t **)dest = wcs;
else *(char **)dest = s;
}
if (t != 'c') {
if (wcs) wcs[i] = 0;
if (s) s[i] = 0;
}
break;
case 'p':
case 'X':
case 'x':
base = 16;
goto int_common;
case 'o':
base = 8;
goto int_common;
case 'd':
case 'u':
base = 10;
goto int_common;
case 'i':
base = 0;
int_common:
x = __intscan(f, base, 0, ULLONG_MAX);
if (!shcnt(f)) goto match_fail;
if (t=='p' && dest) *(void **)dest = (void *)(uintptr_t)x;
else store_int(dest, size, x);
break;
case 'a': case 'A':
case 'e': case 'E':
case 'f': case 'F':
case 'g': case 'G':
y = __floatscan(f, size, 0);
if (!shcnt(f)) goto match_fail;
if (dest) switch (size) {
case SIZE_def:
*(float *)dest = y;
break;
case SIZE_l:
*(double *)dest = y;
break;
case SIZE_L:
*(long double *)dest = y;
break;
}
break;
}
pos += shcnt(f);
if (dest) matches++;
}
if (0) {
fmt_fail:
alloc_fail:
input_fail:
if (!matches) matches--;
match_fail:
if (alloc) {
free(s);
free(wcs);
}
}
FUNLOCK(f);
return matches;
}
weak_alias(vfscanf,__isoc99_vfscanf);
#include "stdio_impl.h"
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdarg.h>
#include <stddef.h>
#include <wchar.h>
#include <inttypes.h>
/* Convenient bit representation for modifier flags, which all fall
* within 31 codepoints of the space character. */
#define ALT_FORM (1U<<'#'-' ')
#define ZERO_PAD (1U<<'0'-' ')
#define LEFT_ADJ (1U<<'-'-' ')
#define PAD_POS (1U<<' '-' ')
#define MARK_POS (1U<<'+'-' ')
#define GROUPED (1U<<'\''-' ')
#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
/* State machine to accept length modifiers + conversion specifiers.
* Result is 0 on failure, or an argument type to pop on success. */
enum {
BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
ZTPRE, JPRE,
STOP,
PTR, INT, UINT, ULLONG,
LONG, ULONG,
SHORT, USHORT, CHAR, UCHAR,
LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
DBL, LDBL,
NOARG,
MAXSTATE
};
#define S(x) [(x)-'A']
static const unsigned char states[]['z'-'A'+1] = {
{ /* 0: bare types */
S('d') = INT, S('i') = INT,
S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
S('c') = CHAR, S('C') = INT,
S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
S('m') = NOARG,
S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
}, { /* 1: l-prefixed */
S('d') = LONG, S('i') = LONG,
S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
S('c') = INT, S('s') = PTR, S('n') = PTR,
S('l') = LLPRE,
}, { /* 2: ll-prefixed */
S('d') = LLONG, S('i') = LLONG,
S('o') = ULLONG, S('u') = ULLONG,
S('x') = ULLONG, S('X') = ULLONG,
S('n') = PTR,
}, { /* 3: h-prefixed */
S('d') = SHORT, S('i') = SHORT,
S('o') = USHORT, S('u') = USHORT,
S('x') = USHORT, S('X') = USHORT,
S('n') = PTR,
S('h') = HHPRE,
}, { /* 4: hh-prefixed */
S('d') = CHAR, S('i') = CHAR,
S('o') = UCHAR, S('u') = UCHAR,
S('x') = UCHAR, S('X') = UCHAR,
S('n') = PTR,
}, { /* 5: L-prefixed */
S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
S('n') = PTR,
}, { /* 6: z- or t-prefixed (assumed to be same size) */
S('d') = PDIFF, S('i') = PDIFF,
S('o') = SIZET, S('u') = SIZET,
S('x') = SIZET, S('X') = SIZET,
S('n') = PTR,
}, { /* 7: j-prefixed */
S('d') = IMAX, S('i') = IMAX,
S('o') = UMAX, S('u') = UMAX,
S('x') = UMAX, S('X') = UMAX,
S('n') = PTR,
}
};
#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
union arg
{
uintmax_t i;
long double f;
void *p;
};
static void pop_arg(union arg *arg, int type, va_list *ap)
{
switch (type) {
case PTR: arg->p = va_arg(*ap, void *);
break; case INT: arg->i = va_arg(*ap, int);
break; case UINT: arg->i = va_arg(*ap, unsigned int);
break; case LONG: arg->i = va_arg(*ap, long);
break; case ULONG: arg->i = va_arg(*ap, unsigned long);
break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
break; case SHORT: arg->i = (short)va_arg(*ap, int);
break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int);
break; case CHAR: arg->i = (signed char)va_arg(*ap, int);
break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int);
break; case LLONG: arg->i = va_arg(*ap, long long);
break; case SIZET: arg->i = va_arg(*ap, size_t);
break; case IMAX: arg->i = va_arg(*ap, intmax_t);
break; case UMAX: arg->i = va_arg(*ap, uintmax_t);
break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t);
break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *);
break; case DBL: arg->f = va_arg(*ap, double);
break; case LDBL: arg->f = va_arg(*ap, long double);
}
}
static void out(FILE *f, const wchar_t *s, size_t l)
{
while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f);
}
static int getint(wchar_t **s) {
int i;
for (i=0; iswdigit(**s); (*s)++) {
if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1;
else i = 10*i + (**s-'0');
}
return i;
}
static const char sizeprefix['y'-'a'] = {
['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L',
['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j',
['p'-'a']='j'
};
static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
{
wchar_t *a, *z, *s=(wchar_t *)fmt;
unsigned l10n=0, fl;
int w, p, xp;
union arg arg;
int argpos;
unsigned st, ps;
int cnt=0, l=0;
int i;
int t;
char *bs;
char charfmt[16];
wchar_t wc;
for (;;) {
/* This error is only specified for snprintf, but since it's
* unspecified for other forms, do the same. Stop immediately
* on overflow; otherwise %n could produce wrong results. */
if (l > INT_MAX - cnt) goto overflow;
/* Update output count, end loop when fmt is exhausted */
cnt += l;
if (!*s) break;
/* Handle literal text and %% format specifiers */
for (a=s; *s && *s!='%'; s++);
for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
if (z-a > INT_MAX-cnt) goto overflow;
l = z-a;
if (f) out(f, a, l);
if (l) continue;
if (iswdigit(s[1]) && s[2]=='$') {
l10n=1;
argpos = s[1]-'0';
s+=3;
} else {
argpos = -1;
s++;
}
/* Read modifier flags */
for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
fl |= 1U<<*s-' ';
/* Read field width */
if (*s=='*') {
if (iswdigit(s[1]) && s[2]=='$') {
l10n=1;
nl_type[s[1]-'0'] = INT;
w = nl_arg[s[1]-'0'].i;
s+=3;
} else if (!l10n) {
w = f ? va_arg(*ap, int) : 0;
s++;
} else goto inval;
if (w<0) fl|=LEFT_ADJ, w=-w;
} else if ((w=getint(&s))<0) goto overflow;
/* Read precision */
if (*s=='.' && s[1]=='*') {
if (isdigit(s[2]) && s[3]=='$') {
nl_type[s[2]-'0'] = INT;
p = nl_arg[s[2]-'0'].i;
s+=4;
} else if (!l10n) {
p = f ? va_arg(*ap, int) : 0;
s+=2;
} else goto inval;
xp = (p>=0);
} else if (*s=='.') {
s++;
p = getint(&s);
xp = 1;
} else {
p = -1;
xp = 0;
}
/* Format specifier state machine */
st=0;
do {
if (OOB(*s)) goto inval;
ps=st;
st=states[st]S(*s++);
} while (st-1<STOP);
if (!st) goto inval;
/* Check validity of argument type (nl/normal) */
if (st==NOARG) {
if (argpos>=0) goto inval;
} else {
if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
else if (f) pop_arg(&arg, st, ap);
else return 0;
}
if (!f) continue;
t = s[-1];
if (ps && (t&15)==3) t&=~32;
switch (t) {
case 'n':
switch(ps) {
case BARE: *(int *)arg.p = cnt; break;
case LPRE: *(long *)arg.p = cnt; break;
case LLPRE: *(long long *)arg.p = cnt; break;
case HPRE: *(unsigned short *)arg.p = cnt; break;
case HHPRE: *(unsigned char *)arg.p = cnt; break;
case ZTPRE: *(size_t *)arg.p = cnt; break;
case JPRE: *(uintmax_t *)arg.p = cnt; break;
}
continue;
case 'c':
fputwc(btowc(arg.i), f);
l = 1;
continue;
case 'C':
fputwc(arg.i, f);
l = 1;
continue;
case 'S':
a = arg.p;
z = a + wcsnlen(a, p<0 ? INT_MAX : p);
if (p<0 && *z) goto overflow;
p = z-a;
if (w<p) w=p;
if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
out(f, a, p);
if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
l=w;
continue;
case 'm':
arg.p = strerror(errno);
case 's':
if (!arg.p) arg.p = "(null)";
bs = arg.p;
for (i=l=0; l<(p<0?INT_MAX:p) && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++);
if (i<0) return -1;
if (p<0 && *bs) goto overflow;
p=l;
if (w<p) w=p;
if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
bs = arg.p;
while (l--) {
i=mbtowc(&wc, bs, MB_LEN_MAX);
bs+=i;
fputwc(wc, f);
}
if ((fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
l=w;
continue;
}
if (xp && p<0) goto overflow;
snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c",
"#"+!(fl & ALT_FORM),
"+"+!(fl & MARK_POS),
"-"+!(fl & LEFT_ADJ),
" "+!(fl & PAD_POS),
"0"+!(fl & ZERO_PAD),
sizeprefix[(t|32)-'a'], t);
switch (t|32) {
case 'a': case 'e': case 'f': case 'g':
l = fprintf(f, charfmt, w, p, arg.f);
break;
case 'd': case 'i': case 'o': case 'u': case 'x': case 'p':
l = fprintf(f, charfmt, w, p, arg.i);
break;
}
}
if (f) return cnt;
if (!l10n) return 0;
for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
pop_arg(nl_arg+i, nl_type[i], ap);
for (; i<=NL_ARGMAX && !nl_type[i]; i++);
if (i<=NL_ARGMAX) return -1;
return 1;
inval:
errno = EINVAL;
return -1;
overflow:
errno = EOVERFLOW;
return -1;
}
int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
{
va_list ap2;
int nl_type[NL_ARGMAX] = {0};
union arg nl_arg[NL_ARGMAX];
int olderr;
int ret;
/* the copy allows passing va_list* even if va_list is an array */
va_copy(ap2, ap);
if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
va_end(ap2);
return -1;
}
FLOCK(f);
fwide(f, 1);
olderr = f->flags & F_ERR;
f->flags &= ~F_ERR;
ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type);
if (f->flags & F_ERR) ret = -1;
f->flags |= olderr;
FUNLOCK(f);
va_end(ap2);
return ret;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <wchar.h>
#include <wctype.h>
#include <limits.h>
#include <string.h>
#include "stdio_impl.h"
#include "shgetc.h"
#include "intscan.h"
#include "floatscan.h"
#include "libc.h"
#define SIZE_hh -2
#define SIZE_h -1
#define SIZE_def 0
#define SIZE_l 1
#define SIZE_L 2
#define SIZE_ll 3
static void store_int(void *dest, int size, unsigned long long i)
{
if (!dest) return;
switch (size) {
case SIZE_hh:
*(char *)dest = i;
break;
case SIZE_h:
*(short *)dest = i;
break;
case SIZE_def:
*(int *)dest = i;
break;
case SIZE_l:
*(long *)dest = i;
break;
case SIZE_ll:
*(long long *)dest = i;
break;
}
}
static void *arg_n(va_list ap, unsigned int n)
{
void *p;
unsigned int i;
va_list ap2;
va_copy(ap2, ap);
for (i=n; i>1; i--) va_arg(ap2, void *);
p = va_arg(ap2, void *);
va_end(ap2);
return p;
}
static int in_set(const wchar_t *set, int c)
{
int j;
const wchar_t *p = set;
if (*p == '-') {
if (c=='-') return 1;
p++;
} else if (*p == ']') {
if (c==']') return 1;
p++;
}
for (; *p && *p != ']'; p++) {
if (*p=='-' && p[1] && p[1] != ']')
for (j=p++[-1]; j<*p; j++)
if (c==j) return 1;
if (c==*p) return 1;
}
return 0;
}
#if 1
#undef getwc
#define getwc(f) \
((f)->rpos < (f)->rend && *(f)->rpos < 128 ? *(f)->rpos++ : (getwc)(f))
#undef ungetwc
#define ungetwc(c,f) \
((f)->rend && (c)<128U ? *--(f)->rpos : ungetwc((c),(f)))
#endif
int vfwscanf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
{
int width;
int size;
int alloc;
const wchar_t *p;
int c, t;
char *s;
wchar_t *wcs;
void *dest=NULL;
int invert;
int matches=0;
off_t pos = 0, cnt;
static const char size_pfx[][3] = { "hh", "h", "", "l", "L", "ll" };
char tmp[3*sizeof(int)+10];
const wchar_t *set;
size_t i, k;
FLOCK(f);
fwide(f, 1);
for (p=fmt; *p; p++) {
alloc = 0;
if (iswspace(*p)) {
while (iswspace(p[1])) p++;
while (iswspace((c=getwc(f)))) pos++;
ungetwc(c, f);
continue;
}
if (*p != '%' || p[1] == '%') {
if (*p == '%') {
p++;
while (iswspace((c=getwc(f)))) pos++;
} else {
c = getwc(f);
}
if (c!=*p) {
ungetwc(c, f);
if (c<0) goto input_fail;
goto match_fail;
}
pos++;
continue;
}
p++;
if (*p=='*') {
dest = 0; p++;
} else if (iswdigit(*p) && p[1]=='$') {
dest = arg_n(ap, *p-'0'); p+=2;
} else {
dest = va_arg(ap, void *);
}
for (width=0; iswdigit(*p); p++) {
width = 10*width + *p - '0';
}
if (*p=='m') {
wcs = 0;
s = 0;
alloc = !!dest;
p++;
} else {
alloc = 0;
}
size = SIZE_def;
switch (*p++) {
case 'h':
if (*p == 'h') p++, size = SIZE_hh;
else size = SIZE_h;
break;
case 'l':
if (*p == 'l') p++, size = SIZE_ll;
else size = SIZE_l;
break;
case 'j':
size = SIZE_ll;
break;
case 'z':
case 't':
size = SIZE_l;
break;
case 'L':
size = SIZE_L;
break;
case 'd': case 'i': case 'o': case 'u': case 'x':
case 'a': case 'e': case 'f': case 'g':
case 'A': case 'E': case 'F': case 'G': case 'X':
case 's': case 'c': case '[':
case 'S': case 'C':
case 'p': case 'n':
p--;
break;
default:
goto fmt_fail;
}
t = *p;
/* Transform S,C -> ls,lc */
if ((t&0x2f)==3) {
size = SIZE_l;
t |= 32;
}
if (t != 'n') {
if (t != '[' && (t|32) != 'c')
while (iswspace((c=getwc(f)))) pos++;
else
c=getwc(f);
if (c < 0) goto input_fail;
ungetwc(c, f);
}
switch (t) {
case 'n':
store_int(dest, size, pos);
/* do not increment match count, etc! */
continue;
case 's':
case 'c':
case '[':
if (t == 'c') {
if (width<1) width = 1;
invert = 1;
set = L"";
} else if (t == 's') {
invert = 1;
static const wchar_t spaces[] = {
' ', '\t', '\n', '\r', 11, 12, 0x0085,
0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005,
0x2006, 0x2008, 0x2009, 0x200a,
0x2028, 0x2029, 0x205f, 0x3000, 0 };
set = spaces;
} else {
if (*++p == '^') p++, invert = 1;
else invert = 0;
set = p;
if (*p==']') p++;
while (*p!=']') {
if (!*p) goto fmt_fail;
p++;
}
}
s = (size == SIZE_def) ? dest : 0;
wcs = (size == SIZE_l) ? dest : 0;
int gotmatch = 0;
if (width < 1) width = -1;
i = 0;
if (alloc) {
k = t=='c' ? width+1U : 31;
if (size == SIZE_l) {
wcs = malloc(k*sizeof(wchar_t));
if (!wcs) goto alloc_fail;
} else {
s = malloc(k);
if (!s) goto alloc_fail;
}
}
while (width) {
if ((c=getwc(f))<0) break;
if (in_set(set, c) == invert)
break;
if (wcs) {
wcs[i++] = c;
if (alloc && i==k) {
k += k+1;
wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t));
if (!tmp) goto alloc_fail;
wcs = tmp;
}
} else if (size != SIZE_l) {
int l = wctomb(s?s+i:tmp, c);
if (l<0) goto input_fail;
i += l;
if (alloc && i > k-4) {
k += k+1;
char *tmp = realloc(s, k);
if (!tmp) goto alloc_fail;
s = tmp;
}
}
pos++;
width-=(width>0);
gotmatch=1;
}
if (width) {
ungetwc(c, f);
if (t == 'c' || !gotmatch) goto match_fail;
}
if (alloc) {
if (size == SIZE_l) *(wchar_t **)dest = wcs;
else *(char **)dest = s;
}
if (t != 'c') {
if (wcs) wcs[i] = 0;
if (s) s[i] = 0;
}
break;
case 'd': case 'i': case 'o': case 'u': case 'x':
case 'a': case 'e': case 'f': case 'g':
case 'A': case 'E': case 'F': case 'G': case 'X':
case 'p':
if (width < 1) width = 0;
snprintf(tmp, sizeof tmp, "%.*s%.0d%s%c%%lln",
1+!dest, "%*", width, size_pfx[size+2], t);
cnt = 0;
if (fscanf(f, tmp, dest?dest:&cnt, &cnt) == -1)
goto input_fail;
else if (!cnt)
goto match_fail;
pos += cnt;
break;
default:
goto fmt_fail;
}
if (dest) matches++;
}
if (0) {
fmt_fail:
alloc_fail:
input_fail:
if (!matches) matches--;
match_fail:
if (alloc) {
free(s);
free(wcs);
}
}
FUNLOCK(f);
return matches;
}
weak_alias(vfwscanf,__isoc99_vfwscanf);
#include <stdio.h>
int vprintf(const char *restrict fmt, va_list ap)
{
return vfprintf(stdout, fmt, ap);
}
#include <stdio.h>
#include <stdarg.h>
#include "libc.h"
int vscanf(const char *restrict fmt, va_list ap)
{
return vfscanf(stdin, fmt, ap);
}
weak_alias(vscanf,__isoc99_vscanf);
#include "stdio_impl.h"
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
struct cookie {
char *s;
size_t n;
};
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static size_t sn_write(FILE *f, const unsigned char *s, size_t l)
{
struct cookie *c = f->cookie;
size_t k = MIN(c->n, f->wpos - f->wbase);
if (k) {
memcpy(c->s, f->wbase, k);
c->s += k;
c->n -= k;
}
k = MIN(c->n, l);
if (k) {
memcpy(c->s, s, k);
c->s += k;
c->n -= k;
}
*c->s = 0;
f->wpos = f->wbase = f->buf;
/* pretend to succeed, even if we discarded extra data */
return l;
}
int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
{
unsigned char buf[1];
char dummy[1];
struct cookie c = { .s = n ? s : dummy, .n = n ? n-1 : 0 };
FILE f = {
.lbf = EOF,
.write = sn_write,
.lock = -1,
.buf = buf,
.cookie = &c,
};
if (n > INT_MAX) {
errno = EOVERFLOW;
return -1;
}
*c.s = 0;
return vfprintf(&f, fmt, ap);
}
#include <stdio.h>
#include <limits.h>
int vsprintf(char *restrict s, const char *restrict fmt, va_list ap)
{
return vsnprintf(s, INT_MAX, fmt, ap);
}
#include "stdio_impl.h"
#include "libc.h"
static size_t do_read(FILE *f, unsigned char *buf, size_t len)
{
return __string_read(f, buf, len);
}
int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap)
{
FILE f = {
.buf = (void *)s, .cookie = (void *)s,
.read = do_read, .lock = -1
};
return vfscanf(&f, fmt, ap);
}
weak_alias(vsscanf,__isoc99_vsscanf);
#include "stdio_impl.h"
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <wchar.h>
struct cookie {
wchar_t *ws;
size_t l;
};
static size_t sw_write(FILE *f, const unsigned char *s, size_t l)
{
size_t l0 = l;
int i = 0;
struct cookie *c = f->cookie;
if (s!=f->wbase && sw_write(f, f->wbase, f->wpos-f->wbase)==-1)
return -1;
while (c->l && l && (i=mbtowc(c->ws, (void *)s, l))>=0) {
s+=i;
l-=i;
c->l--;
c->ws++;
}
*c->ws = 0;
if (i < 0) {
f->wpos = f->wbase = f->wend = 0;
f->flags |= F_ERR;
return i;
}
f->wend = f->buf + f->buf_size;
f->wpos = f->wbase = f->buf;
return l0;
}
int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_list ap)
{
int r;
FILE f;
unsigned char buf[256];
struct cookie c = { s, n-1 };
memset(&f, 0, sizeof(FILE));
f.lbf = EOF;
f.write = sw_write;
f.buf_size = sizeof buf;
f.buf = buf;
f.lock = -1;
f.cookie = &c;
if (!n) {
return -1;
} else if (n > INT_MAX) {
errno = EOVERFLOW;
return -1;
}
r = vfwprintf(&f, fmt, ap);
sw_write(&f, 0, 0);
return r>=n ? -1 : r;
}
#include "stdio_impl.h"
#include "libc.h"
#include <wchar.h>
static size_t wstring_read(FILE *f, unsigned char *buf, size_t len)
{
const wchar_t *src = f->cookie;
size_t k;
if (!src) return 0;
k = wcsrtombs((void *)f->buf, &src, f->buf_size, 0);
if (k==(size_t)-1) {
f->rpos = f->rend = 0;
return 0;
}
f->rpos = f->buf;
f->rend = f->buf + k;
f->cookie = (void *)src;
if (!len || !k) return 0;
*buf = *f->rpos++;
return 1;
}
int vswscanf(const wchar_t *restrict s, const wchar_t *restrict fmt, va_list ap)
{
unsigned char buf[256];
FILE f = {
.buf = buf, .buf_size = sizeof buf,
.cookie = (void *)s,
.read = wstring_read, .lock = -1
};
return vfwscanf(&f, fmt, ap);
}
weak_alias(vswscanf,__isoc99_vswscanf);
#include <stdio.h>
#include <wchar.h>
int vwprintf(const wchar_t *restrict fmt, va_list ap)
{
return vfwprintf(stdout, fmt, ap);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册