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