| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 | /* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org> * * GNU Library General Public License (LGPL) version 2 or later. * * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details. */#include "_stdio.h"#ifndef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__#error no custom streams!#endiftypedef struct {	size_t pos;	size_t len;	size_t eof;	int dynbuf;	unsigned char *buf;	FILE *fp;} __fmo_cookie;#define COOKIE ((__fmo_cookie *) cookie)static ssize_t fmo_read(register void *cookie, char *buf, size_t bufsize){	size_t count = COOKIE->len - COOKIE->pos;	/* Note: 0 < bufsize < SSIZE_MAX because of _stdio_READ. */	if (!count) {				/* EOF! */		return 0;	}	if (bufsize > count) {		bufsize = count;	}	memcpy(buf, COOKIE->buf + COOKIE->pos, bufsize);	COOKIE->pos += bufsize;	return bufsize;}static ssize_t fmo_write(register void *cookie, const char *buf, size_t bufsize){	size_t count;	/* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */	/* If appending, need to seek to end of file!!!! */	if (COOKIE->fp->__modeflags & __FLAG_APPEND) {		COOKIE->pos = COOKIE->eof;	}	count = COOKIE->len - COOKIE->pos;	if (bufsize > count) {		bufsize = count;		if (count == 0) {		/* We're at the end of the buffer... */			__set_errno(EFBIG);			return -1;		}	}	memcpy(COOKIE->buf + COOKIE->pos, buf, bufsize);	COOKIE->pos += bufsize;	if (COOKIE->pos > COOKIE->eof) {		COOKIE->eof = COOKIE->pos;		if (bufsize < count) {	/* New eof and still room in buffer? */			*(COOKIE->buf + COOKIE->pos) = 0;		}	}	return bufsize;}/* glibc doesn't allow seeking, but it has in-buffer seeks... we don't. */static int fmo_seek(register void *cookie, __offmax_t *pos, int whence){	__offmax_t p = *pos;	/* Note: fseek already checks that whence is legal, so don't check here	 * unless debugging. */	assert(((unsigned int) whence) <= 2);	if (whence != SEEK_SET) {		p += (whence == SEEK_CUR) ? COOKIE->pos : /* SEEK_END */ COOKIE->eof;	}	/* Note: glibc only allows seeking in the buffer.  We'll actually restrict	 * to the data. */	/* Check for offset < 0, offset > eof, or offset overflow... */	if (((uintmax_t) p) > COOKIE->eof) {		return -1;	}	COOKIE->pos = *pos = p;	return 0;}static int fmo_close(register void *cookie){	if (COOKIE->dynbuf) {		free(COOKIE->buf);	}	free(cookie);	return 0;}#undef COOKIEstatic const cookie_io_functions_t _fmo_io_funcs = {	fmo_read, fmo_write, fmo_seek, fmo_close};/* TODO: If we have buffers enabled, it might be worthwile to add a pointer * to the FILE in the cookie and have read, write, and seek operate directly * on the buffer itself (ie replace the FILE buffer with the cookie buffer * and update FILE bufstart, etc. whenever we seek). */FILE *fmemopen(void *s, size_t len, const char *modes){	FILE *fp;	register __fmo_cookie *cookie;	size_t i;	if ((cookie = malloc(sizeof(__fmo_cookie))) != NULL) {		cookie->len = len;		cookie->eof = cookie->pos = 0; /* pos and eof adjusted below. */		cookie->dynbuf = 0;		if (((cookie->buf = s) == NULL) && (len > 0)) {			if ((cookie->buf = malloc(len)) == NULL) {				goto EXIT_cookie;			}			cookie->dynbuf = 1;			*cookie->buf = 0;	/* If we're appending, treat as empty file. */		}		#ifndef __BCC__		fp = fopencookie(cookie, modes, _fmo_io_funcs);#else		fp = fopencookie(cookie, modes, &_fmo_io_funcs);#endif		/* Note: We don't need to worry about locking fp in the thread case		 * as the only possible access would be a close or flush with		 * nothing currently in the FILE's write buffer. */		if (fp != NULL) {			cookie->fp = fp;			if (fp->__modeflags & __FLAG_READONLY) {				cookie->eof = len;			}			if ((fp->__modeflags & __FLAG_APPEND) && (len > 0)) {				for (i = 0 ; i < len ; i++) {					if (cookie->buf[i] == 0) {						break;					}				}				cookie->eof = cookie->pos = i; /* Adjust eof and pos. */			}			__STDIO_STREAM_VALIDATE(fp);			return fp;		}	}	if (!s) {		free(cookie->buf);	} EXIT_cookie:	free(cookie);	return NULL;}
 |