Fix issues with stdio needed for Lua

See #61
This commit is contained in:
Justine Tunney
2021-03-06 16:06:15 -08:00
parent c3ed8d6c7f
commit d769df3482
17 changed files with 102 additions and 155 deletions

View File

@ -1,28 +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 │
│ │
│ 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"
/* TODO(jart): Delete or rework */
/**
* Returns number of bytes available in stream buffer.
*/
unsigned favail(FILE *f) {
return ((f->end - f->beg - 1) & (f->size - 1)) + 1;
}

View File

@ -40,7 +40,7 @@ FILE *fdopen(int fd, const char *mode) {
f->bufmode = ischardev(fd) ? _IOLBF : _IOFBF;
f->iomode = fopenflags(mode);
f->size = BUFSIZ;
if ((f->buf = valloc(f->size))) {
if ((f->buf = malloc(f->size))) {
if ((f->iomode & O_ACCMODE) != O_RDONLY) {
__fflush_register(f);
}

View File

@ -50,9 +50,11 @@ int fflush(FILE *f) {
}
}
} else if (f->fd != -1) {
while (!f->state && f->beg && !f->end) {
while (f->beg && !f->end) {
if ((wrote = __fwritebuf(f)) != -1) {
res += wrote;
} else {
break;
}
}
} else if (f->beg && f->beg < f->size) {

View File

@ -16,7 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/popcnt.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"

View File

@ -16,29 +16,32 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/stdio/stdio.h"
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
/**
* Turns stdio flags description string into bitmask.
*/
int fopenflags(const char *mode) {
unsigned flags = 0;
unsigned omode, flags;
omode = flags = 0;
do {
if (*mode == 'r') {
flags |= O_RDONLY;
omode = O_RDONLY;
} else if (*mode == 'w') {
flags |= O_WRONLY | O_CREAT | O_TRUNC;
omode = O_WRONLY;
flags |= O_CREAT | O_TRUNC;
} else if (*mode == 'a') {
flags |= O_WRONLY | O_CREAT | O_APPEND;
omode = O_WRONLY;
flags |= O_CREAT | O_APPEND;
} else if (*mode == '+') {
flags |= O_RDWR;
omode = O_RDWR;
} else if (*mode == 'x') {
flags |= O_EXCL;
} else if (*mode == 'e') {
flags |= O_CLOEXEC;
}
} while (*mode++);
return flags;
return omode | flags;
}

View File

@ -17,10 +17,18 @@
│ 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"
static noinstrument noinline int __fputc(int c, FILE *f) {
/**
* Writes byte to stream.
* @return c (as unsigned char) if written or -1 w/ errno
* @see putc() if called within loop
*/
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 ||
@ -35,18 +43,7 @@ static noinstrument noinline int __fputc(int c, FILE *f) {
} else {
return __fseteof(f);
}
}
/**
* Writes byte to stream.
* @return c (as unsigned char) if written or -1 w/ errno
* @see putc() if called within loop
*/
noinstrument int fputc(int c, FILE *f) {
if (f->beg + 1 < f->size && f->bufmode == _IOFBF) {
f->buf[f->beg++] = c;
return c & 0xff;
} else {
return __fputc(c, f);
return __fseterr(f, EBADF);
}
}

View File

@ -1,52 +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 │
│ │
│ 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/internal.h"
#include "libc/stdio/stdio.h"
static noinline int slowpath(int c, FILE *f) {
if (f->beg < f->size) {
c &= 0xff;
f->buf[f->beg++] = c;
if (f->beg == f->size) {
if (f->writer) {
if (f->writer(f) == -1) return -1;
} else if (f->beg == f->size) {
f->beg = 0;
}
}
return c;
} else {
return __fseteof(f);
}
}
/**
* Writes byte to stream.
*
* @return c (as unsigned char) if written or -1 w/ errno
*/
noinstrument int fputcfb(int c, FILE *f) {
if (f->beg + 1 < f->size) {
c &= 0xff;
f->buf[f->beg++] = c;
return c;
} else {
return slowpath(c, f);
}
}

View File

@ -35,8 +35,7 @@
* @returns new offset or -1 on error
*/
long fseek(FILE *f, long offset, int whence) {
int skew;
int64_t newpos;
int64_t pos;
if (f->fd != -1) {
if (whence == SEEK_CUR && f->beg < f->end) {
offset -= f->end - f->beg;
@ -44,17 +43,17 @@ long fseek(FILE *f, long offset, int whence) {
if (f->beg && !f->end) {
f->writer(f);
}
if ((newpos = lseek(f->fd, offset, whence)) != -1) {
if (lseek(f->fd, offset, whence) != -1) {
f->state = 0;
f->beg = 0;
f->end = 0;
return newpos;
return 0;
} else {
f->state = errno == ESPIPE ? EBADF : errno;
return -1;
}
} else {
f->beg = offset % f->size;
f->beg = (offset & 0xffffffff) % f->size;
return -1;
}
}

View File

@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
/**
@ -25,6 +26,23 @@
* @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 *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;
}
}

View File

@ -25,20 +25,14 @@
* Writes data to stream.
*
* @param stride specifies the size of individual items
* @param count is the number of strides to fetch
* @param count is the number of strides to write
* @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) {
if (!(i % stride)) {
return i / stride;
} else {
return __fseterr(f, EOVERFLOW);
}
}
if (fputc(p[i], f) == -1) return -1;
}
return count;
}

View File

@ -16,7 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/popcnt.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/errfuns.h"
@ -25,7 +24,6 @@
* Sets buffer on stdio stream.
*/
void setbuffer(FILE *f, char *buf, size_t size) {
if (size && popcnt(size) != 1) abort();
if (buf && f->buf != (unsigned char *)buf) {
free_s(&f->buf);
if (!size) size = BUFSIZ;

View File

@ -16,7 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/popcnt.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/errfuns.h"
@ -30,7 +29,6 @@
* @return 0 on success or -1 on error
*/
int setvbuf(FILE *f, char *buf, int mode, size_t size) {
if (size && popcnt(size) != 1) return einval();
setbuffer(f, buf, size);
f->bufmode = mode;
return 0;

View File

@ -67,7 +67,6 @@ long fseek(FILE *, long, int) paramsnonnull();
long ftell(FILE *) paramsnonnull();
void rewind(FILE *) paramsnonnull();
int fopenflags(const char *) paramsnonnull();
unsigned favail(FILE *);
void setbuf(FILE *, char *);
void setbuffer(FILE *, char *, size_t);
int setvbuf(FILE *, char *, int, size_t);

View File

@ -28,6 +28,7 @@
*/
FILE *tmpfile(void) {
int fd;
if ((fd = mkostemps("/tmp/tmp.XXXXXX", 0, 0)) == -1) return NULL;
char template[] = "/tmp/tmp.XXXXXX";
if ((fd = mkostemps(template, 0, 0)) == -1) return NULL;
return fdopen(fd, "w+");
}

View File

@ -18,8 +18,12 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/stdio/stdio.h"
/**
* Pushes 𝑐 back to stream.
*/
int ungetc(int c, FILE *f) {
f->beg = (f->beg - 1) & (f->size - 1);
f->buf[f->beg] = c;
uint32_t i;
if (c == -1) return c;
if (f->beg) f->buf[--f->beg] = c;
return c;
}

View File

@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/safemacros.internal.h"
#include "libc/str/str.h"
#include "libc/unicode/locale.h"
/**
@ -25,5 +26,10 @@
* Cosmopolitan only supports the C or POSIX locale.
*/
char *setlocale(int category, const char *locale) {
return firstnonnull(locale, "C");
if (!locale) return "C";
if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) {
return locale;
} else {
return NULL;
}
}

View File

@ -1,7 +1,7 @@
/*-*- 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
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
@ -16,29 +16,38 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/popcnt.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
unsigned naive(unsigned beg, unsigned end, unsigned size) {
assert(end < size);
assert(beg < size);
assert(popcnt(size) == 1);
if (beg == end) return size;
if (end > beg) return end - beg;
return (size - beg) + end;
}
char testlib_enable_tmp_setup_teardown;
unsigned fancy(unsigned beg, unsigned end, unsigned size) {
return ((end - beg - 1) & (size - 1)) + 1;
}
TEST(fwrite, test) {
FILE *f;
char buf[512];
TEST(favail, test) {
unsigned i, j, n = 4;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
ASSERT_EQ(naive(i, j, n), fancy(i, j, n), "%u %u %u", i, j, n);
}
ASSERT_NE(NULL, (f = fopen("hog", "wb")));
EXPECT_EQ(-1, fgetc(f));
EXPECT_EQ(5, fwrite("hello", 1, 5, f));
EXPECT_EQ(5, ftell(f));
EXPECT_NE(-1, fclose(f));
ASSERT_NE(NULL, (f = fopen("hog", "r")));
EXPECT_EQ(-1, fwrite("hello", 1, 5, f));
EXPECT_EQ(EBADF, ferror(f));
EXPECT_NE(-1, fclose(f));
ASSERT_NE(NULL, (f = fopen("hog", "a+b")));
EXPECT_EQ(5, fwrite("hello", 1, 5, f));
EXPECT_NE(-1, fclose(f));
/* TODO(jart): O_APPEND on Windows */
if (!IsWindows()) {
ASSERT_NE(NULL, (f = fopen("hog", "r")));
EXPECT_EQ(10, fread(buf, 1, 10, f));
EXPECT_TRUE(!memcmp(buf, "hellohello", 10));
EXPECT_NE(-1, fclose(f));
}
}