xref: /netbsd-src/lib/libc/stdio/funopen.c (revision 5b486ace20948bb245077554a3b10cc27218545c)
1*5b486aceSchristos /*	$NetBSD: funopen.c,v 1.15 2016/10/23 21:01:52 christos Exp $	*/
2255db7b2Sjtc 
361f28255Scgd /*-
4255db7b2Sjtc  * Copyright (c) 1990, 1993
5255db7b2Sjtc  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * This code is derived from software contributed to Berkeley by
861f28255Scgd  * Chris Torek.
961f28255Scgd  *
1061f28255Scgd  * Redistribution and use in source and binary forms, with or without
1161f28255Scgd  * modification, are permitted provided that the following conditions
1261f28255Scgd  * are met:
1361f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1561f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1761f28255Scgd  *    documentation and/or other materials provided with the distribution.
18eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd  *    may be used to endorse or promote products derived from this software
2061f28255Scgd  *    without specific prior written permission.
2161f28255Scgd  *
2261f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd  * SUCH DAMAGE.
3361f28255Scgd  */
3461f28255Scgd 
3523312f88Schristos #include <sys/cdefs.h>
3661f28255Scgd #if defined(LIBC_SCCS) && !defined(lint)
37255db7b2Sjtc #if 0
38255db7b2Sjtc static char sccsid[] = "@(#)funopen.c	8.1 (Berkeley) 6/4/93";
3923312f88Schristos #else
40*5b486aceSchristos __RCSID("$NetBSD: funopen.c,v 1.15 2016/10/23 21:01:52 christos Exp $");
41255db7b2Sjtc #endif
4261f28255Scgd #endif /* LIBC_SCCS and not lint */
4361f28255Scgd 
4461f28255Scgd #include <stdio.h>
4561f28255Scgd #include <errno.h>
46de001ba2Schristos #include <stdlib.h>
47de001ba2Schristos #include <stddef.h>
483fdac2b8Sthorpej #include "reentrant.h"
4961f28255Scgd #include "local.h"
5061f28255Scgd 
5161f28255Scgd FILE *
funopen2(const void * cookie,ssize_t (* readfn)(void *,void *,size_t),ssize_t (* writefn)(void *,const void *,size_t),off_t (* seekfn)(void *,off_t,int),int (* flushfn)(void *),int (* closefn)(void *))52de001ba2Schristos funopen2(const void *cookie,
53de001ba2Schristos     ssize_t (*readfn)(void *, void *, size_t),
54de001ba2Schristos     ssize_t (*writefn)(void *, const void *, size_t),
55526d9427Schristos     off_t (*seekfn)(void *, off_t, int),
56de001ba2Schristos     int (*flushfn)(void *),
57526d9427Schristos     int (*closefn)(void *))
5861f28255Scgd {
59c8bafd62Sperry 	FILE *fp;
6061f28255Scgd 	int flags;
6161f28255Scgd 
6261f28255Scgd 	if (readfn == NULL) {
6361f28255Scgd 		if (writefn == NULL) {		/* illegal */
6461f28255Scgd 			errno = EINVAL;
65526d9427Schristos 			return NULL;
6661f28255Scgd 		} else
6761f28255Scgd 			flags = __SWR;		/* write only */
6861f28255Scgd 	} else {
6961f28255Scgd 		if (writefn == NULL)
7061f28255Scgd 			flags = __SRD;		/* read only */
7161f28255Scgd 		else
7261f28255Scgd 			flags = __SRW;		/* read-write */
7361f28255Scgd 	}
7461f28255Scgd 	if ((fp = __sfp()) == NULL)
75526d9427Schristos 		return NULL;
7661f28255Scgd 	fp->_flags = flags;
7761f28255Scgd 	fp->_file = -1;
7803256c6eSchristos 	fp->_cookie = __UNCONST(cookie);
7961f28255Scgd 	fp->_read = readfn;
8061f28255Scgd 	fp->_write = writefn;
8161f28255Scgd 	fp->_seek = seekfn;
82de001ba2Schristos 	fp->_flush = flushfn;
8361f28255Scgd 	fp->_close = closefn;
84526d9427Schristos 	return fp;
8561f28255Scgd }
86de001ba2Schristos 
87de001ba2Schristos typedef struct {
88de001ba2Schristos 	void *cookie;
89de001ba2Schristos 	int (*readfn)(void *, char *, int);
90de001ba2Schristos 	int (*writefn)(void *, const char *, int);
91de001ba2Schristos 	off_t (*seekfn)(void *, off_t, int);
92de001ba2Schristos 	int (*closefn)(void *);
93de001ba2Schristos } dookie_t;
94de001ba2Schristos 
95de001ba2Schristos static ssize_t
creadfn(void * dookie,void * buf,size_t len)96de001ba2Schristos creadfn(void *dookie, void *buf, size_t len)
97de001ba2Schristos {
98de001ba2Schristos 	dookie_t *d = dookie;
99de001ba2Schristos 	if (len > INT_MAX)
100de001ba2Schristos 		len = INT_MAX;
101de001ba2Schristos 	return (*d->readfn)(d->cookie, buf, (int)len);
102de001ba2Schristos }
103de001ba2Schristos 
104de001ba2Schristos static ssize_t
cwritefn(void * dookie,const void * buf,size_t len)105de001ba2Schristos cwritefn(void *dookie, const void *buf, size_t len)
106de001ba2Schristos {
107de001ba2Schristos 	dookie_t *d = dookie;
108de001ba2Schristos 	ssize_t nr;
109de001ba2Schristos 	size_t l = len;
110de001ba2Schristos 	const char *b = buf;
111de001ba2Schristos 
112de001ba2Schristos 	while (l) {
113de001ba2Schristos 		size_t nw = l > INT_MAX ? INT_MAX : l;
114de001ba2Schristos 		nr = (*d->writefn)(d->cookie, buf, (int)nw);
115de001ba2Schristos 		if (nr == -1) {
116de001ba2Schristos 			if (len == l)
117de001ba2Schristos 				return -1;
118de001ba2Schristos 			else
119de001ba2Schristos 				return len - l;
120de001ba2Schristos 		}
121de001ba2Schristos 		b += nr;
122de001ba2Schristos 		l -= nr;
123de001ba2Schristos 	}
124de001ba2Schristos 	return len;
125de001ba2Schristos }
126de001ba2Schristos 
127de001ba2Schristos static off_t
cseekfn(void * dookie,off_t off,int whence)128de001ba2Schristos cseekfn(void *dookie, off_t off, int whence)
129de001ba2Schristos {
130de001ba2Schristos 	dookie_t *d = dookie;
131de001ba2Schristos 	return (*d->seekfn)(d->cookie, off, whence);
132de001ba2Schristos }
133de001ba2Schristos 
134de001ba2Schristos static int
cclosefn(void * dookie)135de001ba2Schristos cclosefn(void *dookie)
136de001ba2Schristos {
137de001ba2Schristos 	dookie_t *d = dookie;
138de001ba2Schristos 	void *c = d->cookie;
139de001ba2Schristos 	int (*cf)(void *) = d->closefn;
140de001ba2Schristos 	free(dookie);
141*5b486aceSchristos 	if (cf == NULL)
142*5b486aceSchristos 		return 0;
143de001ba2Schristos 	return (*cf)(c);
144de001ba2Schristos }
145de001ba2Schristos 
146de001ba2Schristos FILE *
funopen(const void * cookie,int (* readfn)(void *,char *,int),int (* writefn)(void *,const char *,int),off_t (* seekfn)(void *,off_t,int),int (* closefn)(void *))147de001ba2Schristos funopen(const void *cookie,
148de001ba2Schristos     int (*readfn)(void *, char *, int),
149de001ba2Schristos     int (*writefn)(void *, const char *, int),
150de001ba2Schristos     off_t (*seekfn)(void *, off_t, int),
151de001ba2Schristos     int (*closefn)(void *))
152de001ba2Schristos {
153de001ba2Schristos 	dookie_t *d;
154de001ba2Schristos 	FILE *fp;
155de001ba2Schristos 
156de001ba2Schristos 	if ((d = malloc(sizeof(*d))) == NULL)
157de001ba2Schristos 		return NULL;
158de001ba2Schristos 
159de001ba2Schristos 	d->cookie = __UNCONST(cookie);
160de001ba2Schristos 	d->readfn = readfn;
161de001ba2Schristos 	d->writefn = writefn;
162de001ba2Schristos 	d->seekfn = seekfn;
163de001ba2Schristos 	d->closefn = closefn;
16461a429c0Schristos 	fp = funopen2(d,
16561a429c0Schristos 	    d->readfn ? creadfn : NULL,
16661a429c0Schristos 	    d->writefn ? cwritefn : NULL,
16761a429c0Schristos 	    d->seekfn ? cseekfn : NULL,
168*5b486aceSchristos 	    NULL, cclosefn);
169de001ba2Schristos 	if (fp != NULL)
170de001ba2Schristos 		return fp;
171de001ba2Schristos 	free(d);
172de001ba2Schristos 	return NULL;
173de001ba2Schristos  }
174