1#include "stdio_impl.h"
2#include <errno.h>
3#include <limits.h>
4#include <string.h>
5
6struct 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
15static 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
29static 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
55static int ms_close(FILE* f) {
56    return 0;
57}
58
59FILE* 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