1570af302Sopenharmony_ci#include "stdio_impl.h" 2570af302Sopenharmony_ci#include <errno.h> 3570af302Sopenharmony_ci#include <string.h> 4570af302Sopenharmony_ci#include <stdlib.h> 5570af302Sopenharmony_ci#include <stddef.h> 6570af302Sopenharmony_ci#include <inttypes.h> 7570af302Sopenharmony_ci#include "libc.h" 8570af302Sopenharmony_ci 9570af302Sopenharmony_cistruct cookie { 10570af302Sopenharmony_ci size_t pos, len, size; 11570af302Sopenharmony_ci unsigned char *buf; 12570af302Sopenharmony_ci int mode; 13570af302Sopenharmony_ci}; 14570af302Sopenharmony_ci 15570af302Sopenharmony_cistruct mem_FILE { 16570af302Sopenharmony_ci FILE f; 17570af302Sopenharmony_ci struct cookie c; 18570af302Sopenharmony_ci unsigned char buf[UNGET+BUFSIZ], buf2[]; 19570af302Sopenharmony_ci}; 20570af302Sopenharmony_ci 21570af302Sopenharmony_cistatic off_t mseek(FILE *f, off_t off, int whence) 22570af302Sopenharmony_ci{ 23570af302Sopenharmony_ci ssize_t base; 24570af302Sopenharmony_ci struct cookie *c = f->cookie; 25570af302Sopenharmony_ci if (whence>2U) { 26570af302Sopenharmony_cifail: 27570af302Sopenharmony_ci errno = EINVAL; 28570af302Sopenharmony_ci return -1; 29570af302Sopenharmony_ci } 30570af302Sopenharmony_ci base = (size_t [3]){0, c->pos, c->len}[whence]; 31570af302Sopenharmony_ci if (off < -base || off > (ssize_t)c->size-base) goto fail; 32570af302Sopenharmony_ci return c->pos = base+off; 33570af302Sopenharmony_ci} 34570af302Sopenharmony_ci 35570af302Sopenharmony_cistatic size_t mread(FILE *f, unsigned char *buf, size_t len) 36570af302Sopenharmony_ci{ 37570af302Sopenharmony_ci struct cookie *c = f->cookie; 38570af302Sopenharmony_ci size_t rem = c->len - c->pos; 39570af302Sopenharmony_ci if (c->pos > c->len) rem = 0; 40570af302Sopenharmony_ci if (len > rem) { 41570af302Sopenharmony_ci len = rem; 42570af302Sopenharmony_ci f->flags |= F_EOF; 43570af302Sopenharmony_ci } 44570af302Sopenharmony_ci memcpy(buf, c->buf+c->pos, len); 45570af302Sopenharmony_ci c->pos += len; 46570af302Sopenharmony_ci rem -= len; 47570af302Sopenharmony_ci if (rem > f->buf_size) rem = f->buf_size; 48570af302Sopenharmony_ci f->rpos = f->buf; 49570af302Sopenharmony_ci f->rend = f->buf + rem; 50570af302Sopenharmony_ci memcpy(f->rpos, c->buf+c->pos, rem); 51570af302Sopenharmony_ci c->pos += rem; 52570af302Sopenharmony_ci return len; 53570af302Sopenharmony_ci} 54570af302Sopenharmony_ci 55570af302Sopenharmony_cistatic size_t mwrite(FILE *f, const unsigned char *buf, size_t len) 56570af302Sopenharmony_ci{ 57570af302Sopenharmony_ci struct cookie *c = f->cookie; 58570af302Sopenharmony_ci size_t rem; 59570af302Sopenharmony_ci size_t len2 = f->wpos - f->wbase; 60570af302Sopenharmony_ci if (len2) { 61570af302Sopenharmony_ci f->wpos = f->wbase; 62570af302Sopenharmony_ci if (mwrite(f, f->wpos, len2) < len2) return 0; 63570af302Sopenharmony_ci } 64570af302Sopenharmony_ci if (c->mode == 'a') c->pos = c->len; 65570af302Sopenharmony_ci rem = c->size - c->pos; 66570af302Sopenharmony_ci if (len > rem) len = rem; 67570af302Sopenharmony_ci memcpy(c->buf+c->pos, buf, len); 68570af302Sopenharmony_ci c->pos += len; 69570af302Sopenharmony_ci if (c->pos > c->len) { 70570af302Sopenharmony_ci c->len = c->pos; 71570af302Sopenharmony_ci if (c->len < c->size) c->buf[c->len] = 0; 72570af302Sopenharmony_ci else if ((f->flags&F_NORD) && c->size) c->buf[c->size-1] = 0; 73570af302Sopenharmony_ci } 74570af302Sopenharmony_ci return len; 75570af302Sopenharmony_ci} 76570af302Sopenharmony_ci 77570af302Sopenharmony_cistatic int mclose(FILE *m) 78570af302Sopenharmony_ci{ 79570af302Sopenharmony_ci return 0; 80570af302Sopenharmony_ci} 81570af302Sopenharmony_ci 82570af302Sopenharmony_ciFILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode) 83570af302Sopenharmony_ci{ 84570af302Sopenharmony_ci struct mem_FILE *f; 85570af302Sopenharmony_ci int plus = !!strchr(mode, '+'); 86570af302Sopenharmony_ci 87570af302Sopenharmony_ci if (!strchr("rwa", *mode)) { 88570af302Sopenharmony_ci errno = EINVAL; 89570af302Sopenharmony_ci return 0; 90570af302Sopenharmony_ci } 91570af302Sopenharmony_ci 92570af302Sopenharmony_ci if (!buf && size > PTRDIFF_MAX) { 93570af302Sopenharmony_ci errno = ENOMEM; 94570af302Sopenharmony_ci return 0; 95570af302Sopenharmony_ci } 96570af302Sopenharmony_ci 97570af302Sopenharmony_ci f = malloc(sizeof *f + (buf?0:size)); 98570af302Sopenharmony_ci if (!f) return 0; 99570af302Sopenharmony_ci memset(f, 0, offsetof(struct mem_FILE, buf)); 100570af302Sopenharmony_ci f->f.cookie = &f->c; 101570af302Sopenharmony_ci f->f.fd = -1; 102570af302Sopenharmony_ci f->f.lbf = EOF; 103570af302Sopenharmony_ci f->f.buf = f->buf + UNGET; 104570af302Sopenharmony_ci f->f.buf_size = sizeof f->buf - UNGET; 105570af302Sopenharmony_ci if (!buf) { 106570af302Sopenharmony_ci buf = f->buf2; 107570af302Sopenharmony_ci memset(buf, 0, size); 108570af302Sopenharmony_ci } 109570af302Sopenharmony_ci 110570af302Sopenharmony_ci f->c.buf = buf; 111570af302Sopenharmony_ci f->c.size = size; 112570af302Sopenharmony_ci f->c.mode = *mode; 113570af302Sopenharmony_ci 114570af302Sopenharmony_ci if (!plus) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD; 115570af302Sopenharmony_ci if (*mode == 'r') f->c.len = size; 116570af302Sopenharmony_ci else if (*mode == 'a') f->c.len = f->c.pos = strnlen(buf, size); 117570af302Sopenharmony_ci else if (plus) *f->c.buf = 0; 118570af302Sopenharmony_ci 119570af302Sopenharmony_ci f->f.read = mread; 120570af302Sopenharmony_ci f->f.readx = mread; 121570af302Sopenharmony_ci f->f.write = mwrite; 122570af302Sopenharmony_ci f->f.seek = mseek; 123570af302Sopenharmony_ci f->f.close = mclose; 124570af302Sopenharmony_ci 125570af302Sopenharmony_ci if (!libc.threaded) f->f.lock = -1; 126570af302Sopenharmony_ci 127570af302Sopenharmony_ci return __ofl_add(&f->f); 128570af302Sopenharmony_ci} 129