1*96c95412SPietro Cerutti /*- 2*96c95412SPietro Cerutti Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org> 3*96c95412SPietro Cerutti 4*96c95412SPietro Cerutti Redistribution and use in source and binary forms, with or without 5*96c95412SPietro Cerutti modification, are permitted provided that the following conditions 6*96c95412SPietro Cerutti are met: 7*96c95412SPietro Cerutti 1. Redistributions of source code must retain the above copyright 8*96c95412SPietro Cerutti notice, this list of conditions and the following disclaimer. 9*96c95412SPietro Cerutti 2. Redistributions in binary form must reproduce the above copyright 10*96c95412SPietro Cerutti notice, this list of conditions and the following disclaimer in the 11*96c95412SPietro Cerutti documentation and/or other materials provided with the distribution. 12*96c95412SPietro Cerutti 13*96c95412SPietro Cerutti THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*96c95412SPietro Cerutti ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*96c95412SPietro Cerutti IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*96c95412SPietro Cerutti ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17*96c95412SPietro Cerutti FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*96c95412SPietro Cerutti DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*96c95412SPietro Cerutti OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*96c95412SPietro Cerutti HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*96c95412SPietro Cerutti LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*96c95412SPietro Cerutti OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*96c95412SPietro Cerutti SUCH DAMAGE. 24*96c95412SPietro Cerutti */ 25*96c95412SPietro Cerutti 26*96c95412SPietro Cerutti #include <sys/cdefs.h> 27*96c95412SPietro Cerutti __FBSDID("$FreeBSD$"); 28*96c95412SPietro Cerutti 29*96c95412SPietro Cerutti #include <stdio.h> 30*96c95412SPietro Cerutti #include <stdlib.h> 31*96c95412SPietro Cerutti #include <string.h> 32*96c95412SPietro Cerutti #include <errno.h> 33*96c95412SPietro Cerutti 34*96c95412SPietro Cerutti struct __fmemopen_cookie 35*96c95412SPietro Cerutti { 36*96c95412SPietro Cerutti char *buf; /* pointer to the memory region */ 37*96c95412SPietro Cerutti char own; /* did we allocate the buffer ourselves? */ 38*96c95412SPietro Cerutti long len; /* buffer length in bytes */ 39*96c95412SPietro Cerutti long off; /* current offset into the buffer */ 40*96c95412SPietro Cerutti }; 41*96c95412SPietro Cerutti 42*96c95412SPietro Cerutti static int fmemopen_read (void *cookie, char *buf, int nbytes); 43*96c95412SPietro Cerutti static int fmemopen_write (void *cookie, const char *buf, int nbytes); 44*96c95412SPietro Cerutti static fpos_t fmemopen_seek (void *cookie, fpos_t offset, int whence); 45*96c95412SPietro Cerutti static int fmemopen_close (void *cookie); 46*96c95412SPietro Cerutti 47*96c95412SPietro Cerutti FILE * 48*96c95412SPietro Cerutti fmemopen (void * __restrict buf, size_t size, const char * __restrict mode) 49*96c95412SPietro Cerutti { 50*96c95412SPietro Cerutti /* allocate cookie */ 51*96c95412SPietro Cerutti struct __fmemopen_cookie *ck = malloc (sizeof (struct __fmemopen_cookie)); 52*96c95412SPietro Cerutti if (ck == NULL) { 53*96c95412SPietro Cerutti errno = ENOMEM; 54*96c95412SPietro Cerutti return (NULL); 55*96c95412SPietro Cerutti } 56*96c95412SPietro Cerutti 57*96c95412SPietro Cerutti ck->off = 0; 58*96c95412SPietro Cerutti ck->len = size; 59*96c95412SPietro Cerutti 60*96c95412SPietro Cerutti /* do we have to allocate the buffer ourselves? */ 61*96c95412SPietro Cerutti ck->own = ((ck->buf = buf) == NULL); 62*96c95412SPietro Cerutti if (ck->own) { 63*96c95412SPietro Cerutti ck->buf = malloc (size); 64*96c95412SPietro Cerutti if (ck->buf == NULL) { 65*96c95412SPietro Cerutti free (ck); 66*96c95412SPietro Cerutti errno = ENOMEM; 67*96c95412SPietro Cerutti return (NULL); 68*96c95412SPietro Cerutti } 69*96c95412SPietro Cerutti ck->buf[0] = '\0'; 70*96c95412SPietro Cerutti } 71*96c95412SPietro Cerutti 72*96c95412SPietro Cerutti if (mode[0] == 'a') 73*96c95412SPietro Cerutti ck->off = strnlen(ck->buf, ck->len); 74*96c95412SPietro Cerutti 75*96c95412SPietro Cerutti /* actuall wrapper */ 76*96c95412SPietro Cerutti FILE *f = funopen ((void *)ck, fmemopen_read, fmemopen_write, 77*96c95412SPietro Cerutti fmemopen_seek, fmemopen_close); 78*96c95412SPietro Cerutti 79*96c95412SPietro Cerutti if (f == NULL) { 80*96c95412SPietro Cerutti if (ck->own) 81*96c95412SPietro Cerutti free (ck->buf); 82*96c95412SPietro Cerutti free (ck); 83*96c95412SPietro Cerutti return (NULL); 84*96c95412SPietro Cerutti } 85*96c95412SPietro Cerutti 86*96c95412SPietro Cerutti /* turn off buffering, so a write past the end of the buffer 87*96c95412SPietro Cerutti * correctly returns a short object count */ 88*96c95412SPietro Cerutti setvbuf (f, (char *) NULL, _IONBF, 0); 89*96c95412SPietro Cerutti 90*96c95412SPietro Cerutti return (f); 91*96c95412SPietro Cerutti } 92*96c95412SPietro Cerutti 93*96c95412SPietro Cerutti static int 94*96c95412SPietro Cerutti fmemopen_read (void *cookie, char *buf, int nbytes) 95*96c95412SPietro Cerutti { 96*96c95412SPietro Cerutti struct __fmemopen_cookie *ck = cookie; 97*96c95412SPietro Cerutti 98*96c95412SPietro Cerutti if (nbytes > ck->len - ck->off) 99*96c95412SPietro Cerutti nbytes = ck->len - ck->off; 100*96c95412SPietro Cerutti 101*96c95412SPietro Cerutti if (nbytes == 0) 102*96c95412SPietro Cerutti return (0); 103*96c95412SPietro Cerutti 104*96c95412SPietro Cerutti memcpy (buf, ck->buf + ck->off, nbytes); 105*96c95412SPietro Cerutti 106*96c95412SPietro Cerutti ck->off += nbytes; 107*96c95412SPietro Cerutti 108*96c95412SPietro Cerutti return (nbytes); 109*96c95412SPietro Cerutti } 110*96c95412SPietro Cerutti 111*96c95412SPietro Cerutti static int 112*96c95412SPietro Cerutti fmemopen_write (void *cookie, const char *buf, int nbytes) 113*96c95412SPietro Cerutti { 114*96c95412SPietro Cerutti struct __fmemopen_cookie *ck = cookie; 115*96c95412SPietro Cerutti 116*96c95412SPietro Cerutti if (nbytes > ck->len - ck->off) 117*96c95412SPietro Cerutti nbytes = ck->len - ck->off; 118*96c95412SPietro Cerutti 119*96c95412SPietro Cerutti if (nbytes == 0) 120*96c95412SPietro Cerutti return (0); 121*96c95412SPietro Cerutti 122*96c95412SPietro Cerutti memcpy (ck->buf + ck->off, buf, nbytes); 123*96c95412SPietro Cerutti 124*96c95412SPietro Cerutti ck->off += nbytes; 125*96c95412SPietro Cerutti 126*96c95412SPietro Cerutti if (ck->off < ck->len && ck->buf[ck->off - 1] != '\0') 127*96c95412SPietro Cerutti ck->buf[ck->off] = '\0'; 128*96c95412SPietro Cerutti 129*96c95412SPietro Cerutti return (nbytes); 130*96c95412SPietro Cerutti } 131*96c95412SPietro Cerutti 132*96c95412SPietro Cerutti static fpos_t 133*96c95412SPietro Cerutti fmemopen_seek (void *cookie, fpos_t offset, int whence) 134*96c95412SPietro Cerutti { 135*96c95412SPietro Cerutti struct __fmemopen_cookie *ck = cookie; 136*96c95412SPietro Cerutti 137*96c95412SPietro Cerutti 138*96c95412SPietro Cerutti switch (whence) { 139*96c95412SPietro Cerutti case SEEK_SET: 140*96c95412SPietro Cerutti if (offset > ck->len) { 141*96c95412SPietro Cerutti errno = EINVAL; 142*96c95412SPietro Cerutti return (-1); 143*96c95412SPietro Cerutti } 144*96c95412SPietro Cerutti ck->off = offset; 145*96c95412SPietro Cerutti break; 146*96c95412SPietro Cerutti 147*96c95412SPietro Cerutti case SEEK_CUR: 148*96c95412SPietro Cerutti if (ck->off + offset > ck->len) { 149*96c95412SPietro Cerutti errno = EINVAL; 150*96c95412SPietro Cerutti return (-1); 151*96c95412SPietro Cerutti } 152*96c95412SPietro Cerutti ck->off += offset; 153*96c95412SPietro Cerutti break; 154*96c95412SPietro Cerutti 155*96c95412SPietro Cerutti case SEEK_END: 156*96c95412SPietro Cerutti if (offset > 0 || -offset > ck->len) { 157*96c95412SPietro Cerutti errno = EINVAL; 158*96c95412SPietro Cerutti return (-1); 159*96c95412SPietro Cerutti } 160*96c95412SPietro Cerutti ck->off = ck->len + offset; 161*96c95412SPietro Cerutti break; 162*96c95412SPietro Cerutti 163*96c95412SPietro Cerutti default: 164*96c95412SPietro Cerutti errno = EINVAL; 165*96c95412SPietro Cerutti return (-1); 166*96c95412SPietro Cerutti } 167*96c95412SPietro Cerutti 168*96c95412SPietro Cerutti return (ck->off); 169*96c95412SPietro Cerutti } 170*96c95412SPietro Cerutti 171*96c95412SPietro Cerutti static int 172*96c95412SPietro Cerutti fmemopen_close (void *cookie) 173*96c95412SPietro Cerutti { 174*96c95412SPietro Cerutti struct __fmemopen_cookie *ck = cookie; 175*96c95412SPietro Cerutti 176*96c95412SPietro Cerutti if (ck->own) 177*96c95412SPietro Cerutti free (ck->buf); 178*96c95412SPietro Cerutti 179*96c95412SPietro Cerutti free (ck); 180*96c95412SPietro Cerutti 181*96c95412SPietro Cerutti return (0); 182*96c95412SPietro Cerutti } 183