]>
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 | } | |
e369ade4 | 29 | #ifdef __wasilibc_unmodified_upstream // WASI's SEEK_* constants have different values. |
320054e8 | 30 | base = (size_t [3]){0, c->pos, c->len}[whence]; |
e369ade4 DG |
31 | #else |
32 | base = (size_t [3]) { | |
33 | [SEEK_SET] = 0, | |
34 | [SEEK_CUR] = c->pos, | |
35 | [SEEK_END] = c->len | |
36 | }[whence]; | |
37 | #endif | |
320054e8 DG |
38 | if (off < -base || off > (ssize_t)c->size-base) goto fail; |
39 | return c->pos = base+off; | |
40 | } | |
41 | ||
42 | static size_t mread(FILE *f, unsigned char *buf, size_t len) | |
43 | { | |
44 | struct cookie *c = f->cookie; | |
45 | size_t rem = c->len - c->pos; | |
46 | if (c->pos > c->len) rem = 0; | |
47 | if (len > rem) { | |
48 | len = rem; | |
49 | f->flags |= F_EOF; | |
50 | } | |
51 | memcpy(buf, c->buf+c->pos, len); | |
52 | c->pos += len; | |
53 | rem -= len; | |
54 | if (rem > f->buf_size) rem = f->buf_size; | |
55 | f->rpos = f->buf; | |
56 | f->rend = f->buf + rem; | |
57 | memcpy(f->rpos, c->buf+c->pos, rem); | |
58 | c->pos += rem; | |
59 | return len; | |
60 | } | |
61 | ||
62 | static size_t mwrite(FILE *f, const unsigned char *buf, size_t len) | |
63 | { | |
64 | struct cookie *c = f->cookie; | |
65 | size_t rem; | |
66 | size_t len2 = f->wpos - f->wbase; | |
67 | if (len2) { | |
68 | f->wpos = f->wbase; | |
69 | if (mwrite(f, f->wpos, len2) < len2) return 0; | |
70 | } | |
71 | if (c->mode == 'a') c->pos = c->len; | |
72 | rem = c->size - c->pos; | |
73 | if (len > rem) len = rem; | |
74 | memcpy(c->buf+c->pos, buf, len); | |
75 | c->pos += len; | |
76 | if (c->pos > c->len) { | |
77 | c->len = c->pos; | |
78 | if (c->len < c->size) c->buf[c->len] = 0; | |
79 | else if ((f->flags&F_NORD) && c->size) c->buf[c->size-1] = 0; | |
80 | } | |
81 | return len; | |
82 | } | |
83 | ||
84 | static int mclose(FILE *m) | |
85 | { | |
86 | return 0; | |
87 | } | |
88 | ||
89 | FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode) | |
90 | { | |
91 | struct mem_FILE *f; | |
92 | int plus = !!strchr(mode, '+'); | |
93 | ||
d4db3fa2 | 94 | if (!strchr("rwa", *mode)) { |
320054e8 DG |
95 | errno = EINVAL; |
96 | return 0; | |
97 | } | |
98 | ||
99 | if (!buf && size > PTRDIFF_MAX) { | |
100 | errno = ENOMEM; | |
101 | return 0; | |
102 | } | |
103 | ||
104 | f = malloc(sizeof *f + (buf?0:size)); | |
105 | if (!f) return 0; | |
106 | memset(&f->f, 0, sizeof f->f); | |
107 | f->f.cookie = &f->c; | |
108 | f->f.fd = -1; | |
109 | f->f.lbf = EOF; | |
110 | f->f.buf = f->buf + UNGET; | |
111 | f->f.buf_size = sizeof f->buf - UNGET; | |
112 | if (!buf) { | |
113 | buf = f->buf2;; | |
114 | memset(buf, 0, size); | |
115 | } | |
116 | ||
117 | memset(&f->c, 0, sizeof f->c); | |
118 | f->c.buf = buf; | |
119 | f->c.size = size; | |
120 | f->c.mode = *mode; | |
121 | ||
122 | if (!plus) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD; | |
123 | if (*mode == 'r') f->c.len = size; | |
124 | else if (*mode == 'a') f->c.len = f->c.pos = strnlen(buf, size); | |
125 | else if (plus) *f->c.buf = 0; | |
126 | ||
127 | f->f.read = mread; | |
128 | f->f.write = mwrite; | |
129 | f->f.seek = mseek; | |
130 | f->f.close = mclose; | |
131 | ||
9bb4cc5c | 132 | #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) |
320054e8 | 133 | if (!libc.threaded) f->f.lock = -1; |
9bb4cc5c | 134 | #endif |
320054e8 DG |
135 | |
136 | return __ofl_add(&f->f); | |
137 | } |