Subject: Re: SUSv3 extended API set
To: Rui Paulo <rpaulo@fnop.net>
From: Pavel Cahyna <pavel.cahyna@st.mff.cuni.cz>
List: tech-userlevel
Date: 12/18/2005 09:10:48
--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Sat, Dec 17, 2005 at 12:03:00AM +0000, Rui Paulo wrote:
> I just saw this on the freebsd-standards mailing list.
> http://lists.freebsd.org/pipermail/freebsd-standards/2005-December/001087.html
> 
> We already support some of them, but I guess we should start working
> to implement the new ones.
> 
> Thoughts?

I have an implementation of fmemopen(). If you are interested in it, it's
attached.

Bye	Pavel

--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="fmemopen.c"

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#include "fmemopen.h"

#define	READ   		1
#define	WRITE  		2

/* zkratit na nulovou delku  */

#define	TRUNCATE	4

/* zapis ignoruje cur_pos a misto toho se pripojuje na konec */

#define	APPEND		16
	
typedef struct cookie { 
	void * buf;
	fpos_t cur_pos;
	size_t size;
	size_t cur_size;
	int    flags;
} cookie_t;

static int (*appendmem)(void *, const char *, int) = NULL; 

int closemem (void * cookie)
{
	
	cookie_t * cookie_p;

	cookie_p = ( cookie_t * ) cookie;
	assert ( cookie_p->size >= cookie_p->cur_size);
	if ( cookie_p->size > cookie_p->cur_size) {
		* ((char*) (cookie_p->buf) + cookie_p->cur_size) = 0;
	}
	return 0;
}


int writemem (void * cookie, const char * src, int nbytes)
{
	size_t  remain;
	long 	lremain;
	cookie_t * cookie_p;

	/* printf ("writemem: %d\n", nbytes); */

	cookie_p = ( cookie_t * ) cookie;
	assert ( cookie_p->size >= cookie_p->cur_size);
	if ((nbytes < 0) || (cookie_p->cur_pos < 0) ) {
		errno = EINVAL;
		return -1;
	};
	lremain = (long) (cookie_p->size) - (long) (cookie_p->cur_pos);
	/* printf("writemem: remain = %ld\n" , lremain  ); */
	if (lremain < nbytes ) {
		printf("writemem: ENOSPC\n"); 
		errno =	ENOSPC;
		return -1;
	}

	remain = cookie_p->size - cookie_p->cur_pos;
	if ( nbytes) {
		if ( (cookie_p->cur_pos - cookie_p->cur_size) > 0) {
			bzero (cookie_p->buf + cookie_p->cur_size,
			    cookie_p->cur_pos - cookie_p->cur_size);
		}
		memcpy(cookie_p->buf + cookie_p->cur_pos, src, nbytes);
		cookie_p->cur_pos += nbytes;
		if (cookie_p->cur_pos > cookie_p->cur_size) 
			cookie_p->cur_size =  cookie_p->cur_pos;
	}
	/* printf("writemem: cur_size = %zd\nsize = %zd\n" , cookie_p->cur_size, cookie_p->size ); */
	return nbytes;
}

int readmem (void * cookie, char * dst, int nbytes)
{
	size_t len, remain;
	cookie_t * cookie_p;
	cookie_p = ( cookie_t * ) cookie;
	if (nbytes < 0) {
		errno = EINVAL;
		return 0;
	};
	assert ( cookie_p->size >= cookie_p->cur_size);
	if (((long) (cookie_p->cur_size) < (long) (cookie_p->cur_pos)) ) {
		/* printf("readmem: return\n"); */ 
		return 0;
	}
	remain = cookie_p->cur_size - cookie_p->cur_pos ;
	len = ( nbytes > remain ? remain : nbytes);
	if ( len) memcpy(dst, cookie_p->buf + cookie_p->cur_pos, len);
	cookie_p->cur_pos += len;
	return len;
}

fpos_t seekmem (void * cookie, fpos_t off, int whence)
{
	fpos_t retval;
	cookie_t * cookie_p;
	
	/* printf("seekmem: %d\n", (int) off); */

	cookie_p = ( cookie_t * ) cookie;
	switch(whence) {
		case SEEK_CUR: retval = cookie_p->cur_pos + off;
			       break;
		case SEEK_SET: retval = off;
			       break;
		case SEEK_END: retval = cookie_p->cur_size + off;
			       break;
	}
	/*if (retval < 0)
		retval = 0;
	if (retval > cookie_p->size)
	       	retval = cookie_p->size;
	if (retval > cookie_p->cur_size) {
		bzero (cookie_p->buf + cookie_p->cur_size,
		    retval - cookie_p->cur_size);
		cookie_p->cur_size = retval;
	}
	*/
	cookie_p->cur_pos =  retval;
	return retval;
}

FILE * fmemopen (void *BUF, size_t SIZE, const char *OPENTYPE)
{
	cookie_t * cookie_p;
	int (*rfunc)(void *, char *, int) ;
	int (*wfunc)(void *, const char *, int) ;
	int flags;
	flags = 0;
	switch (OPENTYPE[0]) {
	case 'r' : flags |= READ;
		   break;
	case 'w' : flags |= (WRITE | TRUNCATE);
		   break;
	case 'a' : flags |= (WRITE | APPEND);
		   break;
	}
	if ((strlen(OPENTYPE) == 2) && (OPENTYPE[1] == '+') ) {
		flags |= (READ | WRITE);
	}
	

		  
	if((cookie_p = malloc(sizeof (cookie_t))) == NULL ) return NULL;
	cookie_p->buf = BUF;
	cookie_p->size = SIZE;
	if (flags & TRUNCATE ) {
		cookie_p->cur_size = 0;
	} else {
		cookie_p->cur_size = SIZE;
	}

	cookie_p->flags = flags;

	cookie_p->cur_pos = 0;
	
	rfunc = (flags & READ) ? readmem : ( int (*)(void *, char *, int)) NULL;

	if (flags & WRITE) {
		 wfunc = (flags & APPEND) ? appendmem : writemem ;
	}
	else 	wfunc = (int (*)(void *, const char *, int)) NULL; 

	return funopen(cookie_p, rfunc, wfunc, seekmem, closemem );
}

--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="fmemopen.h"

FILE * fmemopen (void *, size_t, const char *);

--mP3DRpeJDSE+ciuQ--