mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-01 19:24:49 +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->bufmode = ischardev(fd) ? _IOLBF : _IOFBF;
|
||||||
f->iomode = fopenflags(mode);
|
f->iomode = fopenflags(mode);
|
||||||
f->size = BUFSIZ;
|
f->size = BUFSIZ;
|
||||||
if ((f->buf = valloc(f->size))) {
|
if ((f->buf = malloc(f->size))) {
|
||||||
if ((f->iomode & O_ACCMODE) != O_RDONLY) {
|
if ((f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||||
__fflush_register(f);
|
__fflush_register(f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,9 +50,11 @@ int fflush(FILE *f) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (f->fd != -1) {
|
} else if (f->fd != -1) {
|
||||||
while (!f->state && f->beg && !f->end) {
|
while (f->beg && !f->end) {
|
||||||
if ((wrote = __fwritebuf(f)) != -1) {
|
if ((wrote = __fwritebuf(f)) != -1) {
|
||||||
res += wrote;
|
res += wrote;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (f->beg && f->beg < f->size) {
|
} else if (f->beg && f->beg < f->size) {
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/popcnt.h"
|
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
|
@ -16,29 +16,32 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/stdio/stdio.h"
|
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns stdio flags description string into bitmask.
|
* Turns stdio flags description string into bitmask.
|
||||||
*/
|
*/
|
||||||
int fopenflags(const char *mode) {
|
int fopenflags(const char *mode) {
|
||||||
unsigned flags = 0;
|
unsigned omode, flags;
|
||||||
|
omode = flags = 0;
|
||||||
do {
|
do {
|
||||||
if (*mode == 'r') {
|
if (*mode == 'r') {
|
||||||
flags |= O_RDONLY;
|
omode = O_RDONLY;
|
||||||
} else if (*mode == 'w') {
|
} else if (*mode == 'w') {
|
||||||
flags |= O_WRONLY | O_CREAT | O_TRUNC;
|
omode = O_WRONLY;
|
||||||
|
flags |= O_CREAT | O_TRUNC;
|
||||||
} else if (*mode == 'a') {
|
} else if (*mode == 'a') {
|
||||||
flags |= O_WRONLY | O_CREAT | O_APPEND;
|
omode = O_WRONLY;
|
||||||
|
flags |= O_CREAT | O_APPEND;
|
||||||
} else if (*mode == '+') {
|
} else if (*mode == '+') {
|
||||||
flags |= O_RDWR;
|
omode = O_RDWR;
|
||||||
} else if (*mode == 'x') {
|
} else if (*mode == 'x') {
|
||||||
flags |= O_EXCL;
|
flags |= O_EXCL;
|
||||||
} else if (*mode == 'e') {
|
} else if (*mode == 'e') {
|
||||||
flags |= O_CLOEXEC;
|
flags |= O_CLOEXEC;
|
||||||
}
|
}
|
||||||
} while (*mode++);
|
} while (*mode++);
|
||||||
return flags;
|
return omode | flags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,25 +17,10 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/stdio/internal.h"
|
#include "libc/stdio/internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/sysv/consts/o.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes byte to stream.
|
* Writes byte to stream.
|
||||||
|
@ -43,10 +28,22 @@ static noinstrument noinline int __fputc(int c, FILE *f) {
|
||||||
* @see putc() if called within loop
|
* @see putc() if called within loop
|
||||||
*/
|
*/
|
||||||
noinstrument int fputc(int c, FILE *f) {
|
noinstrument int fputc(int c, FILE *f) {
|
||||||
if (f->beg + 1 < f->size && f->bufmode == _IOFBF) {
|
if ((f->iomode & O_ACCMODE) != O_RDONLY) {
|
||||||
f->buf[f->beg++] = c;
|
if (f->beg < f->size) {
|
||||||
return c & 0xff;
|
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 {
|
} 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
|
* @returns new offset or -1 on error
|
||||||
*/
|
*/
|
||||||
long fseek(FILE *f, long offset, int whence) {
|
long fseek(FILE *f, long offset, int whence) {
|
||||||
int skew;
|
int64_t pos;
|
||||||
int64_t newpos;
|
|
||||||
if (f->fd != -1) {
|
if (f->fd != -1) {
|
||||||
if (whence == SEEK_CUR && f->beg < f->end) {
|
if (whence == SEEK_CUR && f->beg < f->end) {
|
||||||
offset -= f->end - f->beg;
|
offset -= f->end - f->beg;
|
||||||
|
@ -44,17 +43,17 @@ long fseek(FILE *f, long offset, int whence) {
|
||||||
if (f->beg && !f->end) {
|
if (f->beg && !f->end) {
|
||||||
f->writer(f);
|
f->writer(f);
|
||||||
}
|
}
|
||||||
if ((newpos = lseek(f->fd, offset, whence)) != -1) {
|
if (lseek(f->fd, offset, whence) != -1) {
|
||||||
f->state = 0;
|
f->state = 0;
|
||||||
f->beg = 0;
|
f->beg = 0;
|
||||||
f->end = 0;
|
f->end = 0;
|
||||||
return newpos;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
f->state = errno == ESPIPE ? EBADF : errno;
|
f->state = errno == ESPIPE ? EBADF : errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
f->beg = offset % f->size;
|
f->beg = (offset & 0xffffffff) % f->size;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,6 +26,23 @@
|
||||||
* @param stream is a non-null stream handle
|
* @param stream is a non-null stream handle
|
||||||
* @returns current byte offset from beginning of file, or -1
|
* @returns current byte offset from beginning of file, or -1
|
||||||
*/
|
*/
|
||||||
long ftell(FILE *stream) {
|
long ftell(FILE *f) {
|
||||||
return fseek(stream, 0, SEEK_CUR);
|
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.
|
* Writes data to stream.
|
||||||
*
|
*
|
||||||
* @param stride specifies the size of individual items
|
* @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
|
* @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 fwrite(const void *data, size_t stride, size_t count, FILE *f) {
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
const unsigned char *p;
|
const unsigned char *p;
|
||||||
for (n = stride * count, p = data, i = 0; i < n; ++i) {
|
for (n = stride * count, p = data, i = 0; i < n; ++i) {
|
||||||
if (fputc(p[i], f) == -1) {
|
if (fputc(p[i], f) == -1) return -1;
|
||||||
if (!(i % stride)) {
|
|
||||||
return i / stride;
|
|
||||||
} else {
|
|
||||||
return __fseterr(f, EOVERFLOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/popcnt.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
@ -25,7 +24,6 @@
|
||||||
* Sets buffer on stdio stream.
|
* Sets buffer on stdio stream.
|
||||||
*/
|
*/
|
||||||
void setbuffer(FILE *f, char *buf, size_t size) {
|
void setbuffer(FILE *f, char *buf, size_t size) {
|
||||||
if (size && popcnt(size) != 1) abort();
|
|
||||||
if (buf && f->buf != (unsigned char *)buf) {
|
if (buf && f->buf != (unsigned char *)buf) {
|
||||||
free_s(&f->buf);
|
free_s(&f->buf);
|
||||||
if (!size) size = BUFSIZ;
|
if (!size) size = BUFSIZ;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/popcnt.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
@ -30,7 +29,6 @@
|
||||||
* @return 0 on success or -1 on error
|
* @return 0 on success or -1 on error
|
||||||
*/
|
*/
|
||||||
int setvbuf(FILE *f, char *buf, int mode, size_t size) {
|
int setvbuf(FILE *f, char *buf, int mode, size_t size) {
|
||||||
if (size && popcnt(size) != 1) return einval();
|
|
||||||
setbuffer(f, buf, size);
|
setbuffer(f, buf, size);
|
||||||
f->bufmode = mode;
|
f->bufmode = mode;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -67,7 +67,6 @@ long fseek(FILE *, long, int) paramsnonnull();
|
||||||
long ftell(FILE *) paramsnonnull();
|
long ftell(FILE *) paramsnonnull();
|
||||||
void rewind(FILE *) paramsnonnull();
|
void rewind(FILE *) paramsnonnull();
|
||||||
int fopenflags(const char *) paramsnonnull();
|
int fopenflags(const char *) paramsnonnull();
|
||||||
unsigned favail(FILE *);
|
|
||||||
void setbuf(FILE *, char *);
|
void setbuf(FILE *, char *);
|
||||||
void setbuffer(FILE *, char *, size_t);
|
void setbuffer(FILE *, char *, size_t);
|
||||||
int setvbuf(FILE *, char *, int, size_t);
|
int setvbuf(FILE *, char *, int, size_t);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
*/
|
*/
|
||||||
FILE *tmpfile(void) {
|
FILE *tmpfile(void) {
|
||||||
int fd;
|
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+");
|
return fdopen(fd, "w+");
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,12 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes 𝑐 back to stream.
|
||||||
|
*/
|
||||||
int ungetc(int c, FILE *f) {
|
int ungetc(int c, FILE *f) {
|
||||||
f->beg = (f->beg - 1) & (f->size - 1);
|
uint32_t i;
|
||||||
f->buf[f->beg] = c;
|
if (c == -1) return c;
|
||||||
|
if (f->beg) f->buf[--f->beg] = c;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "libc/unicode/locale.h"
|
#include "libc/unicode/locale.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,5 +26,10 @@
|
||||||
* Cosmopolitan only supports the C or POSIX locale.
|
* Cosmopolitan only supports the C or POSIX locale.
|
||||||
*/
|
*/
|
||||||
char *setlocale(int category, const char *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 -*-│
|
/*-*- 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│
|
│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 │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ 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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/bits/popcnt.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
unsigned naive(unsigned beg, unsigned end, unsigned size) {
|
char testlib_enable_tmp_setup_teardown;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned fancy(unsigned beg, unsigned end, unsigned size) {
|
TEST(fwrite, test) {
|
||||||
return ((end - beg - 1) & (size - 1)) + 1;
|
FILE *f;
|
||||||
}
|
char buf[512];
|
||||||
|
|
||||||
TEST(favail, test) {
|
ASSERT_NE(NULL, (f = fopen("hog", "wb")));
|
||||||
unsigned i, j, n = 4;
|
EXPECT_EQ(-1, fgetc(f));
|
||||||
for (i = 0; i < n; ++i) {
|
EXPECT_EQ(5, fwrite("hello", 1, 5, f));
|
||||||
for (j = 0; j < n; ++j) {
|
EXPECT_EQ(5, ftell(f));
|
||||||
ASSERT_EQ(naive(i, j, n), fancy(i, j, n), "%u %u %u", i, j, n);
|
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…
Add table
Reference in a new issue