]>
Commit | Line | Data |
---|---|---|
320054e8 DG |
1 | #include "stdio_impl.h" |
2 | #include <errno.h> | |
3 | #include <string.h> | |
4 | #include <stdlib.h> | |
5 | #include <inttypes.h> | |
6 | #include "libc.h" | |
7 | ||
8 | struct cookie { | |
9 | size_t pos, len, size; | |
10 | unsigned char *buf; | |
11 | int mode; | |
12 | }; | |
13 | ||
14 | struct mem_FILE { | |
15 | FILE f; | |
16 | struct cookie c; | |
17 | unsigned char buf[UNGET+BUFSIZ], buf2[]; | |
18 | }; | |
19 | ||
20 | static off_t mseek(FILE *f, off_t off, int whence) | |
21 | { | |
22 | ssize_t base; | |
23 | struct cookie *c = f->cookie; | |
24 | if (whence>2U) { | |
25 | fail: | |
26 | errno = EINVAL; | |
27 | return -1; | |
28 | } | |
29 | base = (size_t [3]){0, c->pos, c->len}[whence]; | |
30 | if (off < -base || off > (ssize_t)c->size-base) goto fail; | |
31 | return c->pos = base+off; | |
32 | } | |
33 | ||
34 | static size_t mread(FILE *f, unsigned char *buf, size_t len) | |
35 | { | |
36 | struct cookie *c = f->cookie; | |
37 | size_t rem = c->len - c->pos; | |
38 | if (c->pos > c->len) rem = 0; | |
39 | if (len > rem) { | |
40 | len = rem; | |
41 | f->flags |= F_EOF; | |
42 | } | |
43 | memcpy(buf, c->buf+c->pos, len); | |
44 | c->pos += len; | |
45 | rem -= len; | |
46 | if (rem > f->buf_size) rem = f->buf_size; | |
47 | f->rpos = f->buf; | |
48 | f->rend = f->buf + rem; | |
49 | memcpy(f->rpos, c->buf+c->pos, rem); | |
50 | c->pos += rem; | |
51 | return len; | |
52 | } | |
53 | ||
54 | static size_t mwrite(FILE *f, const unsigned char *buf, size_t len) | |
55 | { | |
56 | struct cookie *c = f->cookie; | |
57 | size_t rem; | |
58 | size_t len2 = f->wpos - f->wbase; | |
59 | if (len2) { | |
60 | f->wpos = f->wbase; | |
61 | if (mwrite(f, f->wpos, len2) < len2) return 0; | |
62 | } | |
63 | if (c->mode == 'a') c->pos = c->len; | |
64 | rem = c->size - c->pos; | |
65 | if (len > rem) len = rem; | |
66 | memcpy(c->buf+c->pos, buf, len); | |
67 | c->pos += len; | |
68 | if (c->pos > c->len) { | |
69 | c->len = c->pos; | |
70 | if (c->len < c->size) c->buf[c->len] = 0; | |
71 | else if ((f->flags&F_NORD) && c->size) c->buf[c->size-1] = 0; | |
72 | } | |
73 | return len; | |
74 | } | |
75 | ||
76 | static int mclose(FILE *m) | |
77 | { | |
78 | return 0; | |
79 | } | |
80 | ||
81 | FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode) | |
82 | { | |
83 | struct mem_FILE *f; | |
84 | int plus = !!strchr(mode, '+'); | |
85 | ||
86 | if (!size || !strchr("rwa", *mode)) { | |
87 | errno = EINVAL; | |
88 | return 0; | |
89 | } | |
90 | ||
91 | if (!buf && size > PTRDIFF_MAX) { | |
92 | errno = ENOMEM; | |
93 | return 0; | |
94 | } | |
95 | ||
96 | f = malloc(sizeof *f + (buf?0:size)); | |
97 | if (!f) return 0; | |
98 | memset(&f->f, 0, sizeof f->f); | |
99 | f->f.cookie = &f->c; | |
100 | f->f.fd = -1; | |
101 | f->f.lbf = EOF; | |
102 | f->f.buf = f->buf + UNGET; | |
103 | f->f.buf_size = sizeof f->buf - UNGET; | |
104 | if (!buf) { | |
105 | buf = f->buf2;; | |
106 | memset(buf, 0, size); | |
107 | } | |
108 | ||
109 | memset(&f->c, 0, sizeof f->c); | |
110 | f->c.buf = buf; | |
111 | f->c.size = size; | |
112 | f->c.mode = *mode; | |
113 | ||
114 | if (!plus) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD; | |
115 | if (*mode == 'r') f->c.len = size; | |
116 | else if (*mode == 'a') f->c.len = f->c.pos = strnlen(buf, size); | |
117 | else if (plus) *f->c.buf = 0; | |
118 | ||
119 | f->f.read = mread; | |
120 | f->f.write = mwrite; | |
121 | f->f.seek = mseek; | |
122 | f->f.close = mclose; | |
123 | ||
9bb4cc5c | 124 | #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) |
320054e8 | 125 | if (!libc.threaded) f->f.lock = -1; |
9bb4cc5c | 126 | #endif |
320054e8 DG |
127 | |
128 | return __ofl_add(&f->f); | |
129 | } |