mirror of
https://github.com/fluencelabs/musl
synced 2025-05-28 07:01:35 +00:00
functions which open in-memory FILE stream variants all shared a tail with __fdopen, adding the FILE structure to stdio's open file list. replacing this common tail with a function call reduces code size and duplication of logic. the list is also partially encapsulated now. function signatures were chosen to facilitate tail call optimization and reduce the need for additional accessor functions. with these changes, static linked programs that do not use stdio no longer have an open file list at all.
115 lines
2.3 KiB
C
115 lines
2.3 KiB
C
#include "stdio_impl.h"
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
struct cookie {
|
|
size_t pos, len, size;
|
|
unsigned char *buf;
|
|
int mode;
|
|
};
|
|
|
|
static off_t mseek(FILE *f, off_t off, int whence)
|
|
{
|
|
ssize_t base;
|
|
struct cookie *c = f->cookie;
|
|
if (whence>2U) {
|
|
fail:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
base = (size_t [3]){0, c->pos, c->len}[whence];
|
|
if (off < -base || off > (ssize_t)c->size-base) goto fail;
|
|
return c->pos = base+off;
|
|
}
|
|
|
|
static size_t mread(FILE *f, unsigned char *buf, size_t len)
|
|
{
|
|
struct cookie *c = f->cookie;
|
|
size_t rem = c->len - c->pos;
|
|
if (c->pos > c->len) rem = 0;
|
|
if (len > rem) {
|
|
len = rem;
|
|
f->flags |= F_EOF;
|
|
}
|
|
memcpy(buf, c->buf+c->pos, len);
|
|
c->pos += len;
|
|
rem -= len;
|
|
if (rem > f->buf_size) rem = f->buf_size;
|
|
f->rpos = f->buf;
|
|
f->rend = f->buf + rem;
|
|
memcpy(f->rpos, c->buf+c->pos, rem);
|
|
c->pos += rem;
|
|
return len;
|
|
}
|
|
|
|
static size_t mwrite(FILE *f, const unsigned char *buf, size_t len)
|
|
{
|
|
struct cookie *c = f->cookie;
|
|
size_t rem;
|
|
size_t len2 = f->wpos - f->wbase;
|
|
if (len2) {
|
|
f->wpos = f->wbase;
|
|
if (mwrite(f, f->wpos, len2) < len2) return 0;
|
|
}
|
|
if (c->mode == 'a') c->pos = c->len;
|
|
rem = c->size - c->pos;
|
|
if (len > rem) len = rem;
|
|
memcpy(c->buf+c->pos, buf, len);
|
|
c->pos += len;
|
|
if (c->pos > c->len) {
|
|
c->len = c->pos;
|
|
if (c->len < c->size) c->buf[c->len] = 0;
|
|
else if ((f->flags&F_NORD) && c->size) c->buf[c->size-1] = 0;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static int mclose(FILE *m)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode)
|
|
{
|
|
FILE *f;
|
|
struct cookie *c;
|
|
int plus = !!strchr(mode, '+');
|
|
|
|
if (!size || !strchr("rwa", *mode)) {
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
if (!buf && size > SIZE_MAX-sizeof(FILE)-BUFSIZ-UNGET) {
|
|
errno = ENOMEM;
|
|
return 0;
|
|
}
|
|
|
|
f = calloc(sizeof *f + sizeof *c + UNGET + BUFSIZ + (buf?0:size), 1);
|
|
if (!f) return 0;
|
|
f->cookie = c = (void *)(f+1);
|
|
f->fd = -1;
|
|
f->lbf = EOF;
|
|
f->buf = (unsigned char *)(c+1) + UNGET;
|
|
f->buf_size = BUFSIZ;
|
|
if (!buf) buf = f->buf + BUFSIZ;
|
|
|
|
c->buf = buf;
|
|
c->size = size;
|
|
c->mode = *mode;
|
|
|
|
if (!plus) f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
|
|
if (*mode == 'r') c->len = size;
|
|
else if (*mode == 'a') c->len = c->pos = strnlen(buf, size);
|
|
|
|
f->read = mread;
|
|
f->write = mwrite;
|
|
f->seek = mseek;
|
|
f->close = mclose;
|
|
|
|
if (!libc.threaded) f->lock = -1;
|
|
|
|
return __ofl_add(f);
|
|
}
|