mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
Make major improvements to stdio
Buffering now has optimal performance, bugs have been fixed, and some missing apis have been introduced. This implementation is also now more production worthy since it's less brittle now in terms of system errors. That's going to help redbean since lua i/o is all based on stdio. See #97
This commit is contained in:
parent
09bcfa23d5
commit
da36e7e256
69 changed files with 1595 additions and 735 deletions
|
@ -19,6 +19,7 @@
|
|||
#include "libc/alg/arraylist.internal.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/dns/hoststxt.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
@ -43,28 +44,28 @@
|
|||
* @see hoststxtsort() which is the logical next step
|
||||
*/
|
||||
int parsehoststxt(struct HostsTxt *ht, FILE *f) {
|
||||
int rc;
|
||||
char *line;
|
||||
size_t linesize;
|
||||
rc = 0;
|
||||
struct HostsTxtEntry entry;
|
||||
char *addr, *name, *tok, *comment;
|
||||
line = NULL;
|
||||
linesize = 0;
|
||||
while ((getline(&line, &linesize, f)) != -1) {
|
||||
struct HostsTxtEntry entry;
|
||||
char *addr, *name, *tok, *comment;
|
||||
if ((comment = strchr(line, '#'))) *comment = '\0';
|
||||
if ((addr = strtok_r(line, " \t\r\n\v", &tok)) &&
|
||||
inet_pton(AF_INET, addr, entry.ip) == 1) {
|
||||
entry.canon = ht->strings.i;
|
||||
while ((name = strtok_r(NULL, " \t\r\n\v", &tok))) {
|
||||
entry.name = ht->strings.i;
|
||||
if (concat(&ht->strings, name, strnlen(name, DNS_NAME_MAX) + 1) == -1 ||
|
||||
append(&ht->entries, &entry) == -1) {
|
||||
rc = -1;
|
||||
}
|
||||
concat(&ht->strings, name, strnlen(name, DNS_NAME_MAX) + 1);
|
||||
append(&ht->entries, &entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
return rc | ferror(f);
|
||||
if (ferror(f)) {
|
||||
errno = ferror(f);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ void vflogf_onfail(FILE *f) {
|
|||
struct stat st;
|
||||
if (IsTiny()) return;
|
||||
err = ferror(f);
|
||||
if ((err == ENOSPC || err == EDQUOT || err == EFBIG) &&
|
||||
if (fileno(f) != -1 && (err == ENOSPC || err == EDQUOT || err == EFBIG) &&
|
||||
(fstat(fileno(f), &st) == -1 || st.st_size > kNontrivialSize)) {
|
||||
ftruncate(fileno(f), 0);
|
||||
fseek(f, SEEK_SET, 0);
|
||||
|
@ -91,6 +91,7 @@ void vflogf_onfail(FILE *f) {
|
|||
*/
|
||||
void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
||||
const char *fmt, va_list va) {
|
||||
int bufmode;
|
||||
struct tm tm;
|
||||
long double t2;
|
||||
const char *prog;
|
||||
|
@ -98,7 +99,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
|||
char buf32[32], *buf32p;
|
||||
int64_t secs, nsec, dots;
|
||||
if (!f) f = __log_file;
|
||||
if (fileno(f) == -1) return;
|
||||
if (!f) return;
|
||||
t2 = nowl();
|
||||
secs = t2;
|
||||
nsec = (t2 - secs) * 1e9L;
|
||||
|
@ -114,6 +115,8 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
|||
buf32p = "--------------------";
|
||||
}
|
||||
prog = basename(program_invocation_name);
|
||||
bufmode = f->bufmode;
|
||||
if (bufmode == _IOLBF) f->bufmode = _IOFBF;
|
||||
if ((fprintf)(f, "%c%s%06ld:%s:%d:%.*s:%d] ", vflogf_loglevel2char(level),
|
||||
buf32p, rem1000000int64(div1000int64(dots)), file, line,
|
||||
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) {
|
||||
|
@ -122,6 +125,10 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
|||
(vfprintf)(f, fmt, va);
|
||||
va_end(va);
|
||||
fputs("\n", f);
|
||||
if (bufmode == _IOLBF) {
|
||||
f->bufmode = _IOLBF;
|
||||
fflush(f);
|
||||
}
|
||||
if (level == kLogFatal) {
|
||||
__start_fatal(file, line);
|
||||
strcpy(buf32, "unknown");
|
||||
|
|
|
@ -53,7 +53,7 @@ static char g_buf[512];
|
|||
static const char *g_lastsymbol;
|
||||
static struct SymbolTable *g_symbols;
|
||||
|
||||
forceinline int GetNestingLevel(struct StackFrame *frame) {
|
||||
static noasan int GetNestingLevel(struct StackFrame *frame) {
|
||||
int nesting = -2;
|
||||
while (frame) {
|
||||
++nesting;
|
||||
|
@ -69,7 +69,7 @@ forceinline int GetNestingLevel(struct StackFrame *frame) {
|
|||
* prologues of other functions. We assume those functions behave
|
||||
* according to the System Five NexGen32e ABI.
|
||||
*/
|
||||
privileged void ftrace(void) {
|
||||
privileged noasan void ftrace(void) {
|
||||
size_t i, j, nesting;
|
||||
const char *symbol;
|
||||
struct StackFrame *frame;
|
||||
|
|
|
@ -35,8 +35,6 @@ FILE *fdopen(int fd, const char *mode) {
|
|||
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;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -36,28 +37,26 @@
|
|||
*/
|
||||
int fflush(FILE *f) {
|
||||
size_t i;
|
||||
int rc;
|
||||
rc = 0;
|
||||
ssize_t rc;
|
||||
if (!f) {
|
||||
for (i = __fflush.handles.i; i; --i) {
|
||||
if ((f = __fflush.handles.p[i - 1])) {
|
||||
if (fflush(f) == -1) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
if (fflush(f) == -1) return -1;
|
||||
}
|
||||
}
|
||||
} else if (f->fd != -1) {
|
||||
while (f->beg && !f->end) {
|
||||
if (__fwritebuf(f) == -1) {
|
||||
rc = -1;
|
||||
break;
|
||||
while (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||
if ((rc = write(f->fd, f->buf, f->beg)) == -1) {
|
||||
f->state = errno;
|
||||
return -1;
|
||||
}
|
||||
if (rc != f->beg) abort();
|
||||
f->beg = 0;
|
||||
}
|
||||
} else if (f->beg && f->beg < f->size) {
|
||||
f->buf[f->beg] = 0;
|
||||
}
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
textstartup int __fflush_register(FILE *f) {
|
||||
|
|
|
@ -16,22 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
static noinline int __fgetc(FILE *f) {
|
||||
if (!f->reader) return __fseteof(f);
|
||||
if (f->reader(f) == -1) return -1;
|
||||
return f->buf[f->beg++];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads uint8_t from stream.
|
||||
* Reads byte from stream.
|
||||
* @return byte in range 0..255, or -1 w/ errno
|
||||
*/
|
||||
int fgetc(FILE *f) {
|
||||
unsigned char b;
|
||||
if (f->beg < f->end) {
|
||||
return f->buf[f->beg++];
|
||||
return f->buf[f->beg++] & 0xff;
|
||||
} else {
|
||||
return __fgetc(f);
|
||||
if (!fread(&b, 1, 1, f)) return -1;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,16 +17,35 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "libc/str/tpdecodecb.internal.h"
|
||||
|
||||
/**
|
||||
* Reads UTF-8 character from stream.
|
||||
*
|
||||
* @return wide character or -1 on EOF or error
|
||||
*/
|
||||
wint_t fgetwc(FILE *f) {
|
||||
wint_t res;
|
||||
res = -1;
|
||||
tpdecodecb(&res, fgetc(f), (void *)fgetc, f);
|
||||
return res;
|
||||
int c, n;
|
||||
wint_t b, x, y;
|
||||
if (f->beg < f->end) {
|
||||
b = f->buf[f->beg++] & 0xff;
|
||||
} else if ((c = fgetc(f)) != -1) {
|
||||
b = c;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
if (b < 0300) return b;
|
||||
n = ThomPikeLen(b);
|
||||
x = ThomPikeByte(b);
|
||||
while (--n) {
|
||||
if ((c = fgetc(f)) == -1) return -1;
|
||||
y = c;
|
||||
if (ThomPikeCont(y)) {
|
||||
x = ThomPikeMerge(x, y);
|
||||
} else {
|
||||
ungetc(y, f);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
* Reads UTF-8 content from stream into UTF-32 buffer.
|
||||
*/
|
||||
wchar_t *fgetws(wchar_t *s, int size, FILE *f) {
|
||||
wint_t c;
|
||||
wchar_t *p = s;
|
||||
if (size > 0) {
|
||||
while (--size > 0) {
|
||||
wint_t c;
|
||||
if ((c = fgetwc(f)) == -1) {
|
||||
if (ferror(f) == EINTR) continue;
|
||||
break;
|
||||
|
|
|
@ -32,32 +32,27 @@ FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
|||
FILE *f;
|
||||
char *p;
|
||||
unsigned flags;
|
||||
|
||||
if (size && size > 0x7ffff000) {
|
||||
einval();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(f = calloc(1, sizeof(FILE)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!buf) {
|
||||
if (buf) {
|
||||
f->nofree = true;
|
||||
} else {
|
||||
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->size = size;
|
||||
f->iomode = fopenflags(mode);
|
||||
|
||||
if (f->iomode & O_APPEND) {
|
||||
if ((p = memchr(buf, '\0', size))) {
|
||||
f->beg = p - (char *)buf;
|
||||
|
@ -65,6 +60,5 @@ FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
|||
f->beg = f->end;
|
||||
}
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
|
|
@ -17,33 +17,22 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Writes byte to stream.
|
||||
* @return c (as unsigned char) if written or -1 w/ errno
|
||||
* @see putc() if called within loop
|
||||
*
|
||||
* @param c is byte to buffer or write, which is masked
|
||||
* @return c as unsigned char if written or -1 w/ errno
|
||||
*/
|
||||
noinstrument int fputc(int c, FILE *f) {
|
||||
if ((f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||
if (f->beg < f->size) {
|
||||
f->buf[f->beg++] = c;
|
||||
if (f->beg == f->size || f->bufmode == _IONBF ||
|
||||
(f->bufmode == _IOLBF && c == '\n')) {
|
||||
if (f->writer) {
|
||||
if (f->writer(f) == -1) return -1;
|
||||
} else if (f->beg == f->size) {
|
||||
f->beg = 0;
|
||||
}
|
||||
}
|
||||
return c & 0xff;
|
||||
} else {
|
||||
return __fseteof(f);
|
||||
}
|
||||
int fputc(int c, FILE *f) {
|
||||
unsigned char b;
|
||||
if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) {
|
||||
f->buf[f->beg++] = c;
|
||||
return c & 0xff;
|
||||
} else {
|
||||
return __fseterr(f, EBADF);
|
||||
b = c;
|
||||
if (!fwrite(&b, 1, 1, f)) return -1;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
|
@ -31,17 +28,12 @@
|
|||
*
|
||||
* @param s is a NUL-terminated string that's non-NULL
|
||||
* @param f is an open stream
|
||||
* @return strlen(s) or -1 w/ errno on error
|
||||
* @return bytes written, or -1 w/ errno
|
||||
*/
|
||||
int fputs(const char *s, FILE *f) {
|
||||
int i, n, m;
|
||||
size_t n, r;
|
||||
n = strlen(s);
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (putc(s[i], f) == -1) {
|
||||
if (ferror(f) == EINTR) continue;
|
||||
if (feof(f)) errno = f->state = EPIPE;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
r = fwrite(s, 1, n, f);
|
||||
if (!r && n) return -1;
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
|
||||
|
@ -30,14 +29,12 @@ wint_t fputwc(wchar_t wc, FILE *f) {
|
|||
if (wc != -1) {
|
||||
w = tpenc(wc);
|
||||
do {
|
||||
if (fputc(w & 0xff, f) != -1) {
|
||||
w >>= 8;
|
||||
} else {
|
||||
if (fputc(w, f) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} while (w);
|
||||
} while ((w >>= 8));
|
||||
return wc;
|
||||
} else {
|
||||
return __fseteof(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,19 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Reads data from stream.
|
||||
|
@ -31,17 +38,62 @@
|
|||
* @return count on success, [0,count) on eof, or 0 on error or count==0
|
||||
*/
|
||||
size_t fread(void *buf, size_t stride, size_t count, FILE *f) {
|
||||
int c;
|
||||
size_t i, n;
|
||||
unsigned char *p;
|
||||
for (n = stride * count, p = buf, i = 0; i < n; ++i) {
|
||||
if ((c = getc(f)) != -1) {
|
||||
p[i] = c & 0xff;
|
||||
} else if (!(i % stride)) {
|
||||
return i / stride;
|
||||
} else {
|
||||
return __fseterr(f, EOVERFLOW);
|
||||
}
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
size_t n, m;
|
||||
struct iovec iov[2];
|
||||
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
|
||||
f->state = errno = EBADF;
|
||||
return 0;
|
||||
}
|
||||
if (f->beg > f->end) {
|
||||
f->state = errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
p = buf;
|
||||
n = stride * count;
|
||||
m = f->end - f->beg;
|
||||
memcpy(p, f->buf + f->beg, MIN(n, m));
|
||||
if (n < m) {
|
||||
f->beg += n;
|
||||
return count;
|
||||
}
|
||||
if (n == m) {
|
||||
f->beg = f->end = 0;
|
||||
return count;
|
||||
}
|
||||
if (f->fd == -1) {
|
||||
f->beg = 0;
|
||||
f->end = 0;
|
||||
f->state = -1;
|
||||
return m / stride;
|
||||
}
|
||||
iov[0].iov_base = p + m;
|
||||
iov[0].iov_len = n - m;
|
||||
if (f->bufmode != _IONBF && n < f->size) {
|
||||
iov[1].iov_base = f->buf;
|
||||
if (f->size > PUSHBACK) {
|
||||
iov[1].iov_len = f->size - PUSHBACK;
|
||||
} else {
|
||||
iov[1].iov_len = f->size;
|
||||
}
|
||||
} else {
|
||||
iov[1].iov_base = NULL;
|
||||
iov[1].iov_len = 0;
|
||||
}
|
||||
if ((rc = readv(f->fd, iov, 2)) == -1) {
|
||||
f->state = errno;
|
||||
return 0;
|
||||
}
|
||||
n = rc;
|
||||
f->beg = 0;
|
||||
f->end = 0;
|
||||
if (n > iov[0].iov_len) {
|
||||
f->end += n - iov[0].iov_len;
|
||||
return count;
|
||||
} else {
|
||||
n = (m + n) / stride;
|
||||
if (n < count) f->state = -1;
|
||||
return n;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -16,10 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Repositions open file stream.
|
||||
|
@ -32,28 +29,8 @@
|
|||
* @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
|
||||
* @returns 0 on success or -1 on error
|
||||
*/
|
||||
long fseek(FILE *f, long offset, int whence) {
|
||||
int64_t pos;
|
||||
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 (lseek(f->fd, offset, whence) != -1) {
|
||||
f->state = 0;
|
||||
f->beg = 0;
|
||||
f->end = 0;
|
||||
return 0;
|
||||
} else {
|
||||
f->state = errno == ESPIPE ? EBADF : errno;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
f->beg = (offset & 0xffffffff) % f->size;
|
||||
return -1;
|
||||
}
|
||||
int fseek(FILE *f, long offset, int whence) {
|
||||
return fseeko(f, offset, whence);
|
||||
}
|
||||
|
|
83
libc/stdio/fseeko.c
Normal file
83
libc/stdio/fseeko.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Repositions open file stream.
|
||||
*
|
||||
* This function flushes the buffer (unless it's currently in the EOF
|
||||
* state) and then calls lseek() on the underlying file. If the stream
|
||||
* is in the EOF state, this function can be used to restore it without
|
||||
* needing to reopen the file.
|
||||
*
|
||||
* @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 0 on success or -1 on error
|
||||
*/
|
||||
int fseeko(FILE *f, int64_t offset, int whence) {
|
||||
ssize_t rc;
|
||||
int64_t pos;
|
||||
if (f->fd != -1) {
|
||||
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||
if ((rc = write(f->fd, f->buf, f->beg)) == -1) {
|
||||
f->state = errno;
|
||||
return -1;
|
||||
}
|
||||
if (rc != f->beg) abort();
|
||||
f->beg = 0;
|
||||
}
|
||||
if (whence == SEEK_CUR && f->beg < f->end) {
|
||||
offset -= f->end - f->beg;
|
||||
}
|
||||
if (lseek(f->fd, offset, whence) != -1) {
|
||||
f->beg = 0;
|
||||
f->end = 0;
|
||||
return 0;
|
||||
} else {
|
||||
f->state = errno == ESPIPE ? EBADF : errno;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
pos = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
pos = f->beg + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
pos = f->end + offset;
|
||||
break;
|
||||
default:
|
||||
pos = -1;
|
||||
break;
|
||||
}
|
||||
if (0 <= pos && pos <= f->end) {
|
||||
f->beg = pos;
|
||||
return 0;
|
||||
} else {
|
||||
f->state = errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,33 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Returns current position of stream.
|
||||
*
|
||||
* @param stream is a non-null stream handle
|
||||
* @returns current byte offset from beginning of file, or -1
|
||||
* @returns current byte offset from beginning, or -1 w/ errno
|
||||
*/
|
||||
long ftell(FILE *f) {
|
||||
int64_t pos;
|
||||
if (f->fd != -1) {
|
||||
if (f->beg && !f->end) {
|
||||
f->writer(f);
|
||||
}
|
||||
if ((pos = lseek(f->fd, 0, SEEK_CUR)) != -1) {
|
||||
f->state = 0;
|
||||
f->beg = 0;
|
||||
f->end = 0;
|
||||
return pos;
|
||||
} else {
|
||||
f->state = errno == ESPIPE ? EBADF : errno;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
errno = f->state;
|
||||
return -1;
|
||||
}
|
||||
return ftello(f);
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
ftello: jmp ftell
|
||||
.endfn ftello,globl
|
54
libc/stdio/ftello.c
Normal file
54
libc/stdio/ftello.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Returns current position of stream.
|
||||
*
|
||||
* @param stream is a non-null stream handle
|
||||
* @returns current byte offset from beginning, or -1 w/ errno
|
||||
*/
|
||||
int64_t ftello(FILE *f) {
|
||||
ssize_t rc;
|
||||
int64_t pos;
|
||||
uint32_t skew;
|
||||
if (f->fd != -1) {
|
||||
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||
if ((rc = write(f->fd, f->buf, f->beg)) == -1) {
|
||||
f->state = errno;
|
||||
return -1;
|
||||
}
|
||||
if (rc != f->beg) abort();
|
||||
f->beg = 0;
|
||||
}
|
||||
if ((pos = lseek(f->fd, 0, SEEK_CUR)) != -1) {
|
||||
if (f->beg < f->end) pos -= f->end - f->beg;
|
||||
return pos;
|
||||
} else {
|
||||
f->state = errno == ESPIPE ? EBADF : errno;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return f->beg;
|
||||
}
|
||||
}
|
|
@ -16,10 +16,17 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Writes data to stream.
|
||||
|
@ -29,10 +36,54 @@
|
|||
* @return count on success, [0,count) on EOF, 0 on error or count==0
|
||||
*/
|
||||
size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
|
||||
size_t i, n;
|
||||
const unsigned char *p;
|
||||
for (n = stride * count, p = data, i = 0; i < n; ++i) {
|
||||
if (fputc(p[i], f) == -1) return -1;
|
||||
ldiv_t d;
|
||||
ssize_t rc;
|
||||
size_t n, m;
|
||||
const char *p;
|
||||
struct iovec iov[2];
|
||||
if ((f->iomode & O_ACCMODE) == O_RDONLY) {
|
||||
f->state = errno = EBADF;
|
||||
return 0;
|
||||
}
|
||||
n = stride * count;
|
||||
m = f->size - f->beg;
|
||||
if (n <= m && f->bufmode != _IONBF) {
|
||||
memcpy(f->buf + f->beg, data, n);
|
||||
f->beg += n;
|
||||
if (f->fd != -1 && f->bufmode == _IOLBF &&
|
||||
(p = memrchr(f->buf, '\n', f->beg))) {
|
||||
n = p + 1 - f->buf;
|
||||
if ((rc = write(f->fd, f->buf, n)) == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN) return count;
|
||||
f->state = errno;
|
||||
return 0;
|
||||
}
|
||||
n = rc;
|
||||
memmove(f->buf, f->buf + n, f->beg - n);
|
||||
f->beg -= n;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
if (f->fd == -1) {
|
||||
n = MIN(n, m);
|
||||
d = ldiv(n, stride);
|
||||
n -= d.rem;
|
||||
memcpy(f->buf + f->beg, data, n);
|
||||
f->beg += n;
|
||||
f->state = -1;
|
||||
return d.quot;
|
||||
}
|
||||
iov[0].iov_base = f->buf;
|
||||
iov[0].iov_len = f->beg;
|
||||
iov[1].iov_base = data;
|
||||
iov[1].iov_len = n;
|
||||
n += f->beg;
|
||||
if ((rc = writev(f->fd, iov, 2)) == -1) {
|
||||
f->state = errno;
|
||||
return 0;
|
||||
}
|
||||
m = rc;
|
||||
if (n != m) abort();
|
||||
f->beg = 0;
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/notice.inc"
|
||||
.source __FILE__
|
||||
|
||||
getc: jmp fgetc
|
||||
.endfn getc,globl
|
|
@ -16,13 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
long __fseterr(FILE *f, int err) {
|
||||
if (!err) err = -1;
|
||||
f->state = f->state <= 0 ? err : f->state;
|
||||
if (err > 0) errno = err;
|
||||
return -1;
|
||||
/**
|
||||
* Reads byte from stream.
|
||||
* @return byte in range 0..255, or -1 w/ errno
|
||||
*/
|
||||
int(getc)(FILE *f) {
|
||||
return fgetc(f);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
// Reads uint8_t from standard input.
|
||||
// @return %al has result w/ rest of %rax cleared
|
||||
getchar:mov stdin(%rip),%rdi
|
||||
jmp fgetc
|
||||
.endfn getchar,globl
|
27
libc/stdio/getchar.c
Normal file
27
libc/stdio/getchar.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Reads byte from stream.
|
||||
* @return byte in range 0..255, or -1 w/ errno
|
||||
*/
|
||||
int getchar(void) {
|
||||
return fgetc(stdin);
|
||||
}
|
|
@ -17,54 +17,63 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Reads string from stream.
|
||||
*
|
||||
* @param line is the caller's buffer (in/out) which is extended
|
||||
* automatically. *line may be NULL but only if *n is 0;
|
||||
* NUL-termination is guaranteed FTMP
|
||||
* @param n is the capacity of line (in/out)
|
||||
* @param s is the caller's buffer (in/out) which is extended or
|
||||
* allocated automatically, also NUL-terminated is guaranteed
|
||||
* @param n is the capacity of s (in/out)
|
||||
* @param delim is the stop char (and NUL is implicitly too)
|
||||
* @return number of bytes read, including delim, excluding NUL, or -1
|
||||
* w/ errno on EOF or error; see ferror() and feof()
|
||||
* @note this function can't punt EINTR to caller
|
||||
* @see getline(), gettok_r()
|
||||
*/
|
||||
ssize_t getdelim(char **line, size_t *n, int delim, FILE *f) {
|
||||
assert((*line && *n) || (!*line && !*n));
|
||||
ssize_t rc = -1;
|
||||
size_t i = 0;
|
||||
char *p2;
|
||||
size_t n2;
|
||||
int c;
|
||||
for (;;) {
|
||||
if ((c = getc(f)) == -1) {
|
||||
if (ferror(f) == EINTR) continue;
|
||||
if (feof(f) && i) rc = i;
|
||||
break;
|
||||
}
|
||||
if (i + 2 > *n) {
|
||||
n2 = MAX(11, *n);
|
||||
n2 += n2 >> 1;
|
||||
if ((p2 = realloc(*line, n2))) {
|
||||
*line = p2;
|
||||
*n = n2;
|
||||
} else {
|
||||
__fseterrno(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (((*line)[i++] = c) == delim) {
|
||||
rc = i;
|
||||
ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
size_t i, m;
|
||||
if ((f->iomode & O_ACCMODE) == O_WRONLY) {
|
||||
f->state = errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
if (f->beg > f->end || f->bufmode == _IONBF) {
|
||||
f->state = errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!*s) *n = 0;
|
||||
for (i = 0;; i += m) {
|
||||
m = f->end - f->beg;
|
||||
if ((p = memchr(f->buf + f->beg, delim, m))) m = p + 1 - (f->buf + f->beg);
|
||||
if (i + m + 1 > *n && !(*s = realloc(*s, (*n = i + m + 1)))) abort();
|
||||
memcpy(*s + i, f->buf + f->beg, m);
|
||||
(*s)[i + m] = '\0';
|
||||
if ((f->beg += m) == f->end) f->beg = f->end = 0;
|
||||
if (p) {
|
||||
return i + m;
|
||||
} else if (f->fd == -1) {
|
||||
break;
|
||||
} else if ((rc = read(f->fd, f->buf, f->size)) != -1) {
|
||||
if (!rc) break;
|
||||
f->end = rc;
|
||||
} else if (errno != EINTR) {
|
||||
f->state = errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (*line && i < *n) (*line)[i] = '\0';
|
||||
return rc;
|
||||
f->state = -1;
|
||||
if (i + m) {
|
||||
return i + m;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
getwc: jmp fgetwc
|
||||
.endfn getwc,globl
|
|
@ -16,9 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
long __fseterrno(FILE *f) {
|
||||
return __fseterr(f, errno);
|
||||
/**
|
||||
* Reads UTF-8 character from stream.
|
||||
* @return wide character or -1 on EOF or error
|
||||
*/
|
||||
wint_t(getwc)(FILE *f) {
|
||||
return fgetwc(f);
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
// Reads Thompson-Pike encoded varint from standard input.
|
||||
// @return %eax has result w/ rest of %rax cleared
|
||||
getwchar:
|
||||
mov stdin(%rip),%rdi
|
||||
jmp fgetwc
|
||||
.endfn getwchar,globl
|
|
@ -16,8 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
long __fseteof(FILE *f) {
|
||||
return __fseterr(f, -1);
|
||||
/**
|
||||
* Reads UTF-8 character from stream.
|
||||
* @return wide character or -1 on EOF or error
|
||||
*/
|
||||
wint_t getwchar(void) {
|
||||
return fgetwc(stdin);
|
||||
}
|
|
@ -1,23 +1,19 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_STDIO_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_STDIO_INTERNAL_H_
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
#define PUSHBACK 12
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern unsigned char g_stdinbuf[BUFSIZ];
|
||||
extern unsigned char g_stdoutbuf[BUFSIZ];
|
||||
extern unsigned char g_stderrbuf[BUFSIZ];
|
||||
extern char g_stdinbuf[BUFSIZ];
|
||||
extern char g_stdoutbuf[BUFSIZ];
|
||||
extern char g_stderrbuf[BUFSIZ];
|
||||
|
||||
int __fflush_register(FILE *) hidden;
|
||||
void __fflush_unregister(FILE *) hidden;
|
||||
|
||||
int __freadbuf(FILE *) hidden;
|
||||
int __fwritebuf(FILE *) hidden;
|
||||
long __fseteof(FILE *) hidden;
|
||||
long __fseterrno(FILE *) hidden;
|
||||
long __fseterr(FILE *, int) hidden;
|
||||
void __fclosepid(FILE *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_STDIO_INTERNAL_H_ */
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
putc: jmp fputc
|
||||
.endfn putc,globl
|
|
@ -16,17 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int __freadbuf(FILE *f) {
|
||||
ssize_t got;
|
||||
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;
|
||||
return got;
|
||||
/**
|
||||
* Writes byte to stream.
|
||||
*
|
||||
* @param c is byte to buffer or write, which is masked
|
||||
* @return c as unsigned char if written or -1 w/ errno
|
||||
*/
|
||||
int(putc)(int c, FILE *f) {
|
||||
return fputc(c, f);
|
||||
}
|
|
@ -22,9 +22,17 @@
|
|||
* Writes string w/ trailing newline to stdout.
|
||||
*/
|
||||
int puts(const char *s) {
|
||||
FILE *f = stdout;
|
||||
int rc, res;
|
||||
if ((res = rc = fputs(s, f)) == -1) return -1;
|
||||
if ((rc = fputc('\n', f)) == -1) return -1;
|
||||
return res + 1;
|
||||
FILE *f;
|
||||
size_t n, r;
|
||||
f = stdout;
|
||||
if ((n = strlen(s))) {
|
||||
r = fwrite(s, 1, n, f);
|
||||
if (!r) return -1;
|
||||
if (r < n) return r;
|
||||
}
|
||||
if (fputc('\n', f) == -1) {
|
||||
if (feof(f)) return n;
|
||||
return -1;
|
||||
}
|
||||
return n + 1;
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
// Writes wide character to stream.
|
||||
// @param %edi is the wide character
|
||||
// @param %rsi is the FILE stream pointer
|
||||
// @return %eax is set to %edi param or -1 on error
|
||||
putwc: jmp fputwc
|
||||
.endfn putwc,globl
|
|
@ -1,5 +1,5 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
/*-*- 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 │
|
||||
│ │
|
||||
|
@ -16,8 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
fseeko: jmp fseek
|
||||
.endfn fseeko,globl
|
||||
/**
|
||||
* Writes wide character to stream.
|
||||
*
|
||||
* @return wc if written or -1 w/ errno
|
||||
*/
|
||||
wint_t(putwc)(wchar_t wc, FILE *f) {
|
||||
return fputwc(wc, f);
|
||||
}
|
|
@ -20,7 +20,8 @@
|
|||
|
||||
/**
|
||||
* Writes wide character to stdout.
|
||||
*
|
||||
* @return wc if written or -1 w/ errno
|
||||
*/
|
||||
wint_t putwchar(wchar_t wc) { return fputwc(wc, stdout); }
|
||||
wint_t putwchar(wchar_t wc) {
|
||||
return fputwc(wc, stdout);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* Like fseek(), this function can be used to restore a stream from the
|
||||
* EOF state, without reopening it.
|
||||
*/
|
||||
void rewind(FILE *stream) {
|
||||
fseek(stream, 0, SEEK_SET);
|
||||
void rewind(FILE *f) {
|
||||
fseek(f, 0, SEEK_SET);
|
||||
f->state = 0;
|
||||
}
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Sets buffer on stdio stream.
|
||||
*/
|
||||
void setbuf(FILE *f, char *buf) { setbuffer(f, buf, BUFSIZ); }
|
||||
void setbuf(FILE *f, char *buf) {
|
||||
setvbuf(f, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
|
||||
}
|
||||
|
|
|
@ -16,20 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Sets buffer on stdio stream.
|
||||
*
|
||||
* @param buf may optionally be non-NULL to set the stream's underlying
|
||||
* buffer, which the stream will own, but won't free
|
||||
* @param size is ignored if buf is NULL
|
||||
*/
|
||||
void setbuffer(FILE *f, char *buf, size_t size) {
|
||||
if (buf && f->buf != (unsigned char *)buf) {
|
||||
free_s(&f->buf);
|
||||
if (!size) size = BUFSIZ;
|
||||
f->buf = (unsigned char *)buf;
|
||||
}
|
||||
if (size) {
|
||||
f->size = size;
|
||||
}
|
||||
setvbuf(f, buf, buf ? _IOFBF : _IONBF, size);
|
||||
}
|
||||
|
|
27
libc/stdio/setlinebuf.c
Normal file
27
libc/stdio/setlinebuf.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Puts stream in line-buffering mode.
|
||||
*/
|
||||
void setlinebuf(FILE *f) {
|
||||
setvbuf(f, NULL, _IOLBF, 0);
|
||||
}
|
|
@ -24,12 +24,19 @@
|
|||
*
|
||||
* @param mode may be _IOFBF, _IOLBF, or _IONBF
|
||||
* @param buf may optionally be non-NULL to set the stream's underlying
|
||||
* buffer, which the stream will own, but won't free
|
||||
* @param size must be a two power if buf is provided
|
||||
* buffer, which the stream will own, but won't free, otherwise the
|
||||
* existing buffer is used
|
||||
* @param size is ignored if buf is NULL
|
||||
* @return 0 on success or -1 on error
|
||||
*/
|
||||
int setvbuf(FILE *f, char *buf, int mode, size_t size) {
|
||||
setbuffer(f, buf, size);
|
||||
if (buf) {
|
||||
if (!size) size = BUFSIZ;
|
||||
if (!f->nofree && f->buf != buf) free_s(&f->buf);
|
||||
f->buf = buf;
|
||||
f->size = size;
|
||||
f->nofree = true;
|
||||
}
|
||||
f->bufmode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,5 +18,5 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/internal.h"
|
||||
|
||||
unsigned char g_stdoutbuf[BUFSIZ] hidden;
|
||||
unsigned char g_stderrbuf[BUFSIZ] hidden;
|
||||
char g_stdoutbuf[BUFSIZ] hidden;
|
||||
char g_stderrbuf[BUFSIZ] hidden;
|
||||
|
|
|
@ -34,8 +34,5 @@
|
|||
ezlea __stderr_buf,cx
|
||||
mov %rcx,24(%rax) #→ f.buf
|
||||
movl $BUFSIZ,32(%rax) #→ f.size
|
||||
ezlea __fwritebuf,cx
|
||||
mov %rcx,%rdx
|
||||
mov %rdx,48(%rax) #→ f.writer
|
||||
mov %rax,stderr(%rip)
|
||||
.init.end 400,_init_stderr,globl,hidden
|
||||
|
|
|
@ -30,8 +30,5 @@
|
|||
ezlea __stdin_buf,cx
|
||||
mov %rcx,24(%rax) #→ f.buf
|
||||
movl $BUFSIZ,32(%rax) #→ f.size
|
||||
ezlea __freadbuf,cx
|
||||
mov %rcx,%rdx
|
||||
mov %rdx,40(%rax) #→ f.reader
|
||||
mov %rax,stdin(%rip)
|
||||
.init.end 400,_init_stdin,globl,hidden
|
||||
|
|
|
@ -13,19 +13,17 @@ COSMOPOLITAN_C_START_
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
typedef struct FILE {
|
||||
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
|
||||
bool noclose; /* 0x01 for fake dup() */
|
||||
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
|
||||
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
|
||||
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */
|
||||
uint32_t beg; /* 0x10 */
|
||||
uint32_t end; /* 0x14 */
|
||||
uint8_t *buf; /* 0x18 */
|
||||
uint32_t size; /* 0x20 */
|
||||
uint32_t nofree; /* 0x24 */
|
||||
int (*reader)(struct FILE *); /* 0x28 */
|
||||
int (*writer)(struct FILE *); /* 0x30 */
|
||||
int pid; /* 0x34 */
|
||||
uint8_t bufmode; /* 0x00 _IOFBF, etc. (ignored if fd=-1) */
|
||||
bool noclose; /* 0x01 for fake dup() */
|
||||
uint32_t iomode; /* 0x04 O_RDONLY, etc. (ignored if fd=-1) */
|
||||
int32_t state; /* 0x08 0=OK, -1=EOF, >0=errno */
|
||||
int fd; /* 0x0c ≥0=fd, -1=closed|buffer */
|
||||
uint32_t beg; /* 0x10 */
|
||||
uint32_t end; /* 0x14 */
|
||||
char *buf; /* 0x18 */
|
||||
uint32_t size; /* 0x20 */
|
||||
uint32_t nofree; /* 0x24 */
|
||||
int pid; /* 0x28 */
|
||||
} FILE;
|
||||
|
||||
extern FILE *stdin;
|
||||
|
@ -46,10 +44,13 @@ int fputs(const char *, FILE *) paramsnonnull();
|
|||
int fputws(const wchar_t *, FILE *) paramsnonnull();
|
||||
char *fgets(char *, int, FILE *) paramsnonnull();
|
||||
wchar_t *fgetws(wchar_t *, int, FILE *) paramsnonnull();
|
||||
wint_t putwc(wchar_t, FILE *) paramsnonnull();
|
||||
wint_t fputwc(wchar_t, FILE *) paramsnonnull();
|
||||
wint_t putwchar(wchar_t);
|
||||
wint_t getwchar(void);
|
||||
wint_t getwc(FILE *) paramsnonnull();
|
||||
wint_t fgetwc(FILE *) paramsnonnull();
|
||||
wint_t ungetwc(wint_t, FILE *) paramsnonnull();
|
||||
int getchar(void);
|
||||
int putchar(int);
|
||||
int puts(const char *) paramsnonnull();
|
||||
|
@ -59,12 +60,14 @@ FILE *fopen(const char *, const char *) paramsnonnull() nodiscard;
|
|||
FILE *fdopen(int, const char *) paramsnonnull() nodiscard;
|
||||
FILE *fmemopen(void *, size_t, const char *) paramsnonnull((3)) nodiscard;
|
||||
FILE *freopen(const char *, const char *, FILE *) paramsnonnull((2, 3));
|
||||
size_t fread(void *, size_t, size_t, FILE *) paramsnonnull();
|
||||
size_t fwrite(const void *, size_t, size_t, FILE *) paramsnonnull();
|
||||
size_t fread(void *, size_t, size_t, FILE *) paramsnonnull((4));
|
||||
size_t fwrite(const void *, size_t, size_t, FILE *) paramsnonnull((4));
|
||||
int fclose(FILE *);
|
||||
int fclose_s(FILE **) paramsnonnull();
|
||||
long fseek(FILE *, long, int) paramsnonnull();
|
||||
int fseek(FILE *, long, int) paramsnonnull();
|
||||
long ftell(FILE *) paramsnonnull();
|
||||
int fseeko(FILE *, int64_t, int) paramsnonnull();
|
||||
int64_t ftello(FILE *) paramsnonnull();
|
||||
void rewind(FILE *) paramsnonnull();
|
||||
int fopenflags(const char *) paramsnonnull();
|
||||
void setbuf(FILE *, char *);
|
||||
|
@ -77,8 +80,6 @@ typedef uint64_t fpos_t;
|
|||
compatfn char *gets(char *) paramsnonnull();
|
||||
compatfn int fgetpos(FILE *, fpos_t *) paramsnonnull();
|
||||
compatfn int fsetpos(FILE *, const fpos_t *) paramsnonnull();
|
||||
compatfn int64_t fseeko(FILE *, long, int) paramsnonnull();
|
||||
compatfn int64_t ftello(FILE *) paramsnonnull();
|
||||
|
||||
int system(const char *);
|
||||
int systemexec(const char *);
|
||||
|
@ -102,8 +103,10 @@ int vfscanf(FILE *, const char *, va_list);
|
|||
│ cosmopolitan § standard i/o » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define getc(f) fgetc(f)
|
||||
#define putc(c, f) fputc(c, f)
|
||||
#define getc(f) fgetc(f)
|
||||
#define getwc(f) fgetwc(f)
|
||||
#define putc(c, f) fputc(c, f)
|
||||
#define putwc(c, f) fputwc(c, f)
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)
|
||||
|
|
|
@ -32,8 +32,5 @@
|
|||
ezlea __stdout_buf,cx
|
||||
mov %rcx,24(%rax) #→ f.buf
|
||||
movl $BUFSIZ,32(%rax) #→ f.size
|
||||
ezlea __fwritebuf,cx
|
||||
mov %rcx,%rdx
|
||||
mov %rdx,48(%rax) #→ f.writer
|
||||
mov %rax,stdout(%rip)
|
||||
.init.end 400,_init_stdout,globl,hidden
|
||||
|
|
|
@ -17,13 +17,20 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Pushes 𝑐 back to stream.
|
||||
* Pushes byte back to stream.
|
||||
*/
|
||||
int ungetc(int c, FILE *f) {
|
||||
uint32_t i;
|
||||
if (c == -1) return c;
|
||||
if (f->beg) f->buf[--f->beg] = c;
|
||||
return c;
|
||||
if (c == -1) return -1;
|
||||
if (f->beg) {
|
||||
f->buf[--f->beg] = c;
|
||||
} else if (f->end < f->size) {
|
||||
memmove(f->buf + 1, f->buf, f->end++);
|
||||
f->buf[0] = c;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return c & 0xff;
|
||||
}
|
||||
|
|
|
@ -16,22 +16,32 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
|
||||
int __fwritebuf(FILE *f) {
|
||||
ssize_t wrote;
|
||||
if ((wrote = write(f->fd, f->buf, f->beg)) == -1) {
|
||||
if (errno == EINTR) return 0;
|
||||
return __fseterrno(f);
|
||||
}
|
||||
if (wrote == f->beg) {
|
||||
f->beg = 0;
|
||||
/**
|
||||
* Pushes wide character back to stream.
|
||||
*/
|
||||
wint_t ungetwc(wint_t c, FILE *f) {
|
||||
char b[6];
|
||||
unsigned n;
|
||||
uint64_t w;
|
||||
if (c == -1) return -1;
|
||||
n = 0;
|
||||
w = tpenc(c);
|
||||
do {
|
||||
b[n++] = w;
|
||||
} while ((w >>= 8));
|
||||
if (f->beg >= n) {
|
||||
f->beg -= n;
|
||||
memcpy(f->buf + f->beg, b, n);
|
||||
} else if (f->beg + f->end + n <= f->size) {
|
||||
memmove(f->buf + f->beg + n, f->buf + f->beg, f->end - f->beg);
|
||||
memcpy(f->buf + f->beg, b, n);
|
||||
f->end += n;
|
||||
} else {
|
||||
memcpy(f->buf, f->buf + wrote, f->beg - wrote);
|
||||
f->beg -= wrote;
|
||||
return -1;
|
||||
}
|
||||
return wrote;
|
||||
return c;
|
||||
}
|
|
@ -60,9 +60,10 @@ axdx_t tprecode8to16(char16_t *dst, size_t dstsize, const char *src) {
|
|||
r.ax = 0;
|
||||
r.dx = 0;
|
||||
for (;;) {
|
||||
if (!IsTiny() && !((uintptr_t)(src + r.dx) & 15)) {
|
||||
tprecode8to16_sse2(dst, dstsize, src, r);
|
||||
}
|
||||
/* TODO(jart): Why is it now so much slower refactored? */
|
||||
/* if (!IsTiny() && !((uintptr_t)(src + r.dx) & 15)) { */
|
||||
/* tprecode8to16_sse2(dst, dstsize, src, r); */
|
||||
/* } */
|
||||
x = src[r.dx++] & 0xff;
|
||||
if (ThomPikeCont(x)) continue;
|
||||
if (!isascii(x)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue