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.
13 /* Experimentally off - libc_hidden_proto(memcpy) */
14 /* libc_hidden_proto(fopencookie) */
16 #ifndef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
17 #error no custom streams!
29 #define COOKIE ((__fmo_cookie *) cookie)
31 static ssize_t fmo_read(register void *cookie, char *buf, size_t bufsize)
33 size_t count = COOKIE->len - COOKIE->pos;
35 /* Note: 0 < bufsize < SSIZE_MAX because of _stdio_READ. */
36 if (!count) { /* EOF! */
40 if (bufsize > count) {
44 memcpy(buf, COOKIE->buf + COOKIE->pos, bufsize);
45 COOKIE->pos += bufsize;
50 static ssize_t fmo_write(register void *cookie, const char *buf, size_t bufsize)
54 /* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
56 /* If appending, need to seek to end of file!!!! */
57 if (COOKIE->fp->__modeflags & __FLAG_APPEND) {
58 COOKIE->pos = COOKIE->eof;
61 count = COOKIE->len - COOKIE->pos;
63 if (bufsize > count) {
65 if (count == 0) { /* We're at the end of the buffer... */
71 memcpy(COOKIE->buf + COOKIE->pos, buf, bufsize);
72 COOKIE->pos += bufsize;
74 if (COOKIE->pos > COOKIE->eof) {
75 COOKIE->eof = COOKIE->pos;
76 if (bufsize < count) { /* New eof and still room in buffer? */
77 *(COOKIE->buf + COOKIE->pos) = 0;
84 /* glibc doesn't allow seeking, but it has in-buffer seeks... we don't. */
85 static int fmo_seek(register void *cookie, __offmax_t *pos, int whence)
89 /* Note: fseek already checks that whence is legal, so don't check here
90 * unless debugging. */
91 assert(((unsigned int) whence) <= 2);
93 if (whence != SEEK_SET) {
94 p += (whence == SEEK_CUR) ? COOKIE->pos : /* SEEK_END */ COOKIE->eof;
97 /* Note: glibc only allows seeking in the buffer. We'll actually restrict
99 /* Check for offset < 0, offset > eof, or offset overflow... */
100 if (((uintmax_t) p) > COOKIE->eof) {
104 COOKIE->pos = *pos = p;
108 static int fmo_close(register void *cookie)
110 if (COOKIE->dynbuf) {
119 static const cookie_io_functions_t _fmo_io_funcs = {
120 fmo_read, fmo_write, fmo_seek, fmo_close
123 /* TODO: If we have buffers enabled, it might be worthwile to add a pointer
124 * to the FILE in the cookie and have read, write, and seek operate directly
125 * on the buffer itself (ie replace the FILE buffer with the cookie buffer
126 * and update FILE bufstart, etc. whenever we seek). */
128 FILE *fmemopen(void *s, size_t len, const char *modes)
131 register __fmo_cookie *cookie;
134 if ((cookie = malloc(sizeof(__fmo_cookie))) != NULL) {
136 cookie->eof = cookie->pos = 0; /* pos and eof adjusted below. */
138 if (((cookie->buf = s) == NULL) && (len > 0)) {
139 if ((cookie->buf = malloc(len)) == NULL) {
143 *cookie->buf = 0; /* If we're appending, treat as empty file. */
147 fp = fopencookie(cookie, modes, _fmo_io_funcs);
149 fp = fopencookie(cookie, modes, &_fmo_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. */
157 if (fp->__modeflags & __FLAG_READONLY) {
160 if ((fp->__modeflags & __FLAG_APPEND) && (len > 0)) {
161 for (i = 0 ; i < len ; i++) {
162 if (cookie->buf[i] == 0) {
166 cookie->eof = cookie->pos = i; /* Adjust eof and pos. */
169 __STDIO_STREAM_VALIDATE(fp);