1570af302Sopenharmony_ci#include "stdio_impl.h"
2570af302Sopenharmony_ci#include <errno.h>
3570af302Sopenharmony_ci#include <limits.h>
4570af302Sopenharmony_ci#include <string.h>
5570af302Sopenharmony_ci#include <stdlib.h>
6570af302Sopenharmony_ci#include "libc.h"
7570af302Sopenharmony_ci
8570af302Sopenharmony_cistruct cookie {
9570af302Sopenharmony_ci	char **bufp;
10570af302Sopenharmony_ci	size_t *sizep;
11570af302Sopenharmony_ci	size_t pos;
12570af302Sopenharmony_ci	char *buf;
13570af302Sopenharmony_ci	size_t len;
14570af302Sopenharmony_ci	size_t space;
15570af302Sopenharmony_ci};
16570af302Sopenharmony_ci
17570af302Sopenharmony_cistruct ms_FILE {
18570af302Sopenharmony_ci	FILE f;
19570af302Sopenharmony_ci	struct cookie c;
20570af302Sopenharmony_ci	unsigned char buf[BUFSIZ];
21570af302Sopenharmony_ci};
22570af302Sopenharmony_ci
23570af302Sopenharmony_cistatic off_t ms_seek(FILE *f, off_t off, int whence)
24570af302Sopenharmony_ci{
25570af302Sopenharmony_ci	ssize_t base;
26570af302Sopenharmony_ci	struct cookie *c = f->cookie;
27570af302Sopenharmony_ci	if (whence>2U) {
28570af302Sopenharmony_cifail:
29570af302Sopenharmony_ci		errno = EINVAL;
30570af302Sopenharmony_ci		return -1;
31570af302Sopenharmony_ci	}
32570af302Sopenharmony_ci	base = (size_t [3]){0, c->pos, c->len}[whence];
33570af302Sopenharmony_ci	if (off < -base || off > SSIZE_MAX-base) goto fail;
34570af302Sopenharmony_ci	return c->pos = base+off;
35570af302Sopenharmony_ci}
36570af302Sopenharmony_ci
37570af302Sopenharmony_cistatic size_t ms_write(FILE *f, const unsigned char *buf, size_t len)
38570af302Sopenharmony_ci{
39570af302Sopenharmony_ci	struct cookie *c = f->cookie;
40570af302Sopenharmony_ci	size_t len2 = f->wpos - f->wbase;
41570af302Sopenharmony_ci	char *newbuf;
42570af302Sopenharmony_ci	if (len2) {
43570af302Sopenharmony_ci		f->wpos = f->wbase;
44570af302Sopenharmony_ci		if (ms_write(f, f->wbase, len2) < len2) return 0;
45570af302Sopenharmony_ci	}
46570af302Sopenharmony_ci	if (len + c->pos >= c->space) {
47570af302Sopenharmony_ci		len2 = 2*c->space+1 | c->pos+len+1;
48570af302Sopenharmony_ci		newbuf = realloc(c->buf, len2);
49570af302Sopenharmony_ci		if (!newbuf) return 0;
50570af302Sopenharmony_ci		*c->bufp = c->buf = newbuf;
51570af302Sopenharmony_ci		memset(c->buf + c->space, 0, len2 - c->space);
52570af302Sopenharmony_ci		c->space = len2;
53570af302Sopenharmony_ci	}
54570af302Sopenharmony_ci	memcpy(c->buf+c->pos, buf, len);
55570af302Sopenharmony_ci	c->pos += len;
56570af302Sopenharmony_ci	if (c->pos >= c->len) c->len = c->pos;
57570af302Sopenharmony_ci	*c->sizep = c->pos;
58570af302Sopenharmony_ci	return len;
59570af302Sopenharmony_ci}
60570af302Sopenharmony_ci
61570af302Sopenharmony_cistatic int ms_close(FILE *f)
62570af302Sopenharmony_ci{
63570af302Sopenharmony_ci	return 0;
64570af302Sopenharmony_ci}
65570af302Sopenharmony_ci
66570af302Sopenharmony_ciFILE *open_memstream(char **bufp, size_t *sizep)
67570af302Sopenharmony_ci{
68570af302Sopenharmony_ci	struct ms_FILE *f;
69570af302Sopenharmony_ci	char *buf;
70570af302Sopenharmony_ci
71570af302Sopenharmony_ci	if (!(f=malloc(sizeof *f))) return 0;
72570af302Sopenharmony_ci	if (!(buf=malloc(sizeof *buf))) {
73570af302Sopenharmony_ci		free(f);
74570af302Sopenharmony_ci		return 0;
75570af302Sopenharmony_ci	}
76570af302Sopenharmony_ci	memset(&f->f, 0, sizeof f->f);
77570af302Sopenharmony_ci	memset(&f->c, 0, sizeof f->c);
78570af302Sopenharmony_ci	f->f.cookie = &f->c;
79570af302Sopenharmony_ci
80570af302Sopenharmony_ci	f->c.bufp = bufp;
81570af302Sopenharmony_ci	f->c.sizep = sizep;
82570af302Sopenharmony_ci	f->c.pos = f->c.len = f->c.space = *sizep = 0;
83570af302Sopenharmony_ci	f->c.buf = *bufp = buf;
84570af302Sopenharmony_ci	*buf = 0;
85570af302Sopenharmony_ci
86570af302Sopenharmony_ci	f->f.flags = F_NORD;
87570af302Sopenharmony_ci	f->f.fd = -1;
88570af302Sopenharmony_ci	f->f.buf = f->buf;
89570af302Sopenharmony_ci	f->f.buf_size = sizeof f->buf;
90570af302Sopenharmony_ci	f->f.lbf = EOF;
91570af302Sopenharmony_ci	f->f.write = ms_write;
92570af302Sopenharmony_ci	f->f.seek = ms_seek;
93570af302Sopenharmony_ci	f->f.close = ms_close;
94570af302Sopenharmony_ci	f->f.mode = -1;
95570af302Sopenharmony_ci
96570af302Sopenharmony_ci	if (!libc.threaded) f->f.lock = -1;
97570af302Sopenharmony_ci
98570af302Sopenharmony_ci	return __ofl_add(&f->f);
99570af302Sopenharmony_ci}
100