netinet/in.h: add IPPROTO_MH
[uclibc-ng.git] / libc / stdio / open_memstream.c
blob17ef191cb6a5d69e343252fd45fe4d608ec6d2d1
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.
6 */
8 #include <features.h>
10 #ifdef __USE_GNU
11 #include "_stdio.h"
14 #ifndef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
15 #error no custom streams!
16 #endif
18 #define COOKIE ((__oms_cookie *) cookie)
20 #define MEMSTREAM_BUFSIZ 256
22 typedef struct {
23 char *buf;
24 size_t len;
25 size_t pos;
26 size_t eof;
27 char **bufloc;
28 size_t *sizeloc;
29 } __oms_cookie;
31 /* Nothing to do here, as memstreams are write-only. */
32 /* static ssize_t oms_read(void *cookie, char *buf, size_t bufsize) */
33 /* { */
34 /* } */
36 static ssize_t oms_write(register void *cookie, const char *buf, size_t bufsize)
38 register char *newbuf;
39 size_t count;
41 /* Note: we already know bufsize < SSIZE_MAX... */
43 count = COOKIE->len - COOKIE->pos - 1;
44 assert(COOKIE->pos < COOKIE->len); /* Always nul-terminate! */
46 if (bufsize > count) {
47 newbuf = realloc(COOKIE->buf, COOKIE->len + bufsize - count);
48 if (newbuf) {
49 *COOKIE->bufloc = COOKIE->buf = newbuf;
50 COOKIE->len += (bufsize - count);
51 } else {
52 bufsize = count;
53 if (count == 0) {
54 __set_errno(EFBIG); /* TODO: check glibc errno setting... */
55 return -1;
60 memcpy(COOKIE->buf + COOKIE->pos, buf, bufsize);
61 COOKIE->pos += bufsize;
63 if (COOKIE->pos > COOKIE->eof) {
64 *COOKIE->sizeloc = COOKIE->eof = COOKIE->pos;
65 COOKIE->buf[COOKIE->eof] = 0; /* Need to nul-terminate. */
68 return bufsize;
71 static int oms_seek(register void *cookie, __offmax_t *pos, int whence)
73 __offmax_t p = *pos;
74 register char *buf;
75 size_t leastlen;
77 /* Note: fseek already checks that whence is legal, so don't check here
78 * unless debugging. */
79 assert(((unsigned int) whence) <= 2);
81 if (whence != SEEK_SET) {
82 p += (whence == SEEK_CUR) ? COOKIE->pos : /* SEEK_END */ COOKIE->eof;
85 /* Note: glibc only allows seeking in the buffer. We'll actually restrict
86 * to the data. */
87 /* Check for offset < 0, offset >= too big (need nul), or overflow... */
88 if (((uintmax_t) p) >= SIZE_MAX - 1) {
89 return -1;
92 leastlen = ((size_t) p) + 1; /* New pos + 1 for nul if necessary. */
94 if (leastlen >= COOKIE->len) { /* Need to grow buffer... */
95 buf = realloc(COOKIE->buf, leastlen);
96 if (buf) {
97 *COOKIE->bufloc = COOKIE->buf = buf;
98 COOKIE->len = leastlen;
99 memset(buf + COOKIE->eof, 0, leastlen - COOKIE->eof); /* 0-fill */
100 } else {
101 /* TODO: check glibc errno setting... */
102 return -1;
106 *pos = COOKIE->pos = --leastlen;
108 if (leastlen > COOKIE->eof) {
109 memset(COOKIE->buf + COOKIE->eof, 0, leastlen - COOKIE->eof);
110 *COOKIE->sizeloc = COOKIE->eof;
113 return 0;
116 static int oms_close(void *cookie)
118 free(cookie);
119 return 0;
122 #undef COOKIE
124 static const cookie_io_functions_t _oms_io_funcs = {
125 NULL, oms_write, oms_seek, oms_close
128 /* TODO: If we have buffers enabled, it might be worthwile to add a pointer
129 * to the FILE in the cookie and operate directly on the buffer itself
130 * (ie replace the FILE buffer with the cookie buffer and update FILE bufstart,
131 * etc. whenever we seek). */
133 FILE *open_memstream(char **bufloc, size_t *sizeloc)
135 register __oms_cookie *cookie;
136 register FILE *fp;
138 if ((cookie = malloc(sizeof(__oms_cookie))) != NULL) {
139 if ((cookie->buf = malloc(cookie->len = MEMSTREAM_BUFSIZ)) == NULL) {
140 goto EXIT_cookie;
142 *cookie->buf = 0; /* Set nul terminator for buffer. */
143 *(cookie->bufloc = bufloc) = cookie->buf;
144 *(cookie->sizeloc = sizeloc) = cookie->eof = cookie->pos = 0;
146 #ifndef __BCC__
147 fp = fopencookie(cookie, "w", _oms_io_funcs);
148 #else
149 fp = fopencookie(cookie, "w", &_oms_io_funcs);
150 #endif
151 /* Note: We don't need to worry about locking fp in the thread case
152 * as the only possible access would be a close or flush with
153 * nothing currently in the FILE's write buffer. */
155 if (fp != NULL) {
156 __STDIO_STREAM_VALIDATE(fp);
157 return fp;
161 free(cookie->buf);
162 EXIT_cookie:
163 free(cookie);
165 return NULL;
167 libc_hidden_def(open_memstream)
168 #endif