mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 03:08:31 +00:00
Add epoll and do more release readiness changes
This change also pays off some of the remaining technical debt with stdio, file descriptors, and memory managemnt polyfills.
This commit is contained in:
parent
a9ea949df8
commit
3e4fd4b0ad
271 changed files with 5706 additions and 1365 deletions
|
@ -19,6 +19,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/* TODO(jart): Delete or rework */
|
||||
|
||||
/**
|
||||
* Returns number of bytes available in stream buffer.
|
||||
*/
|
||||
|
|
|
@ -37,10 +37,12 @@
|
|||
*/
|
||||
int fclose(FILE *f) {
|
||||
int rc;
|
||||
if (!f) return 0; /* good java behavior; glibc crashes */
|
||||
if (!f) return 0;
|
||||
_fflushunregister(f);
|
||||
fflush(f);
|
||||
free_s(&f->buf);
|
||||
if (!f->nofree) {
|
||||
free_s(&f->buf);
|
||||
}
|
||||
f->state = EOF;
|
||||
if (f->noclose) {
|
||||
f->fd = -1;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -31,14 +33,21 @@
|
|||
* @error ENOMEM
|
||||
*/
|
||||
FILE *fdopen(int fd, const char *mode) {
|
||||
FILE *res;
|
||||
if ((res = fmemopen(NULL, BUFSIZ, mode))) {
|
||||
res->fd = fd;
|
||||
res->reader = freadbuf;
|
||||
res->writer = fwritebuf;
|
||||
if ((res->iomode & O_ACCMODE) != O_RDONLY) {
|
||||
_fflushregister(res);
|
||||
FILE *f;
|
||||
if ((f = calloc(1, sizeof(FILE)))) {
|
||||
f->fd = fd;
|
||||
f->reader = __freadbuf;
|
||||
f->writer = __fwritebuf;
|
||||
f->bufmode = ischardev(fd) ? _IOLBF : _IOFBF;
|
||||
f->iomode = fopenflags(mode);
|
||||
f->size = BUFSIZ;
|
||||
if ((f->buf = valloc(f->size))) {
|
||||
if ((f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||
_fflushregister(f);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
free(f);
|
||||
}
|
||||
return res;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Returns true if stream is in end-of-file state.
|
||||
*/
|
||||
int feof(FILE *f) {
|
||||
return f->state == -1;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ static struct StdioFlush g_fflush;
|
|||
*
|
||||
* @param f is the stream handle
|
||||
* @return number of bytes written or -1 on error
|
||||
* @see fwritebuf
|
||||
*/
|
||||
int fflush(FILE *f) {
|
||||
size_t i;
|
||||
|
@ -62,19 +61,14 @@ int fflush(FILE *f) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (f->fd != -1 && (f->iomode & O_WRONLY)) {
|
||||
if (!f->state) {
|
||||
while (f->beg != f->end) {
|
||||
if ((wrote = fwritebuf(f)) != -1) {
|
||||
res += wrote;
|
||||
} else {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
} else if (f->fd != -1) {
|
||||
while (!f->state && f->beg && !f->end) {
|
||||
if ((wrote = __fwritebuf(f)) != -1) {
|
||||
res += wrote;
|
||||
}
|
||||
} else if (f->state != -1) {
|
||||
res = fseterr(f, f->state);
|
||||
}
|
||||
} else if (f->beg && f->beg < f->size) {
|
||||
f->buf[f->beg] = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -17,11 +17,17 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Reads uint8_t from stream.
|
||||
*/
|
||||
int fgetc(FILE *f) {
|
||||
return getc(f);
|
||||
int c;
|
||||
if (f->beg >= f->end) {
|
||||
if (!f->reader) return __fseteof(f);
|
||||
if (f->reader(f) == -1) return -1;
|
||||
}
|
||||
return f->buf[f->beg++];
|
||||
}
|
||||
|
|
|
@ -17,12 +17,8 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/popcnt.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -31,46 +27,46 @@
|
|||
/**
|
||||
* Opens buffer as stream.
|
||||
*
|
||||
* This function is the heart of the streams implementation, and it's
|
||||
* truly magnificent for unit testing.
|
||||
*
|
||||
* @param buf becomes owned by this function, and is allocated if NULL
|
||||
* @return new stream or NULL w/ errno
|
||||
* @error ENOMEM, EINVAL
|
||||
*/
|
||||
FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
||||
FILE *res;
|
||||
FILE *f;
|
||||
char *p;
|
||||
unsigned flags;
|
||||
|
||||
if (buf && !size) {
|
||||
if (size && size > 0x7ffff000) {
|
||||
einval();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size && popcnt(size) != 1) {
|
||||
einval();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(res = calloc(1, sizeof(FILE)))) {
|
||||
if (!(f = calloc(1, sizeof(FILE)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!buf) {
|
||||
if (!size) size = FRAMESIZE;
|
||||
if (!(buf = valloc(size))) {
|
||||
free(res);
|
||||
if (!size) size = BUFSIZ;
|
||||
if (!(buf = calloc(1, size))) {
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
f->nofree = true;
|
||||
}
|
||||
|
||||
f->fd = -1;
|
||||
f->buf = buf;
|
||||
f->size = size;
|
||||
f->end = size;
|
||||
f->iomode = fopenflags(mode);
|
||||
|
||||
if (f->iomode & O_APPEND) {
|
||||
if ((p = memchr(buf, '\0', size))) {
|
||||
f->beg = p - (char *)buf;
|
||||
} else {
|
||||
f->beg = f->end;
|
||||
}
|
||||
}
|
||||
|
||||
res->fd = -1;
|
||||
setbuffer(res, buf, size);
|
||||
res->bufmode = res->buf ? _IOFBF : _IONBF;
|
||||
flags = fopenflags(mode);
|
||||
res->iomode = (flags & O_ACCMODE) == O_RDWR
|
||||
? O_RDWR
|
||||
: (flags & O_ACCMODE) == O_WRONLY ? O_WRONLY : O_RDONLY;
|
||||
|
||||
return res;
|
||||
return f;
|
||||
}
|
||||
|
|
|
@ -27,20 +27,19 @@
|
|||
* @return c (as unsigned char) if written or -1 w/ errno
|
||||
*/
|
||||
noinstrument int fputc(int c, FILE *f) {
|
||||
if (c != -1) {
|
||||
if (f->beg < f->size) {
|
||||
c &= 0xff;
|
||||
f->buf[f->end] = c;
|
||||
f->end = (f->end + 1) & (f->size - 1);
|
||||
if (unlikely(f->beg == f->end || f->bufmode == _IONBF ||
|
||||
(f->bufmode == _IOLBF && c == '\n'))) {
|
||||
f->buf[f->beg++] = c;
|
||||
if (f->beg == f->size || f->bufmode == _IONBF ||
|
||||
(f->bufmode == _IOLBF && c == '\n')) {
|
||||
if (f->writer) {
|
||||
return f->writer(f);
|
||||
} else if (f->beg == f->end) {
|
||||
return fseteof(f);
|
||||
if (f->writer(f) == -1) return -1;
|
||||
} else if (f->beg == f->size) {
|
||||
f->beg = 0;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
return fseteof(f);
|
||||
return __fseteof(f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,9 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/limits.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpencode.internal.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
|
||||
/**
|
||||
* Writes wide character to stream.
|
||||
|
@ -29,15 +27,18 @@
|
|||
* @return wc if written or -1 w/ errno
|
||||
*/
|
||||
wint_t fputwc(wchar_t wc, FILE *f) {
|
||||
unsigned i, len;
|
||||
char buf[MB_LEN_MAX];
|
||||
uint64_t w;
|
||||
if (wc != -1) {
|
||||
len = tpencode(buf, sizeof(buf), wc, false);
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (fputc(buf[i], f) == -1) return -1;
|
||||
}
|
||||
w = tpenc(wc);
|
||||
do {
|
||||
if (fputc(w & 0xff, f) != -1) {
|
||||
w >>= 8;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} while (w);
|
||||
return wc;
|
||||
} else {
|
||||
return fseteof(f);
|
||||
return __fseteof(f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ size_t fread(void *buf, size_t stride, size_t count, FILE *f) {
|
|||
} else if (!(i % stride)) {
|
||||
return i / stride;
|
||||
} else {
|
||||
return fseterr(f, EOVERFLOW);
|
||||
return __fseterr(f, EOVERFLOW);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int freadbuf(FILE *f) {
|
||||
int __freadbuf(FILE *f) {
|
||||
ssize_t got;
|
||||
got = read(f->fd, f->buf, f->size - 1);
|
||||
if (got == -1) return fseterrno(f);
|
||||
if (got == 0) return fseteof(f);
|
||||
got = read(f->fd, f->buf, f->size);
|
||||
if (got == -1) return __fseterrno(f);
|
||||
if (got == 0) return __fseteof(f);
|
||||
f->beg = 0;
|
||||
f->end = got & (f->size - 1);
|
||||
f->end = got;
|
||||
return got;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
|
|||
kNtFileAttributeNormal)) {
|
||||
return stream;
|
||||
} else {
|
||||
winerr();
|
||||
__winerr();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/* TODO(jart): Delete or rework */
|
||||
|
||||
/**
|
||||
* Fills empty space in buffer with whatever's available.
|
||||
*
|
||||
|
@ -34,11 +36,9 @@ int freplenish(FILE *f) {
|
|||
ssize_t rc;
|
||||
size_t got;
|
||||
struct iovec iov[2];
|
||||
|
||||
if (f->beg == f->end) {
|
||||
f->beg = f->end = 0;
|
||||
}
|
||||
|
||||
if (f->beg <= f->end) {
|
||||
if (f->beg) {
|
||||
iov[0].iov_base = f->buf + f->end;
|
||||
|
@ -57,14 +57,14 @@ int freplenish(FILE *f) {
|
|||
if (rc != -1) {
|
||||
if (rc) {
|
||||
got = rc;
|
||||
f->end = (f->end + got) & (f->size - 1);
|
||||
f->end = (f->end + got) % f->size;
|
||||
return got;
|
||||
} else {
|
||||
return fseteof(f);
|
||||
return __fseteof(f);
|
||||
}
|
||||
} else if (errno == EINTR || errno == EAGAIN) {
|
||||
return 0;
|
||||
} else {
|
||||
return fseterrno(f);
|
||||
return __fseterrno(f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,25 @@
|
|||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Stream decoder.
|
||||
* @see libc/fmt/vcscanf.h
|
||||
* Decodes data from stream.
|
||||
*
|
||||
* To read a line of data from a well-formed trustworthy file:
|
||||
*
|
||||
* int x, y;
|
||||
* char text[256];
|
||||
* fscanf(f, "%d %d %s\n", &x, &y, text);
|
||||
*
|
||||
* Please note that this function is brittle by default, which makes it
|
||||
* a good fit for yolo coding. With some toil it can be used in a way
|
||||
* that makes it reasonably hardened although getline() may be better.
|
||||
*
|
||||
* @see libc/fmt/vcscanf.c
|
||||
*/
|
||||
int(fscanf)(FILE *stream, const char *fmt, ...) {
|
||||
int rc;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
rc = (vcscanf)((int (*)(void *))fgetc, stream, fmt, va);
|
||||
rc = (vcscanf)((int (*)(void *))fgetc, (void *)ungetc, stream, fmt, va);
|
||||
va_end(va);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Repositions open file stream.
|
||||
|
@ -29,20 +30,32 @@
|
|||
* is in the EOF state, this function can be used to restore it without
|
||||
* needing to reopen the file.
|
||||
*
|
||||
* @param stream is a non-null stream handle
|
||||
* @param f is a non-null stream handle
|
||||
* @param offset is the byte delta
|
||||
* @param whence can be SEET_SET, SEEK_CUR, or SEEK_END
|
||||
* @returns new offset or -1 on error
|
||||
*/
|
||||
long fseek(FILE *stream, long offset, int whence) {
|
||||
int skew = fflush(stream);
|
||||
if (whence == SEEK_CUR && skew != -1) offset -= skew;
|
||||
long fseek(FILE *f, long offset, int whence) {
|
||||
int skew;
|
||||
int64_t newpos;
|
||||
if ((newpos = lseek(stream->fd, offset, whence)) != -1) {
|
||||
stream->state = 0;
|
||||
return newpos;
|
||||
if (f->fd != -1) {
|
||||
if (whence == SEEK_CUR && f->beg < f->end) {
|
||||
offset -= f->end - f->beg;
|
||||
}
|
||||
if (f->beg && !f->end) {
|
||||
f->writer(f);
|
||||
}
|
||||
if ((newpos = lseek(f->fd, offset, whence)) != -1) {
|
||||
f->state = 0;
|
||||
f->beg = 0;
|
||||
f->end = 0;
|
||||
return newpos;
|
||||
} else {
|
||||
f->state = errno == ESPIPE ? EBADF : errno;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
stream->state = errno == ESPIPE ? EBADF : errno;
|
||||
f->beg = offset % f->size;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/internal.h"
|
||||
|
||||
long fseteof(FILE *f) {
|
||||
return fseterr(f, -1);
|
||||
long __fseteof(FILE *f) {
|
||||
return __fseterr(f, -1);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
|
||||
long fseterr(FILE *f, int err) {
|
||||
long __fseterr(FILE *f, int err) {
|
||||
if (!err) err = -1;
|
||||
f->state = f->state <= 0 ? err : f->state;
|
||||
if (err > 0) errno = err;
|
||||
|
|
|
@ -20,4 +20,6 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
|
||||
long fseterrno(FILE *f) { return fseterr(f, errno); }
|
||||
long __fseterrno(FILE *f) {
|
||||
return __fseterr(f, errno);
|
||||
}
|
||||
|
|
|
@ -26,4 +26,6 @@
|
|||
* @param stream is a non-null stream handle
|
||||
* @returns current byte offset from beginning of file, or -1
|
||||
*/
|
||||
long ftell(FILE *stream) { return fseek(stream, 0, SEEK_CUR); }
|
||||
long ftell(FILE *stream) {
|
||||
return fseek(stream, 0, SEEK_CUR);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
|
|||
if (!(i % stride)) {
|
||||
return i / stride;
|
||||
} else {
|
||||
return fseterr(f, EOVERFLOW);
|
||||
return __fseterr(f, EOVERFLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,28 +18,21 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* One-shot writes data from stream buffer to underlying file or device.
|
||||
*
|
||||
* @param f is a non-null open stream handle
|
||||
* @return number of bytes written or -1 on error
|
||||
*/
|
||||
int fwritebuf(FILE *f) {
|
||||
ssize_t put;
|
||||
unsigned bytes;
|
||||
bytes = (f->beg < f->end ? f->end : f->size) - f->beg;
|
||||
if ((put = write(f->fd, &f->buf[f->beg], bytes)) == -1) {
|
||||
int __fwritebuf(FILE *f) {
|
||||
ssize_t wrote;
|
||||
if ((wrote = write(f->fd, f->buf, f->beg)) == -1) {
|
||||
if (errno == EINTR) return 0;
|
||||
return (int)fseterrno(f);
|
||||
return __fseterrno(f);
|
||||
}
|
||||
f->beg = (unsigned)((f->beg + put) & (f->size - 1));
|
||||
return bytes;
|
||||
if (wrote == f->beg) {
|
||||
f->beg = 0;
|
||||
} else {
|
||||
memcpy(f->buf, f->buf + wrote, f->beg - wrote);
|
||||
f->beg -= wrote;
|
||||
}
|
||||
return wrote;
|
||||
}
|
||||
|
|
|
@ -35,10 +35,8 @@
|
|||
ezlea g_stderr_buf,cx
|
||||
mov %rcx,24(%rax) #→ f.buf
|
||||
movl $BUFSIZ,32(%rax) #→ f.size
|
||||
ezlea fwritebuf,cx
|
||||
ezlea fswritebuf,dx
|
||||
testb IsMetal()
|
||||
cmove %rcx,%rdx
|
||||
ezlea __fwritebuf,cx
|
||||
mov %rcx,%rdx
|
||||
mov %rdx,48(%rax) #→ f.writer
|
||||
mov %rax,stderr(%rip)
|
||||
.init.end 400,_init_g_stderr,globl,hidden
|
||||
|
|
|
@ -31,10 +31,8 @@
|
|||
ezlea g_stdin_buf,cx
|
||||
mov %rcx,24(%rax) #→ f.buf
|
||||
movl $BUFSIZ,32(%rax) #→ f.size
|
||||
ezlea freadbuf,cx
|
||||
ezlea fsreadbuf,dx
|
||||
testb IsMetal()
|
||||
cmove %rcx,%rdx
|
||||
ezlea __freadbuf,cx
|
||||
mov %rcx,%rdx
|
||||
mov %rdx,40(%rax) #→ f.reader
|
||||
mov %rax,stdin(%rip)
|
||||
.init.end 400,_init_g_stdin,globl,hidden
|
||||
|
|
|
@ -33,10 +33,8 @@
|
|||
ezlea g_stdout_buf,cx
|
||||
mov %rcx,24(%rax) #→ f.buf
|
||||
movl $BUFSIZ,32(%rax) #→ f.size
|
||||
ezlea fwritebuf,cx
|
||||
ezlea fswritebuf,dx
|
||||
testb IsMetal()
|
||||
cmovz %rcx,%rdx
|
||||
ezlea __fwritebuf,cx
|
||||
mov %rcx,%rdx
|
||||
mov %rdx,48(%rax) #→ f.writer
|
||||
mov %rax,stdout(%rip)
|
||||
.init.end 400,_init_g_stdout,globl,hidden
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int __getc_moar(FILE *f) {
|
||||
int b;
|
||||
if (f->beg == f->end) {
|
||||
if (!f->reader) return fseteof(f);
|
||||
if (f->reader(f) == -1) return -1;
|
||||
}
|
||||
b = f->buf[f->beg];
|
||||
f->beg = (f->beg + 1) & (f->size - 1);
|
||||
return b;
|
||||
}
|
|
@ -51,7 +51,7 @@ ssize_t getdelim(char **line, size_t *n, int delim, FILE *f) {
|
|||
break;
|
||||
}
|
||||
if (i + 2 >= *n && !__grow(line, n, 1, 0)) {
|
||||
fseterrno(f);
|
||||
__fseterrno(f);
|
||||
break;
|
||||
}
|
||||
if (((*line)[i++] = c) == delim) {
|
||||
|
|
|
@ -12,13 +12,11 @@ extern unsigned char g_stderrbuf[BUFSIZ];
|
|||
int _fflushregister(FILE *) hidden;
|
||||
void _fflushunregister(FILE *) hidden;
|
||||
|
||||
int freadbuf(FILE *) hidden;
|
||||
int fwritebuf(FILE *) hidden;
|
||||
int fsreadbuf(FILE *) hidden;
|
||||
int fswritebuf(FILE *) hidden;
|
||||
long fseteof(FILE *) hidden;
|
||||
long fseterrno(FILE *) hidden;
|
||||
long fseterr(FILE *, int) hidden;
|
||||
int __freadbuf(FILE *) hidden;
|
||||
int __fwritebuf(FILE *) hidden;
|
||||
long __fseteof(FILE *) hidden;
|
||||
long __fseterrno(FILE *) hidden;
|
||||
long __fseterr(FILE *, int) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -28,7 +28,7 @@ int(scanf)(const char *fmt, ...) {
|
|||
int rc;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
rc = (vcscanf)((int (*)(void *))fgetc, stdin, fmt, va);
|
||||
rc = (vcscanf)((int (*)(void *))fgetc, NULL, stdin, fmt, va);
|
||||
va_end(va);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/lib/pc.h"
|
||||
#include "libc/nexgen32e/uart.internal.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
static void fin(FILE *f) {
|
||||
f->buf[f->end] = inb(0x3F8);
|
||||
f->end = (f->end + 1) & (f->size - 1);
|
||||
}
|
||||
|
||||
static void fout(FILE *f) {
|
||||
outb(0x3F8, f->buf[f->beg]);
|
||||
f->beg = (f->beg + 1) & (f->size - 1);
|
||||
}
|
||||
|
||||
static int serialstdio(FILE *f, unsigned char status, void action(FILE *)) {
|
||||
int block = 1;
|
||||
unsigned tally = 0;
|
||||
while (f->end != f->beg) {
|
||||
if (!(inb(0x3F8 + UART_LSR) & status)) {
|
||||
if (!block) break;
|
||||
asm("pause");
|
||||
} else {
|
||||
action(f);
|
||||
tally++;
|
||||
}
|
||||
}
|
||||
return (int)tally;
|
||||
}
|
||||
|
||||
int fsreadbuf(FILE *f) {
|
||||
return serialstdio(f, UART_TTYDA, fin);
|
||||
}
|
||||
|
||||
int fswritebuf(FILE *f) {
|
||||
return serialstdio(f, UART_TTYTXR, fout);
|
||||
}
|
|
@ -18,7 +18,8 @@ typedef struct FILE {
|
|||
uint32_t beg; // 0x10
|
||||
uint32_t end; // 0x14
|
||||
uint8_t *buf; // 0x18
|
||||
size_t size; // 0x20
|
||||
uint32_t size; // 0x20
|
||||
uint32_t nofree; // 0x24
|
||||
int (*reader)(struct FILE *); // 0x28
|
||||
int (*writer)(struct FILE *); // 0x30
|
||||
} FILE;
|
||||
|
@ -99,10 +100,8 @@ int vfscanf(FILE *, const char *, va_list);
|
|||
│ cosmopolitan § standard i/o » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
int __getc_moar(FILE *);
|
||||
|
||||
#define putc(c, f) fputc(c, f)
|
||||
#define getc(f) (f->beg + 1 < f->end ? f->buf[f->beg++] : __getc_moar(f))
|
||||
#define getc(f) (f->beg < f->end ? f->buf[f->beg++] : fgetc(f))
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int ungetc(int c, FILE *f) {
|
||||
f->beg = (f->beg - 1) & (f->size - 1);
|
||||
f->buf[f->beg] = c;
|
||||
f->beg = (f->beg - 1u) & (f->size - 1);
|
||||
return c;
|
||||
}
|
||||
|
|
|
@ -25,5 +25,5 @@
|
|||
* @see libc/fmt/vcscanf.h
|
||||
*/
|
||||
int(vfscanf)(FILE *stream, const char *fmt, va_list ap) {
|
||||
return (vcscanf)((int (*)(void *))fgetc, stream, fmt, ap);
|
||||
return (vcscanf)((void *)fgetc, (void *)ungetc, stream, fmt, ap);
|
||||
}
|
||||
|
|
|
@ -25,5 +25,5 @@
|
|||
* @see libc/fmt/vcscanf.h
|
||||
*/
|
||||
int(vscanf)(const char *fmt, va_list ap) {
|
||||
return (vcscanf)((int (*)(void *))fgetc, stdin, fmt, ap);
|
||||
return (vcscanf)((int (*)(void *))fgetc, (void *)ungetc, stdin, fmt, ap);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue