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.
14 #ifndef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
15 #error no custom streams!
18 #define COOKIE ((__oms_cookie *) cookie)
20 #define MEMSTREAM_BUFSIZ 256
31 /* Nothing to do here, as memstreams are write-only. */
32 /* static ssize_t oms_read(void *cookie, char *buf, size_t bufsize) */
36 static ssize_t
oms_write(register void *cookie
, const char *buf
, size_t bufsize
)
38 register char *newbuf
;
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
);
49 *COOKIE
->bufloc
= COOKIE
->buf
= newbuf
;
50 COOKIE
->len
+= (bufsize
- count
);
54 __set_errno(EFBIG
); /* TODO: check glibc errno setting... */
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. */
71 static int oms_seek(register void *cookie
, __offmax_t
*pos
, int whence
)
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
87 /* Check for offset < 0, offset >= too big (need nul), or overflow... */
88 if (((uintmax_t) p
) >= SIZE_MAX
- 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
);
97 *COOKIE
->bufloc
= COOKIE
->buf
= buf
;
98 COOKIE
->len
= leastlen
;
99 memset(buf
+ COOKIE
->eof
, 0, leastlen
- COOKIE
->eof
); /* 0-fill */
101 /* TODO: check glibc errno setting... */
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
;
116 static int oms_close(void *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
;
138 if ((cookie
= malloc(sizeof(__oms_cookie
))) != NULL
) {
139 if ((cookie
->buf
= malloc(cookie
->len
= MEMSTREAM_BUFSIZ
)) == NULL
) {
142 *cookie
->buf
= 0; /* Set nul terminator for buffer. */
143 *(cookie
->bufloc
= bufloc
) = cookie
->buf
;
144 *(cookie
->sizeloc
= sizeloc
) = cookie
->eof
= cookie
->pos
= 0;
147 fp
= fopencookie(cookie
, "w", _oms_io_funcs
);
149 fp
= fopencookie(cookie
, "w", &_oms_io_funcs
);
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. */
156 __STDIO_STREAM_VALIDATE(fp
);
168 libc_hidden_def(open_memstream
)