40f5ad60caf986e253aa7241be726248b58a806c
[musl] / open_memstream.c
1 #include "stdio_impl.h"
2 #include <errno.h>
3 #include <limits.h>
4 #include <string.h>
5
6 struct cookie {
7         char **bufp;
8         size_t *sizep;
9         size_t pos;
10         char *buf;
11         size_t len;
12         size_t space;
13 };
14
15 struct ms_FILE {
16         FILE f;
17         struct cookie c;
18         unsigned char buf[BUFSIZ];
19 };
20
21 static off_t ms_seek(FILE *f, off_t off, int whence)
22 {
23         ssize_t base;
24         struct cookie *c = f->cookie;
25         if (whence>2U) {
26 fail:
27                 errno = EINVAL;
28                 return -1;
29         }
30         base = (size_t [3]){0, c->pos, c->len}[whence];
31         if (off < -base || off > SSIZE_MAX-base) goto fail;
32         return c->pos = base+off;
33 }
34
35 static size_t ms_write(FILE *f, const unsigned char *buf, size_t len)
36 {
37         struct cookie *c = f->cookie;
38         size_t len2 = f->wpos - f->wbase;
39         char *newbuf;
40         if (len2) {
41                 f->wpos = f->wbase;
42                 if (ms_write(f, f->wbase, len2) < len2) return 0;
43         }
44         if (len + c->pos >= c->space) {
45                 len2 = 2*c->space+1 | c->pos+len+1;
46                 newbuf = realloc(c->buf, len2);
47                 if (!newbuf) return 0;
48                 *c->bufp = c->buf = newbuf;
49                 memset(c->buf + c->space, 0, len2 - c->space);
50                 c->space = len2;
51         }
52         memcpy(c->buf+c->pos, buf, len);
53         c->pos += len;
54         if (c->pos >= c->len) c->len = c->pos;
55         *c->sizep = c->pos;
56         return len;
57 }
58
59 static int ms_close(FILE *f)
60 {
61         return 0;
62 }
63
64 FILE *open_memstream(char **bufp, size_t *sizep)
65 {
66         struct ms_FILE *f;
67         char *buf;
68
69         if (!(f=malloc(sizeof *f))) return 0;
70         if (!(buf=malloc(sizeof *buf))) {
71                 free(f);
72                 return 0;
73         }
74         memset(&f->f, 0, sizeof f->f);
75         memset(&f->c, 0, sizeof f->c);
76         f->f.cookie = &f->c;
77
78         f->c.bufp = bufp;
79         f->c.sizep = sizep;
80         f->c.pos = f->c.len = f->c.space = *sizep = 0;
81         f->c.buf = *bufp = buf;
82         *buf = 0;
83
84         f->f.flags = F_NORD;
85         f->f.fd = -1;
86         f->f.buf = f->buf;
87         f->f.buf_size = sizeof f->buf;
88         f->f.lbf = EOF;
89         f->f.write = ms_write;
90         f->f.seek = ms_seek;
91         f->f.close = ms_close;
92         f->f.mode = -1;
93
94         if (!libc.threaded) f->f.lock = -1;
95
96         return __ofl_add(&f->f);
97 }