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