1 /* 2 * Copyright (c) 2011 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Venkatesh Srinivas <me@endeavour.zapto.org>. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * ---------------------------------------------------------------------------- 36 * "THE BEER-WARE LICENSE" (Revision 42): 37 * <hiten@uk.FreeBSD.ORG> wrote this file. As long as you retain this notice 38 * you can do whatever you want with this stuff. If we meet some day, and you 39 * think this stuff is worth it, you can buy me a beer in return. Hiten Pandya. 40 * ---------------------------------------------------------------------------- 41 * 42 * $FreeBSD: src/sys/dev/md/md.c,v 1.8.2.2 2002/08/19 17:43:34 jdp Exp $ 43 */ 44 45 /* 46 * fmemopen -- Open a memory buffer stream 47 * 48 * POSIX 1003.1-2008 49 */ 50 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <sys/types.h> 55 #include <errno.h> 56 57 static int __fmemopen_closefn (void *); 58 static int __fmemopen_readfn(void *, char *, int); 59 static fpos_t __fmemopen_seekfn (void *, fpos_t, int); 60 static int __fmemopen_writefn(void *, const char *, int); 61 62 struct fmemopen_cookie { 63 char *buffer; 64 int mybuffer; 65 size_t size; 66 size_t pos; 67 size_t maxpos; 68 }; 69 70 static int 71 __fmemopen_readfn(void *cookie, char *buf, int len) 72 { 73 struct fmemopen_cookie *c; 74 75 c = (struct fmemopen_cookie *) cookie; 76 if (c == NULL) { 77 errno = EBADF; 78 return (-1); 79 } 80 81 if ((c->pos + len) > c->size) { 82 if (c->pos == c->size) 83 return -1; 84 len = c->size - c->pos; 85 } 86 87 memcpy(buf, &(c->buffer[c->pos]), len); 88 89 c->pos += len; 90 91 if (c->pos > c->maxpos) 92 c->maxpos = c->pos; 93 94 return (len); 95 } 96 97 static int 98 __fmemopen_writefn (void *cookie, const char *buf, int len) 99 { 100 struct fmemopen_cookie *c; 101 int addnullc; 102 103 c = (struct fmemopen_cookie *) cookie; 104 if (c == NULL) { 105 errno = EBADF; 106 return (-1); 107 } 108 109 addnullc = ((len == 0) || (buf[len - 1] != '\0')) ? 1 : 0; 110 111 if ((c->pos + len + addnullc) > c->size) { 112 if ((c->pos + addnullc) == c->size) 113 return -1; 114 len = c->size - c->pos - addnullc; 115 } 116 117 memcpy(&(c->buffer[c->pos]), buf, len); 118 119 c->pos += len; 120 if (c->pos > c->maxpos) { 121 c->maxpos = c->pos; 122 if (addnullc) 123 c->buffer[c->maxpos] = '\0'; 124 } 125 126 return (len); 127 } 128 129 static fpos_t 130 __fmemopen_seekfn(void *cookie, fpos_t pos, int whence) 131 { 132 fpos_t np = 0; 133 struct fmemopen_cookie *c; 134 135 c = (struct fmemopen_cookie *) cookie; 136 137 switch(whence) { 138 case (SEEK_SET): 139 np = pos; 140 break; 141 case (SEEK_CUR): 142 np = c->pos + pos; 143 break; 144 case (SEEK_END): 145 np = c->size - pos; 146 break; 147 } 148 149 if ((np < 0) || (np > c->size)) 150 return (-1); 151 152 c->pos = np; 153 154 return (np); 155 } 156 157 static int 158 __fmemopen_closefn (void *cookie) 159 { 160 struct fmemopen_cookie *c; 161 162 c = (struct fmemopen_cookie*) cookie; 163 164 if (c->mybuffer) 165 free(c->buffer); 166 free(c); 167 168 return (0); 169 } 170 171 FILE * 172 fmemopen(void *restrict buffer, size_t s, const char *restrict mode) 173 { 174 FILE *f = NULL; 175 struct fmemopen_cookie *c; 176 177 c = malloc(sizeof (struct fmemopen_cookie)); 178 if (c == NULL) 179 return NULL; 180 181 c->mybuffer = (buffer == NULL); 182 183 if (c->mybuffer) { 184 c->buffer = malloc(s); 185 if (c->buffer == NULL) { 186 free(c); 187 return NULL; 188 } 189 c->buffer[0] = '\0'; 190 } else { 191 c->buffer = buffer; 192 } 193 c->size = s; 194 if (mode[0] == 'w') 195 c->buffer[0] = '\0'; 196 c->maxpos = strlen(c->buffer); 197 198 if (mode[0] == 'a') 199 c->pos = c->maxpos; 200 else 201 c->pos = 0; 202 203 f = funopen(c, 204 __fmemopen_readfn, /* string stream read */ 205 __fmemopen_writefn, /* string stream write */ 206 __fmemopen_seekfn, /* string stream seek */ 207 __fmemopen_closefn /* string stream close */ 208 ); 209 210 if (f == NULL) 211 free(c); 212 213 return (f); 214 } 215