/* Copyright (C) 2007 Eric Blake * Permission to use, copy, modify, and distribute this software * is freely granted, provided that this notice is preserved. */ #include #include #include "stdio_impl.h" #define __SRD 0x0004 /* OK to read */ #define __SWR 0x0008 /* OK to write */ #define __SRW 0x0010 /* open for reading & writing */ typedef int (*funread)(void *_cookie, char *_buf, int _n); typedef int (*funwrite)(void *_cookie, const char *_buf, int _n); typedef off_t (*funseek)(void *_cookie, off_t _off, int _whence); typedef int (*funclose)(void *_cookie); typedef struct funcookie { void *cookie; funread readfn; funwrite writefn; funseek seekfn; funclose closefn; } funcookie; static int funreader(void *cookie, char *buf, int n), { int result; funcookie *c = (funcookie *)cookie; errno = 0; if ((result = c->readfn(c->cookie, buf, n)) < 0 && errno) return 0; return result; } static int funwriter(void *cookie, const char *buf, int n) { int result; funcookie *c = (funcookie *)cookie; errno = 0; if ((result = c->writefn(c->cookie, buf, n)) < 0 && errno) return 0; return result; } static off_t funseeker(void *cookie, off_t off, int whence) { funcookie *c = (funcookie *)cookie; off64_t result; errno = 0; if ((result = c->seekfn(c->cookie, (off_t)off, whence)) < 0 && errno) return 0; return result; } static int funcloser(void *cookie) { int result = 0; funcookie *c = (funcookie *)cookie; if (c->closefn) { errno = 0; if ((result = c->closefn(c->cookie)) < 0 && errno) return 0; } free(c); /* check it in newlib src to be shure */ return result; } FILE *funopen(const void *cookie, funread readfn, funwrite writefn, funseek seekfn, funclose closefn) { FILE *fp; funcookie *c; if (!readfn && !writefn) { errno = EINVAL; return NULL; } if ((fp = __sfp()) == NULL) return NULL; if ((c = (funcookie *)malloc(sizeof *c)) == NULL) { __sfp_lock_acquire (); fp->_flags = 0; /* release */ #ifndef __SINGLE_THREAD__ __lock_close_recursive (fp->_lock); #endif __sfp_lock_release (); return NULL; } FLOCK(fp); fp->_file = -1; c->cookie = (void *)cookie; /* cast away const */ fp->_cookie = c; if (readfn) { c->readfn = readfn; fp->_read = funreader; if (writefn) { fp->_flags = __SRW; c->writefn = writefn; fp->_write = funwriter; } else { fp->_flags = __SRD; c->writefn = NULL; fp->_write = NULL; } } else { fp->_flags = __SWR; c->writefn = writefn; fp->_write = funwriter; c->readfn = NULL; fp->_read = NULL; } c->seekfn = seekfn; fp->_seek = seekfn ? funseeker : NULL; c->closefn = closefn; fp->_close = funcloser; FUNLOCK(fp); return fp; }