1 1.8 christos /* $NetBSD: fmemopen.c,v 1.8 2012/03/29 14:27:33 christos Exp $ */ 2 1.1 tnozaki 3 1.1 tnozaki /*- 4 1.1 tnozaki * Copyright (c)2007, 2010 Takehiko NOZAKI, 5 1.1 tnozaki * All rights reserved. 6 1.1 tnozaki * 7 1.1 tnozaki * Redistribution and use in source and binary forms, with or without 8 1.1 tnozaki * modification, are permitted provided that the following conditions 9 1.1 tnozaki * are met: 10 1.1 tnozaki * 1. Redistributions of source code must retain the above copyright 11 1.1 tnozaki * notice, this list of conditions and the following disclaimer. 12 1.1 tnozaki * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 tnozaki * notice, this list of conditions and the following disclaimer in the 14 1.1 tnozaki * documentation and/or other materials provided with the distribution. 15 1.1 tnozaki * 16 1.1 tnozaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 tnozaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 tnozaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 tnozaki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 tnozaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 tnozaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 tnozaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 tnozaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 tnozaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 tnozaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 tnozaki * SUCH DAMAGE. 27 1.1 tnozaki * 28 1.1 tnozaki */ 29 1.1 tnozaki 30 1.1 tnozaki #include <sys/cdefs.h> 31 1.1 tnozaki #if defined(LIBC_SCCS) && !defined(lint) 32 1.8 christos __RCSID("$NetBSD: fmemopen.c,v 1.8 2012/03/29 14:27:33 christos Exp $"); 33 1.1 tnozaki #endif /* LIBC_SCCS and not lint */ 34 1.1 tnozaki 35 1.1 tnozaki #include <assert.h> 36 1.1 tnozaki #include <errno.h> 37 1.1 tnozaki #include <fcntl.h> 38 1.3 tron #include <stddef.h> 39 1.1 tnozaki #include <stdio.h> 40 1.1 tnozaki #include <stdlib.h> 41 1.1 tnozaki 42 1.1 tnozaki #include "reentrant.h" 43 1.1 tnozaki #include "local.h" 44 1.1 tnozaki 45 1.1 tnozaki struct fmemopen_cookie { 46 1.1 tnozaki char *head, *tail, *cur, *eob; 47 1.1 tnozaki }; 48 1.1 tnozaki 49 1.7 christos static ssize_t 50 1.7 christos fmemopen_read(void *cookie, void *buf, size_t nbytes) 51 1.1 tnozaki { 52 1.1 tnozaki struct fmemopen_cookie *p; 53 1.7 christos char *s, *b = buf; 54 1.1 tnozaki 55 1.1 tnozaki _DIAGASSERT(cookie != NULL); 56 1.1 tnozaki _DIAGASSERT(buf != NULL && nbytes > 0); 57 1.1 tnozaki 58 1.1 tnozaki p = (struct fmemopen_cookie *)cookie; 59 1.1 tnozaki s = p->cur; 60 1.1 tnozaki do { 61 1.1 tnozaki if (p->cur == p->tail) 62 1.1 tnozaki break; 63 1.7 christos *b++ = *p->cur++; 64 1.1 tnozaki } while (--nbytes > 0); 65 1.1 tnozaki 66 1.7 christos return (ssize_t)(p->cur - s); 67 1.1 tnozaki } 68 1.1 tnozaki 69 1.7 christos static ssize_t 70 1.7 christos fmemopen_write(void *cookie, const void *buf, size_t nbytes) 71 1.1 tnozaki { 72 1.1 tnozaki struct fmemopen_cookie *p; 73 1.4 tnozaki char *s; 74 1.7 christos const char *b = buf; 75 1.1 tnozaki 76 1.1 tnozaki _DIAGASSERT(cookie != NULL); 77 1.1 tnozaki _DIAGASSERT(buf != NULL && nbytes > 0); 78 1.1 tnozaki 79 1.1 tnozaki p = (struct fmemopen_cookie *)cookie; 80 1.1 tnozaki if (p->cur >= p->tail) 81 1.1 tnozaki return 0; 82 1.1 tnozaki s = p->cur; 83 1.1 tnozaki do { 84 1.4 tnozaki if (p->cur == p->tail - 1) { 85 1.7 christos if (*b == '\0') { 86 1.4 tnozaki *p->cur++ = '\0'; 87 1.4 tnozaki goto ok; 88 1.4 tnozaki } 89 1.1 tnozaki break; 90 1.1 tnozaki } 91 1.7 christos *p->cur++ = *b++; 92 1.1 tnozaki } while (--nbytes > 0); 93 1.1 tnozaki *p->cur = '\0'; 94 1.4 tnozaki ok: 95 1.1 tnozaki if (p->cur > p->eob) 96 1.1 tnozaki p->eob = p->cur; 97 1.1 tnozaki 98 1.7 christos return (ssize_t)(p->cur - s); 99 1.7 christos } 100 1.7 christos 101 1.8 christos #ifdef notyet 102 1.7 christos static int 103 1.7 christos fmemopen_flush(void *cookie) 104 1.7 christos { 105 1.7 christos struct fmemopen_cookie *p; 106 1.7 christos 107 1.7 christos _DIAGASSERT(cookie != NULL); 108 1.7 christos 109 1.7 christos p = (struct fmemopen_cookie *)cookie; 110 1.7 christos if (p->cur >= p->tail) 111 1.7 christos return -1; 112 1.7 christos *p->cur = '\0'; 113 1.7 christos return 0; 114 1.1 tnozaki } 115 1.8 christos #endif 116 1.1 tnozaki 117 1.6 christos static off_t 118 1.6 christos fmemopen_seek(void *cookie, off_t offset, int whence) 119 1.1 tnozaki { 120 1.1 tnozaki struct fmemopen_cookie *p; 121 1.1 tnozaki 122 1.1 tnozaki _DIAGASSERT(cookie != NULL); 123 1.1 tnozaki 124 1.1 tnozaki p = (struct fmemopen_cookie *)cookie; 125 1.1 tnozaki switch (whence) { 126 1.1 tnozaki case SEEK_SET: 127 1.1 tnozaki break; 128 1.1 tnozaki case SEEK_CUR: 129 1.1 tnozaki offset += p->cur - p->head; 130 1.1 tnozaki break; 131 1.1 tnozaki case SEEK_END: 132 1.1 tnozaki offset += p->eob - p->head; 133 1.1 tnozaki break; 134 1.1 tnozaki default: 135 1.1 tnozaki errno = EINVAL; 136 1.1 tnozaki goto error; 137 1.1 tnozaki } 138 1.6 christos if (offset >= (off_t)0 && offset <= p->tail - p->head) { 139 1.3 tron p->cur = p->head + (ptrdiff_t)offset; 140 1.6 christos return (off_t)(p->cur - p->head); 141 1.1 tnozaki } 142 1.1 tnozaki error: 143 1.6 christos return (off_t)-1; 144 1.1 tnozaki } 145 1.1 tnozaki 146 1.1 tnozaki static int 147 1.1 tnozaki fmemopen_close0(void *cookie) 148 1.1 tnozaki { 149 1.1 tnozaki _DIAGASSERT(cookie != NULL); 150 1.1 tnozaki 151 1.1 tnozaki free(cookie); 152 1.1 tnozaki 153 1.1 tnozaki return 0; 154 1.1 tnozaki } 155 1.1 tnozaki 156 1.1 tnozaki static int 157 1.1 tnozaki fmemopen_close1(void *cookie) 158 1.1 tnozaki { 159 1.1 tnozaki struct fmemopen_cookie *p; 160 1.1 tnozaki 161 1.1 tnozaki _DIAGASSERT(cookie != NULL); 162 1.1 tnozaki 163 1.1 tnozaki p = (struct fmemopen_cookie *)cookie; 164 1.1 tnozaki free(p->head); 165 1.1 tnozaki free(p); 166 1.1 tnozaki 167 1.1 tnozaki return 0; 168 1.1 tnozaki } 169 1.1 tnozaki 170 1.1 tnozaki 171 1.1 tnozaki FILE * 172 1.1 tnozaki fmemopen(void * __restrict buf, size_t size, const char * __restrict mode) 173 1.1 tnozaki { 174 1.5 tnozaki int flags, oflags; 175 1.1 tnozaki FILE *fp; 176 1.1 tnozaki struct fmemopen_cookie *cookie; 177 1.1 tnozaki 178 1.5 tnozaki if (size < (size_t)1) 179 1.5 tnozaki goto invalid; 180 1.5 tnozaki 181 1.5 tnozaki flags = __sflags(mode, &oflags); 182 1.5 tnozaki if (flags == 0) 183 1.1 tnozaki return NULL; 184 1.5 tnozaki 185 1.5 tnozaki if ((oflags & O_RDWR) == 0 && buf == NULL) 186 1.5 tnozaki goto invalid; 187 1.1 tnozaki 188 1.1 tnozaki fp = __sfp(); 189 1.1 tnozaki if (fp == NULL) 190 1.1 tnozaki return NULL; 191 1.1 tnozaki fp->_file = -1; 192 1.1 tnozaki 193 1.1 tnozaki cookie = malloc(sizeof(*cookie)); 194 1.1 tnozaki if (cookie == NULL) 195 1.1 tnozaki goto release; 196 1.1 tnozaki 197 1.1 tnozaki if (buf == NULL) { 198 1.1 tnozaki cookie->head = malloc(size); 199 1.1 tnozaki if (cookie->head == NULL) { 200 1.1 tnozaki free(cookie); 201 1.1 tnozaki goto release; 202 1.1 tnozaki } 203 1.1 tnozaki *cookie->head = '\0'; 204 1.7 christos fp->_close = fmemopen_close1; 205 1.1 tnozaki } else { 206 1.1 tnozaki cookie->head = (char *)buf; 207 1.1 tnozaki if (oflags & O_TRUNC) 208 1.1 tnozaki *cookie->head = '\0'; 209 1.7 christos fp->_close = fmemopen_close0; 210 1.1 tnozaki } 211 1.1 tnozaki 212 1.1 tnozaki cookie->tail = cookie->head + size; 213 1.1 tnozaki cookie->eob = cookie->head; 214 1.1 tnozaki do { 215 1.1 tnozaki if (*cookie->eob == '\0') 216 1.1 tnozaki break; 217 1.1 tnozaki ++cookie->eob; 218 1.1 tnozaki } while (--size > 0); 219 1.1 tnozaki 220 1.1 tnozaki cookie->cur = (oflags & O_APPEND) ? cookie->eob : cookie->head; 221 1.1 tnozaki 222 1.5 tnozaki fp->_flags = flags; 223 1.7 christos fp->_write = (flags & __SRD) ? NULL : fmemopen_write; 224 1.7 christos fp->_read = (flags & __SWR) ? NULL : fmemopen_read; 225 1.7 christos fp->_seek = fmemopen_seek; 226 1.8 christos #ifdef notyet 227 1.7 christos fp->_flush = fmemopen_flush; 228 1.8 christos #endif 229 1.1 tnozaki fp->_cookie = (void *)cookie; 230 1.1 tnozaki 231 1.1 tnozaki return fp; 232 1.1 tnozaki 233 1.5 tnozaki invalid: 234 1.5 tnozaki errno = EINVAL; 235 1.5 tnozaki return NULL; 236 1.5 tnozaki 237 1.1 tnozaki release: 238 1.1 tnozaki fp->_flags = 0; 239 1.1 tnozaki return NULL; 240 1.1 tnozaki } 241