reduce spurious inclusion of libc.h
[musl] / src / stdio / fmemopen.c
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
124         if (!libc.threaded) f->f.lock = -1;
125
126         return __ofl_add(&f->f);
127 }