1 /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
3 * GNU Library General Public License (LGPL) version 2 or later.
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
10 libc_hidden_proto(memcpy)
11 libc_hidden_proto(memset)
12 libc_hidden_proto(fopencookie)
14 #ifndef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
15 #error no custom streams!
18 #define COOKIE ((__oms_cookie *) cookie)
29 /* Nothing to do here, as memstreams are write-only. */
30 /* static ssize_t oms_read(void *cookie, char *buf, size_t bufsize) */
34 static ssize_t oms_write(register void *cookie, const char *buf, size_t bufsize)
36 register char *newbuf;
39 /* Note: we already know bufsize < SSIZE_MAX... */
41 count = COOKIE->len - COOKIE->pos - 1;
42 assert(COOKIE->pos < COOKIE->len); /* Always nul-terminate! */
44 if (bufsize > count) {
45 newbuf = realloc(COOKIE->buf, COOKIE->len + bufsize - count);
47 *COOKIE->bufloc = COOKIE->buf = newbuf;
48 COOKIE->len += (bufsize - count);
52 __set_errno(EFBIG); /* TODO: check glibc errno setting... */
58 memcpy(COOKIE->buf + COOKIE->pos, buf, bufsize);
59 COOKIE->pos += bufsize;
61 if (COOKIE->pos > COOKIE->eof) {
62 *COOKIE->sizeloc = COOKIE->eof = COOKIE->pos;
63 COOKIE->buf[COOKIE->eof] = 0; /* Need to nul-terminate. */
69 static int oms_seek(register void *cookie, __offmax_t *pos, int whence)
75 /* Note: fseek already checks that whence is legal, so don't check here
76 * unless debugging. */
77 assert(((unsigned int) whence) <= 2);
79 if (whence != SEEK_SET) {
80 p += (whence == SEEK_CUR) ? COOKIE->pos : /* SEEK_END */ COOKIE->eof;
83 /* Note: glibc only allows seeking in the buffer. We'll actually restrict
85 /* Check for offset < 0, offset >= too big (need nul), or overflow... */
86 if (((uintmax_t) p) >= SIZE_MAX - 1) {
90 leastlen = ((size_t) p) + 1; /* New pos + 1 for nul if necessary. */
92 if (leastlen >= COOKIE->len) { /* Need to grow buffer... */
93 buf = realloc(COOKIE->buf, leastlen);
95 *COOKIE->bufloc = COOKIE->buf = buf;
96 COOKIE->len = leastlen;
97 memset(buf + COOKIE->eof, leastlen - COOKIE->eof, 0); /* 0-fill */
99 /* TODO: check glibc errno setting... */
104 *pos = COOKIE->pos = --leastlen;
106 if (leastlen > COOKIE->eof) {
107 memset(COOKIE->buf + COOKIE->eof, leastlen - COOKIE->eof, 0);
108 *COOKIE->sizeloc = COOKIE->eof;
114 static int oms_close(void *cookie)
122 static const cookie_io_functions_t _oms_io_funcs = {
123 NULL, oms_write, oms_seek, oms_close
126 /* TODO: If we have buffers enabled, it might be worthwile to add a pointer
127 * to the FILE in the cookie and operate directly on the buffer itself
128 * (ie replace the FILE buffer with the cookie buffer and update FILE bufstart,
129 * etc. whenever we seek). */
131 FILE *open_memstream(char **__restrict bufloc, size_t *__restrict sizeloc)
133 register __oms_cookie *cookie;
136 if ((cookie = malloc(sizeof(__oms_cookie))) != NULL) {
137 if ((cookie->buf = malloc(cookie->len = BUFSIZ)) == NULL) {
140 *cookie->buf = 0; /* Set nul terminator for buffer. */
141 *(cookie->bufloc = bufloc) = cookie->buf;
142 *(cookie->sizeloc = sizeloc) = cookie->eof = cookie->pos = 0;
145 fp = fopencookie(cookie, "w", _oms_io_funcs);
147 fp = fopencookie(cookie, "w", &_oms_io_funcs);
149 /* Note: We don't need to worry about locking fp in the thread case
150 * as the only possible access would be a close or flush with
151 * nothing currently in the FILE's write buffer. */
154 __STDIO_STREAM_VALIDATE(fp);
159 if (cookie->buf != NULL) {
167 libc_hidden_proto(open_memstream)
168 libc_hidden_def(open_memstream)