xref: /dflybsd-src/lib/libc/stdio/open_memstream.c (revision cfdfe49dcfb77e81b1e4734386a051b6a5a6f104)
1*cfdfe49dSVenkatesh Srinivas /*-
2*cfdfe49dSVenkatesh Srinivas  * Copyright (c) 2011 Venkatesh Srinivas,
3*cfdfe49dSVenkatesh Srinivas  * All rights reserved.
4*cfdfe49dSVenkatesh Srinivas  *
5*cfdfe49dSVenkatesh Srinivas  * Redistribution and use in source and binary forms, with or without
6*cfdfe49dSVenkatesh Srinivas  * modification, are permitted provided that the following conditions
7*cfdfe49dSVenkatesh Srinivas  * are met:
8*cfdfe49dSVenkatesh Srinivas  * 1. Redistributions of source code must retain the above copyright
9*cfdfe49dSVenkatesh Srinivas  *    notice, this list of conditions and the following disclaimer.
10*cfdfe49dSVenkatesh Srinivas  * 2. Redistributions in binary form must reproduce the above copyright
11*cfdfe49dSVenkatesh Srinivas  *    notice, this list of conditions and the following disclaimer in the
12*cfdfe49dSVenkatesh Srinivas  *    documentation and/or other materials provided with the distribution.
13*cfdfe49dSVenkatesh Srinivas  *
14*cfdfe49dSVenkatesh Srinivas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*cfdfe49dSVenkatesh Srinivas  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*cfdfe49dSVenkatesh Srinivas  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*cfdfe49dSVenkatesh Srinivas  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*cfdfe49dSVenkatesh Srinivas  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*cfdfe49dSVenkatesh Srinivas  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*cfdfe49dSVenkatesh Srinivas  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*cfdfe49dSVenkatesh Srinivas  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*cfdfe49dSVenkatesh Srinivas  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*cfdfe49dSVenkatesh Srinivas  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*cfdfe49dSVenkatesh Srinivas  * SUCH DAMAGE.
25*cfdfe49dSVenkatesh Srinivas  */
26*cfdfe49dSVenkatesh Srinivas 
27*cfdfe49dSVenkatesh Srinivas #include <stdio.h>
28*cfdfe49dSVenkatesh Srinivas #include <stdlib.h>
29*cfdfe49dSVenkatesh Srinivas #include <errno.h>
30*cfdfe49dSVenkatesh Srinivas 
31*cfdfe49dSVenkatesh Srinivas struct memstream_cookie {
32*cfdfe49dSVenkatesh Srinivas 	char **pub_buf;
33*cfdfe49dSVenkatesh Srinivas 	size_t *pub_size;
34*cfdfe49dSVenkatesh Srinivas 
35*cfdfe49dSVenkatesh Srinivas 	char *head;
36*cfdfe49dSVenkatesh Srinivas 	size_t pos;
37*cfdfe49dSVenkatesh Srinivas 	size_t tail;
38*cfdfe49dSVenkatesh Srinivas };
39*cfdfe49dSVenkatesh Srinivas 
40*cfdfe49dSVenkatesh Srinivas static void
41*cfdfe49dSVenkatesh Srinivas sync_pub_cookie(struct memstream_cookie *cp)
42*cfdfe49dSVenkatesh Srinivas {
43*cfdfe49dSVenkatesh Srinivas 	*cp->pub_buf = cp->head;
44*cfdfe49dSVenkatesh Srinivas 	*cp->pub_size = cp->tail;
45*cfdfe49dSVenkatesh Srinivas }
46*cfdfe49dSVenkatesh Srinivas 
47*cfdfe49dSVenkatesh Srinivas static int
48*cfdfe49dSVenkatesh Srinivas memstream_writefn(void *cookie, const char *buf, int len)
49*cfdfe49dSVenkatesh Srinivas {
50*cfdfe49dSVenkatesh Srinivas 	struct memstream_cookie *c;
51*cfdfe49dSVenkatesh Srinivas 	size_t reqsize;
52*cfdfe49dSVenkatesh Srinivas 
53*cfdfe49dSVenkatesh Srinivas 	c = cookie;
54*cfdfe49dSVenkatesh Srinivas 
55*cfdfe49dSVenkatesh Srinivas 	/* Write is contained within valid region */
56*cfdfe49dSVenkatesh Srinivas 	if (c->pos + len < c->tail) {
57*cfdfe49dSVenkatesh Srinivas 		bcopy(buf, &c->head[c->pos], len);
58*cfdfe49dSVenkatesh Srinivas 		c->pos += len;
59*cfdfe49dSVenkatesh Srinivas 		return (len);
60*cfdfe49dSVenkatesh Srinivas 	}
61*cfdfe49dSVenkatesh Srinivas 
62*cfdfe49dSVenkatesh Srinivas 	/* Write results in resizing buffer */
63*cfdfe49dSVenkatesh Srinivas 	reqsize = c->pos + len + 1;
64*cfdfe49dSVenkatesh Srinivas 	c->head = reallocf(c->head, reqsize);
65*cfdfe49dSVenkatesh Srinivas 	if (c->head == NULL) {
66*cfdfe49dSVenkatesh Srinivas 		errno = ENOMEM;
67*cfdfe49dSVenkatesh Srinivas 		return (0);
68*cfdfe49dSVenkatesh Srinivas 	}
69*cfdfe49dSVenkatesh Srinivas 
70*cfdfe49dSVenkatesh Srinivas 	bcopy(buf, &c->head[c->pos], len);
71*cfdfe49dSVenkatesh Srinivas 
72*cfdfe49dSVenkatesh Srinivas 	c->tail = c->pos + len;
73*cfdfe49dSVenkatesh Srinivas 	c->pos = c->tail;
74*cfdfe49dSVenkatesh Srinivas 	c->head[c->tail] = '\0';
75*cfdfe49dSVenkatesh Srinivas 
76*cfdfe49dSVenkatesh Srinivas 	sync_pub_cookie(c);
77*cfdfe49dSVenkatesh Srinivas 
78*cfdfe49dSVenkatesh Srinivas 	return (len);
79*cfdfe49dSVenkatesh Srinivas }
80*cfdfe49dSVenkatesh Srinivas 
81*cfdfe49dSVenkatesh Srinivas static fpos_t
82*cfdfe49dSVenkatesh Srinivas memstream_seekfn(void *cookie, fpos_t pos, int whence)
83*cfdfe49dSVenkatesh Srinivas {
84*cfdfe49dSVenkatesh Srinivas 	struct memstream_cookie *c;
85*cfdfe49dSVenkatesh Srinivas 
86*cfdfe49dSVenkatesh Srinivas 	c = cookie;
87*cfdfe49dSVenkatesh Srinivas 
88*cfdfe49dSVenkatesh Srinivas 	/* XXX: Should validate SEEK_SET and SEEK_CUR positions */
89*cfdfe49dSVenkatesh Srinivas 	/* XXX: What to do wrt SEEK_END? Is it relative to tail? to pos? */
90*cfdfe49dSVenkatesh Srinivas 
91*cfdfe49dSVenkatesh Srinivas 	switch(whence) {
92*cfdfe49dSVenkatesh Srinivas 	case (SEEK_SET):
93*cfdfe49dSVenkatesh Srinivas 		c->pos = pos;
94*cfdfe49dSVenkatesh Srinivas 		return (c->pos);
95*cfdfe49dSVenkatesh Srinivas 		break;
96*cfdfe49dSVenkatesh Srinivas 	case (SEEK_CUR):
97*cfdfe49dSVenkatesh Srinivas 		c->pos += pos;
98*cfdfe49dSVenkatesh Srinivas 		return (c->pos);
99*cfdfe49dSVenkatesh Srinivas 		break;
100*cfdfe49dSVenkatesh Srinivas 	case (SEEK_END):
101*cfdfe49dSVenkatesh Srinivas 	default:
102*cfdfe49dSVenkatesh Srinivas 		errno = EINVAL;
103*cfdfe49dSVenkatesh Srinivas 		return (fpos_t) -1;
104*cfdfe49dSVenkatesh Srinivas 	}
105*cfdfe49dSVenkatesh Srinivas }
106*cfdfe49dSVenkatesh Srinivas 
107*cfdfe49dSVenkatesh Srinivas static int
108*cfdfe49dSVenkatesh Srinivas memstream_closefn(void *cookie)
109*cfdfe49dSVenkatesh Srinivas {
110*cfdfe49dSVenkatesh Srinivas 	struct memstream_cookie *c;
111*cfdfe49dSVenkatesh Srinivas 
112*cfdfe49dSVenkatesh Srinivas 	c = cookie;
113*cfdfe49dSVenkatesh Srinivas 
114*cfdfe49dSVenkatesh Srinivas 	sync_pub_cookie(c);
115*cfdfe49dSVenkatesh Srinivas 
116*cfdfe49dSVenkatesh Srinivas 	free(c);
117*cfdfe49dSVenkatesh Srinivas }
118*cfdfe49dSVenkatesh Srinivas 
119*cfdfe49dSVenkatesh Srinivas FILE *
120*cfdfe49dSVenkatesh Srinivas open_memstream(char **bufp, size_t *sizep)
121*cfdfe49dSVenkatesh Srinivas {
122*cfdfe49dSVenkatesh Srinivas 	FILE *fp;
123*cfdfe49dSVenkatesh Srinivas 	struct memstream_cookie *c;
124*cfdfe49dSVenkatesh Srinivas 
125*cfdfe49dSVenkatesh Srinivas 	fp = NULL;
126*cfdfe49dSVenkatesh Srinivas 	if (bufp == NULL || sizep == NULL) {
127*cfdfe49dSVenkatesh Srinivas 		errno = EINVAL;
128*cfdfe49dSVenkatesh Srinivas 		goto out;
129*cfdfe49dSVenkatesh Srinivas 	}
130*cfdfe49dSVenkatesh Srinivas 
131*cfdfe49dSVenkatesh Srinivas 	c = malloc(sizeof(struct memstream_cookie));
132*cfdfe49dSVenkatesh Srinivas 	if (c == NULL) {
133*cfdfe49dSVenkatesh Srinivas 		errno = EINVAL;
134*cfdfe49dSVenkatesh Srinivas 		goto out;
135*cfdfe49dSVenkatesh Srinivas 	}
136*cfdfe49dSVenkatesh Srinivas 
137*cfdfe49dSVenkatesh Srinivas 	fp = funopen(c,
138*cfdfe49dSVenkatesh Srinivas 		     NULL,
139*cfdfe49dSVenkatesh Srinivas 		     memstream_writefn,
140*cfdfe49dSVenkatesh Srinivas 		     memstream_seekfn,
141*cfdfe49dSVenkatesh Srinivas 		     memstream_closefn
142*cfdfe49dSVenkatesh Srinivas 		    );
143*cfdfe49dSVenkatesh Srinivas 
144*cfdfe49dSVenkatesh Srinivas 	if (fp == NULL) {
145*cfdfe49dSVenkatesh Srinivas 		free(c);
146*cfdfe49dSVenkatesh Srinivas 		errno = ENOMEM;
147*cfdfe49dSVenkatesh Srinivas 		goto out;
148*cfdfe49dSVenkatesh Srinivas 	}
149*cfdfe49dSVenkatesh Srinivas 
150*cfdfe49dSVenkatesh Srinivas 	c->pub_buf = bufp;
151*cfdfe49dSVenkatesh Srinivas 	c->pub_size = sizep;
152*cfdfe49dSVenkatesh Srinivas 	c->head = NULL;
153*cfdfe49dSVenkatesh Srinivas 	c->tail = 0;
154*cfdfe49dSVenkatesh Srinivas 	c->pos = 0;
155*cfdfe49dSVenkatesh Srinivas 
156*cfdfe49dSVenkatesh Srinivas out:
157*cfdfe49dSVenkatesh Srinivas 	return (fp);
158*cfdfe49dSVenkatesh Srinivas }
159