xref: /dragonfly/lib/libc/stdio/fmemopen.c (revision 0d5acd74)
1395d17dfSVenkatesh Srinivas /* $NetBSD: fmemopen.c,v 1.4 2010/09/27 16:50:13 tnozaki Exp $ */
2395d17dfSVenkatesh Srinivas 
3395d17dfSVenkatesh Srinivas /*-
4395d17dfSVenkatesh Srinivas  * Copyright (c)2007, 2010 Takehiko NOZAKI,
5*dbd7c185SVenkatesh Srinivas  * Copyright (c) 2012, Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
6395d17dfSVenkatesh Srinivas  * All rights reserved.
7e5afb31fSVenkatesh Srinivas  *
8e5afb31fSVenkatesh Srinivas  * Redistribution and use in source and binary forms, with or without
9e5afb31fSVenkatesh Srinivas  * modification, are permitted provided that the following conditions
10e5afb31fSVenkatesh Srinivas  * are met:
11e5afb31fSVenkatesh Srinivas  * 1. Redistributions of source code must retain the above copyright
12e5afb31fSVenkatesh Srinivas  *    notice, this list of conditions and the following disclaimer.
13e5afb31fSVenkatesh Srinivas  * 2. Redistributions in binary form must reproduce the above copyright
14395d17dfSVenkatesh Srinivas  *    notice, this list of conditions and the following disclaimer in the
15395d17dfSVenkatesh Srinivas  *    documentation and/or other materials provided with the distribution.
16e5afb31fSVenkatesh Srinivas  *
17395d17dfSVenkatesh Srinivas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18395d17dfSVenkatesh Srinivas  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19395d17dfSVenkatesh Srinivas  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20395d17dfSVenkatesh Srinivas  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21395d17dfSVenkatesh Srinivas  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22395d17dfSVenkatesh Srinivas  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23395d17dfSVenkatesh Srinivas  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24395d17dfSVenkatesh Srinivas  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25395d17dfSVenkatesh Srinivas  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26395d17dfSVenkatesh Srinivas  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27e5afb31fSVenkatesh Srinivas  * SUCH DAMAGE.
28e5afb31fSVenkatesh Srinivas  */
29e5afb31fSVenkatesh Srinivas 
30*dbd7c185SVenkatesh Srinivas #include <sys/param.h>
31395d17dfSVenkatesh Srinivas #include <assert.h>
32395d17dfSVenkatesh Srinivas #include <errno.h>
33395d17dfSVenkatesh Srinivas #include <fcntl.h>
34395d17dfSVenkatesh Srinivas #include <stddef.h>
35e5afb31fSVenkatesh Srinivas #include <stdio.h>
36e5afb31fSVenkatesh Srinivas #include <stdlib.h>
37e5afb31fSVenkatesh Srinivas 
38395d17dfSVenkatesh Srinivas #include "local.h"
39e5afb31fSVenkatesh Srinivas 
40e5afb31fSVenkatesh Srinivas struct fmemopen_cookie {
41395d17dfSVenkatesh Srinivas 	char *head, *tail, *cur, *eob;
42e5afb31fSVenkatesh Srinivas };
43e5afb31fSVenkatesh Srinivas 
44c43830c0SSascha Wildner static int
fmemopen_read(void * cookie,char * buf,int nbytes)45395d17dfSVenkatesh Srinivas fmemopen_read(void *cookie, char *buf, int nbytes)
46e5afb31fSVenkatesh Srinivas {
47395d17dfSVenkatesh Srinivas 	struct fmemopen_cookie *p;
48395d17dfSVenkatesh Srinivas 	char *s;
49395d17dfSVenkatesh Srinivas 	int len;
50e5afb31fSVenkatesh Srinivas 
51395d17dfSVenkatesh Srinivas 	assert(cookie != NULL);
52395d17dfSVenkatesh Srinivas 	assert(buf != NULL && nbytes > 0);
53395d17dfSVenkatesh Srinivas 
54*dbd7c185SVenkatesh Srinivas 	p = cookie;
55395d17dfSVenkatesh Srinivas 	s = p->cur;
56*dbd7c185SVenkatesh Srinivas 	len = MIN(p->tail - p->cur, nbytes);
57395d17dfSVenkatesh Srinivas 	bcopy(p->cur, buf, len);
58395d17dfSVenkatesh Srinivas 	p->cur += len;
59395d17dfSVenkatesh Srinivas 
60395d17dfSVenkatesh Srinivas 	return (int)(p->cur - s);
61e5afb31fSVenkatesh Srinivas }
62e5afb31fSVenkatesh Srinivas 
63395d17dfSVenkatesh Srinivas static int
fmemopen_write(void * cookie,const char * buf,int nbytes)64395d17dfSVenkatesh Srinivas fmemopen_write(void *cookie, const char *buf, int nbytes)
65395d17dfSVenkatesh Srinivas {
66395d17dfSVenkatesh Srinivas 	struct fmemopen_cookie *p;
67395d17dfSVenkatesh Srinivas 	char *s;
68*dbd7c185SVenkatesh Srinivas 	int len;
69e5afb31fSVenkatesh Srinivas 
70395d17dfSVenkatesh Srinivas 	assert(cookie != NULL);
71395d17dfSVenkatesh Srinivas 	assert(buf != NULL && nbytes > 0);
72395d17dfSVenkatesh Srinivas 
73*dbd7c185SVenkatesh Srinivas 	p = cookie;
74395d17dfSVenkatesh Srinivas 	if (p->cur >= p->tail)
75395d17dfSVenkatesh Srinivas 		return 0;
76395d17dfSVenkatesh Srinivas 	s = p->cur;
77*dbd7c185SVenkatesh Srinivas 
78*dbd7c185SVenkatesh Srinivas 	len = MIN(p->tail - p->cur, nbytes);
79*dbd7c185SVenkatesh Srinivas 
80*dbd7c185SVenkatesh Srinivas 	bcopy(buf, p->cur, len);
81*dbd7c185SVenkatesh Srinivas 
82*dbd7c185SVenkatesh Srinivas 	p->cur += len - 1;
83395d17dfSVenkatesh Srinivas 	if (p->cur == p->tail - 1) {
84395d17dfSVenkatesh Srinivas 		*p->cur = '\0';
85*dbd7c185SVenkatesh Srinivas 		if (buf[len - 1] == '\0')
86*dbd7c185SVenkatesh Srinivas 			p->cur++;
87*dbd7c185SVenkatesh Srinivas 	} else {
88*dbd7c185SVenkatesh Srinivas 		*++p->cur = '\0';
89*dbd7c185SVenkatesh Srinivas 	}
90*dbd7c185SVenkatesh Srinivas 
91395d17dfSVenkatesh Srinivas 	if (p->cur > p->eob)
92395d17dfSVenkatesh Srinivas 		p->eob = p->cur;
93e5afb31fSVenkatesh Srinivas 
94395d17dfSVenkatesh Srinivas 	return (int)(p->cur - s);
95e5afb31fSVenkatesh Srinivas }
96e5afb31fSVenkatesh Srinivas 
97c43830c0SSascha Wildner static fpos_t
fmemopen_seek(void * cookie,fpos_t offset,int whence)98395d17dfSVenkatesh Srinivas fmemopen_seek(void *cookie, fpos_t offset, int whence)
99e5afb31fSVenkatesh Srinivas {
100395d17dfSVenkatesh Srinivas 	struct fmemopen_cookie *p;
101e5afb31fSVenkatesh Srinivas 
102395d17dfSVenkatesh Srinivas 	assert(cookie != NULL);
103e5afb31fSVenkatesh Srinivas 
104395d17dfSVenkatesh Srinivas 	p = (struct fmemopen_cookie *)cookie;
105e5afb31fSVenkatesh Srinivas 	switch (whence) {
106395d17dfSVenkatesh Srinivas 	case SEEK_SET:
107e5afb31fSVenkatesh Srinivas 		break;
108395d17dfSVenkatesh Srinivas 	case SEEK_CUR:
109395d17dfSVenkatesh Srinivas 		offset += p->cur - p->head;
110e5afb31fSVenkatesh Srinivas 		break;
111395d17dfSVenkatesh Srinivas 	case SEEK_END:
112395d17dfSVenkatesh Srinivas 		offset += p->eob - p->head;
113e5afb31fSVenkatesh Srinivas 		break;
114395d17dfSVenkatesh Srinivas 	default:
115395d17dfSVenkatesh Srinivas 		errno = EINVAL;
116395d17dfSVenkatesh Srinivas 		goto error;
117e5afb31fSVenkatesh Srinivas 	}
118395d17dfSVenkatesh Srinivas 	if (offset >= (fpos_t)0 && offset <= p->tail - p->head) {
119395d17dfSVenkatesh Srinivas 		p->cur = p->head + (ptrdiff_t)offset;
120395d17dfSVenkatesh Srinivas 		return (fpos_t)(p->cur - p->head);
121395d17dfSVenkatesh Srinivas 	}
122395d17dfSVenkatesh Srinivas error:
123395d17dfSVenkatesh Srinivas 	return (fpos_t)-1;
124e5afb31fSVenkatesh Srinivas }
125e5afb31fSVenkatesh Srinivas 
126c43830c0SSascha Wildner static int
fmemopen_close0(void * cookie)127395d17dfSVenkatesh Srinivas fmemopen_close0(void *cookie)
128e5afb31fSVenkatesh Srinivas {
129395d17dfSVenkatesh Srinivas 	assert(cookie != NULL);
1304ad99553SSascha Wildner 
131395d17dfSVenkatesh Srinivas 	free(cookie);
132e5afb31fSVenkatesh Srinivas 
133395d17dfSVenkatesh Srinivas 	return 0;
134e5afb31fSVenkatesh Srinivas }
135e5afb31fSVenkatesh Srinivas 
136395d17dfSVenkatesh Srinivas static int
fmemopen_close1(void * cookie)137395d17dfSVenkatesh Srinivas fmemopen_close1(void *cookie)
138395d17dfSVenkatesh Srinivas {
139395d17dfSVenkatesh Srinivas 	struct fmemopen_cookie *p;
140395d17dfSVenkatesh Srinivas 
141395d17dfSVenkatesh Srinivas 	assert(cookie != NULL);
142395d17dfSVenkatesh Srinivas 
143*dbd7c185SVenkatesh Srinivas 	p = cookie;
144395d17dfSVenkatesh Srinivas 	free(p->head);
145395d17dfSVenkatesh Srinivas 	free(p);
146395d17dfSVenkatesh Srinivas 
147395d17dfSVenkatesh Srinivas 	return 0;
148395d17dfSVenkatesh Srinivas }
149395d17dfSVenkatesh Srinivas 
150395d17dfSVenkatesh Srinivas 
151c43830c0SSascha Wildner FILE *
fmemopen(void * __restrict buf,size_t size,const char * __restrict mode)152395d17dfSVenkatesh Srinivas fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
153e5afb31fSVenkatesh Srinivas {
154395d17dfSVenkatesh Srinivas 	int flags, oflags;
155395d17dfSVenkatesh Srinivas 	FILE *fp;
156395d17dfSVenkatesh Srinivas 	struct fmemopen_cookie *cookie;
157e5afb31fSVenkatesh Srinivas 
158395d17dfSVenkatesh Srinivas 	if (size < (size_t)1)
159395d17dfSVenkatesh Srinivas 		goto invalid;
160395d17dfSVenkatesh Srinivas 
161395d17dfSVenkatesh Srinivas 	flags = __sflags(mode, &oflags);
162395d17dfSVenkatesh Srinivas 	if (flags == 0)
163e5afb31fSVenkatesh Srinivas 		return NULL;
164e5afb31fSVenkatesh Srinivas 
165395d17dfSVenkatesh Srinivas 	if ((oflags & O_RDWR) == 0 && buf == NULL)
166395d17dfSVenkatesh Srinivas 		goto invalid;
167e5afb31fSVenkatesh Srinivas 
168395d17dfSVenkatesh Srinivas 	fp = __sfp();
169395d17dfSVenkatesh Srinivas 	if (fp == NULL)
170e5afb31fSVenkatesh Srinivas 		return NULL;
171395d17dfSVenkatesh Srinivas 
172395d17dfSVenkatesh Srinivas 	cookie = malloc(sizeof(*cookie));
173395d17dfSVenkatesh Srinivas 	if (cookie == NULL)
174395d17dfSVenkatesh Srinivas 		goto release;
175395d17dfSVenkatesh Srinivas 
176395d17dfSVenkatesh Srinivas 	if (buf == NULL) {
177395d17dfSVenkatesh Srinivas 		cookie->head = malloc(size);
178395d17dfSVenkatesh Srinivas 		if (cookie->head == NULL) {
179395d17dfSVenkatesh Srinivas 			free(cookie);
180395d17dfSVenkatesh Srinivas 			goto release;
181e5afb31fSVenkatesh Srinivas 		}
182395d17dfSVenkatesh Srinivas 		*cookie->head = '\0';
183395d17dfSVenkatesh Srinivas 		fp->_close = &fmemopen_close1;
184e5afb31fSVenkatesh Srinivas 	} else {
185395d17dfSVenkatesh Srinivas 		cookie->head = (char *)buf;
186395d17dfSVenkatesh Srinivas 		if (oflags & O_TRUNC)
187395d17dfSVenkatesh Srinivas 			*cookie->head = '\0';
188395d17dfSVenkatesh Srinivas 		fp->_close = &fmemopen_close0;
189e5afb31fSVenkatesh Srinivas 	}
190e5afb31fSVenkatesh Srinivas 
191395d17dfSVenkatesh Srinivas 	cookie->tail = cookie->head + size;
192395d17dfSVenkatesh Srinivas 	cookie->eob  = cookie->head;
193395d17dfSVenkatesh Srinivas 	do {
194395d17dfSVenkatesh Srinivas 		if (*cookie->eob == '\0')
195395d17dfSVenkatesh Srinivas 			break;
196395d17dfSVenkatesh Srinivas 		++cookie->eob;
197395d17dfSVenkatesh Srinivas 	} while (--size > 0);
198e5afb31fSVenkatesh Srinivas 
199395d17dfSVenkatesh Srinivas 	cookie->cur = (oflags & O_APPEND) ? cookie->eob : cookie->head;
200e5afb31fSVenkatesh Srinivas 
201395d17dfSVenkatesh Srinivas 	fp->pub._flags  = flags;
202395d17dfSVenkatesh Srinivas 	fp->_write  = (flags & __SRD) ? NULL : &fmemopen_write;
203395d17dfSVenkatesh Srinivas 	fp->_read   = (flags & __SWR) ? NULL : &fmemopen_read;
204395d17dfSVenkatesh Srinivas 	fp->_seek   = &fmemopen_seek;
205395d17dfSVenkatesh Srinivas 	fp->_cookie = (void *)cookie;
206e5afb31fSVenkatesh Srinivas 
207395d17dfSVenkatesh Srinivas 	return fp;
208395d17dfSVenkatesh Srinivas 
209395d17dfSVenkatesh Srinivas invalid:
210395d17dfSVenkatesh Srinivas 	errno = EINVAL;
211395d17dfSVenkatesh Srinivas 	return NULL;
212395d17dfSVenkatesh Srinivas 
213395d17dfSVenkatesh Srinivas release:
214395d17dfSVenkatesh Srinivas 	fp->pub._flags = 0;
215395d17dfSVenkatesh Srinivas 	return NULL;
216e5afb31fSVenkatesh Srinivas }
217395d17dfSVenkatesh Srinivas 
218