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!
27 #define COOKIE ((__fmo_cookie *) cookie)
29 static ssize_t
fmo_read(register void *cookie
, char *buf
, size_t bufsize
)
31 size_t count
= COOKIE
->len
- COOKIE
->pos
;
33 /* Note: 0 < bufsize < SSIZE_MAX because of _stdio_READ. */
34 if (!count
) { /* EOF! */
38 if (bufsize
> count
) {
42 memcpy(buf
, COOKIE
->buf
+ COOKIE
->pos
, bufsize
);
43 COOKIE
->pos
+= bufsize
;
48 static ssize_t
fmo_write(register void *cookie
, const char *buf
, size_t bufsize
)
52 /* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
54 /* If appending, need to seek to end of file!!!! */
55 if (COOKIE
->fp
->__modeflags
& __FLAG_APPEND
) {
56 COOKIE
->pos
= COOKIE
->eof
;
59 count
= COOKIE
->len
- COOKIE
->pos
;
61 if (bufsize
> count
) {
63 if (count
== 0) { /* We're at the end of the buffer... */
69 memcpy(COOKIE
->buf
+ COOKIE
->pos
, buf
, bufsize
);
70 COOKIE
->pos
+= bufsize
;
72 if (COOKIE
->pos
> COOKIE
->eof
) {
73 COOKIE
->eof
= COOKIE
->pos
;
74 if (bufsize
< count
) { /* New eof and still room in buffer? */
75 *(COOKIE
->buf
+ COOKIE
->pos
) = 0;
82 /* glibc doesn't allow seeking, but it has in-buffer seeks... we don't. */
83 static int fmo_seek(register void *cookie
, __offmax_t
*pos
, int whence
)
87 /* Note: fseek already checks that whence is legal, so don't check here
88 * unless debugging. */
89 assert(((unsigned int) whence
) <= 2);
91 if (whence
!= SEEK_SET
) {
92 p
+= (whence
== SEEK_CUR
) ? COOKIE
->pos
: /* SEEK_END */ COOKIE
->eof
;
95 /* Note: glibc only allows seeking in the buffer. We'll actually restrict
97 /* Check for offset < 0, offset > eof, or offset overflow... */
98 if (((uintmax_t) p
) > COOKIE
->eof
) {
102 COOKIE
->pos
= *pos
= p
;
106 static int fmo_close(register void *cookie
)
108 if (COOKIE
->dynbuf
) {
117 static const cookie_io_functions_t _fmo_io_funcs
= {
118 fmo_read
, fmo_write
, fmo_seek
, fmo_close
121 /* TODO: If we have buffers enabled, it might be worthwile to add a pointer
122 * to the FILE in the cookie and have read, write, and seek operate directly
123 * on the buffer itself (ie replace the FILE buffer with the cookie buffer
124 * and update FILE bufstart, etc. whenever we seek). */
126 FILE *fmemopen(void *s
, size_t len
, const char *modes
)
129 register __fmo_cookie
*cookie
;
132 if ((cookie
= malloc(sizeof(__fmo_cookie
))) != NULL
) {
134 cookie
->eof
= cookie
->pos
= 0; /* pos and eof adjusted below. */
136 if (((cookie
->buf
= s
) == NULL
) && (len
> 0)) {
137 if ((cookie
->buf
= malloc(len
)) == NULL
) {
141 *cookie
->buf
= 0; /* If we're appending, treat as empty file. */
145 fp
= fopencookie(cookie
, modes
, _fmo_io_funcs
);
147 fp
= fopencookie(cookie
, modes
, &_fmo_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. */
155 if (fp
->__modeflags
& __FLAG_READONLY
) {
158 if ((fp
->__modeflags
& __FLAG_APPEND
) && (len
> 0)) {
159 for (i
= 0 ; i
< len
; i
++) {
160 if (cookie
->buf
[i
] == 0) {
164 cookie
->eof
= cookie
->pos
= i
; /* Adjust eof and pos. */
167 __STDIO_STREAM_VALIDATE(fp
);