1 |
|
|
/* $OpenBSD: fmemopen.c,v 1.3 2015/08/31 02:53:57 guenther Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> |
5 |
|
|
* Copyright (c) 2009 Ted Unangst |
6 |
|
|
* |
7 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
8 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
9 |
|
|
* copyright notice and this permission notice appear in all copies. |
10 |
|
|
* |
11 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
#include <errno.h> |
21 |
|
|
#include <fcntl.h> |
22 |
|
|
#include <stdio.h> |
23 |
|
|
#include <stdlib.h> |
24 |
|
|
#include <string.h> |
25 |
|
|
#include "local.h" |
26 |
|
|
|
27 |
|
|
struct state { |
28 |
|
|
char *string; /* actual stream */ |
29 |
|
|
size_t pos; /* current position */ |
30 |
|
|
size_t size; /* allocated size */ |
31 |
|
|
size_t len; /* length of the data */ |
32 |
|
|
int update; /* open for update */ |
33 |
|
|
}; |
34 |
|
|
|
35 |
|
|
static int |
36 |
|
|
fmemopen_read(void *v, char *b, int l) |
37 |
|
|
{ |
38 |
|
|
struct state *st = v; |
39 |
|
|
int i; |
40 |
|
|
|
41 |
|
|
for (i = 0; i < l && i + st->pos < st->len; i++) |
42 |
|
|
b[i] = st->string[st->pos + i]; |
43 |
|
|
st->pos += i; |
44 |
|
|
|
45 |
|
|
return (i); |
46 |
|
|
} |
47 |
|
|
|
48 |
|
|
static int |
49 |
|
|
fmemopen_write(void *v, const char *b, int l) |
50 |
|
|
{ |
51 |
|
|
struct state *st = v; |
52 |
|
|
int i; |
53 |
|
|
|
54 |
|
|
for (i = 0; i < l && i + st->pos < st->size; i++) |
55 |
|
|
st->string[st->pos + i] = b[i]; |
56 |
|
|
st->pos += i; |
57 |
|
|
|
58 |
|
|
if (st->pos >= st->len) { |
59 |
|
|
st->len = st->pos; |
60 |
|
|
|
61 |
|
|
if (st->len < st->size) |
62 |
|
|
st->string[st->len] = '\0'; |
63 |
|
|
else if (!st->update) |
64 |
|
|
st->string[st->size - 1] = '\0'; |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
return (i); |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
static fpos_t |
71 |
|
|
fmemopen_seek(void *v, fpos_t off, int whence) |
72 |
|
|
{ |
73 |
|
|
struct state *st = v; |
74 |
|
|
ssize_t base = 0; |
75 |
|
|
|
76 |
|
|
switch (whence) { |
77 |
|
|
case SEEK_SET: |
78 |
|
|
break; |
79 |
|
|
case SEEK_CUR: |
80 |
|
|
base = st->pos; |
81 |
|
|
break; |
82 |
|
|
case SEEK_END: |
83 |
|
|
base = st->len; |
84 |
|
|
break; |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
if (off > st->size - base || off < -base) { |
88 |
|
|
errno = EOVERFLOW; |
89 |
|
|
return (-1); |
90 |
|
|
} |
91 |
|
|
|
92 |
|
|
st->pos = base + off; |
93 |
|
|
|
94 |
|
|
return (st->pos); |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
static int |
98 |
|
|
fmemopen_close(void *v) |
99 |
|
|
{ |
100 |
|
|
free(v); |
101 |
|
|
|
102 |
|
|
return (0); |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
static int |
106 |
|
|
fmemopen_close_free(void *v) |
107 |
|
|
{ |
108 |
|
|
struct state *st = v; |
109 |
|
|
|
110 |
|
|
free(st->string); |
111 |
|
|
free(st); |
112 |
|
|
|
113 |
|
|
return (0); |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
FILE * |
117 |
|
|
fmemopen(void *buf, size_t size, const char *mode) |
118 |
|
|
{ |
119 |
|
|
struct state *st; |
120 |
|
|
FILE *fp; |
121 |
|
|
int flags, oflags; |
122 |
|
|
|
123 |
|
|
if (size == 0) { |
124 |
|
|
errno = EINVAL; |
125 |
|
|
return (NULL); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
if ((flags = __sflags(mode, &oflags)) == 0) { |
129 |
|
|
errno = EINVAL; |
130 |
|
|
return (NULL); |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
if (buf == NULL && ((oflags & O_RDWR) == 0)) { |
134 |
|
|
errno = EINVAL; |
135 |
|
|
return (NULL); |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
if ((st = malloc(sizeof(*st))) == NULL) |
139 |
|
|
return (NULL); |
140 |
|
|
|
141 |
|
|
if ((fp = __sfp()) == NULL) { |
142 |
|
|
free(st); |
143 |
|
|
return (NULL); |
144 |
|
|
} |
145 |
|
|
|
146 |
|
|
st->pos = 0; |
147 |
|
|
st->len = (oflags & O_WRONLY) ? 0 : size; |
148 |
|
|
st->size = size; |
149 |
|
|
st->update = oflags & O_RDWR; |
150 |
|
|
|
151 |
|
|
if (buf == NULL) { |
152 |
|
|
if ((st->string = malloc(size)) == NULL) { |
153 |
|
|
free(st); |
154 |
|
|
fp->_flags = 0; |
155 |
|
|
return (NULL); |
156 |
|
|
} |
157 |
|
|
*st->string = '\0'; |
158 |
|
|
} else { |
159 |
|
|
st->string = (char *)buf; |
160 |
|
|
|
161 |
|
|
if (oflags & O_TRUNC) |
162 |
|
|
*st->string = '\0'; |
163 |
|
|
|
164 |
|
|
if (oflags & O_APPEND) { |
165 |
|
|
char *p; |
166 |
|
|
|
167 |
|
|
if ((p = memchr(st->string, '\0', size)) != NULL) |
168 |
|
|
st->pos = st->len = (p - st->string); |
169 |
|
|
else |
170 |
|
|
st->pos = st->len = size; |
171 |
|
|
} |
172 |
|
|
} |
173 |
|
|
|
174 |
|
|
fp->_flags = (short)flags; |
175 |
|
|
fp->_file = -1; |
176 |
|
|
fp->_cookie = (void *)st; |
177 |
|
|
fp->_read = (flags & __SWR) ? NULL : fmemopen_read; |
178 |
|
|
fp->_write = (flags & __SRD) ? NULL : fmemopen_write; |
179 |
|
|
fp->_seek = fmemopen_seek; |
180 |
|
|
fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close; |
181 |
|
|
|
182 |
|
|
return (fp); |
183 |
|
|
} |
184 |
|
|
DEF_WEAK(fmemopen); |