mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
parent
c3ed8d6c7f
commit
d769df3482
17 changed files with 102 additions and 155 deletions
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -17,25 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
static noinstrument noinline int __fputc(int c, FILE *f) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Writes byte to stream.
|
||||
|
@ -43,10 +28,22 @@ static noinstrument noinline int __fputc(int c, FILE *f) {
|
|||
* @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;
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
return __fputc(c, f);
|
||||
return __fseterr(f, EBADF);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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+");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue