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