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