ia64/xen-unstable

view tools/vnet/libxutil/mem_stream.c @ 6766:219d96d545fc

merge?
author cl349@firebug.cl.cam.ac.uk
date Mon Sep 12 20:00:41 2005 +0000 (2005-09-12)
parents 7ae8090e5f67
children b35215021b32 9af349b055e5 3233e7ecfa9f
line source
1 /*
2 * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
3 *
4 * This library is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
19 /** @file
20 * IOStream subtype for input and output to memory.
21 * Usable from user or kernel code (with __KERNEL__ defined).
22 */
24 #include "sys_string.h"
25 #include "mem_stream.h"
26 #include "allocate.h"
28 /** Internal state for a memory stream.
29 *
30 * The memory stream buffer is treated as a circular buffer.
31 * The lo and hi markers indicate positions in the buffer, but
32 * are not reduced modulo the buffer size. This avoids the ambiguity
33 * between a full and empty buffer when using reduced values.
34 *
35 * If x is a marker, then buf + (x % buf_n) is the corresponding
36 * pointer into the buffer. When the buffer is empty, lo == hi,
37 * and the corresponding pointers are equal. When the buffer is
38 * full, hi == lo + buf_n, and the corresponding pointers
39 * are also equal.
40 *
41 * Data is written after the high pointer and read from the lo pointer.
42 * The value hi - lo is the number of bytes in the buffer.
43 */
44 typedef struct MemData {
45 /** Data buffer. */
46 char *buf;
47 /** Low marker - start of readable area. */
48 unsigned long lo;
49 /** High marker - end of readable area, start of writeable area. */
50 unsigned long hi;
51 /** Size of the buffer. */
52 unsigned int buf_n;
53 /** Maximum size the buffer can grow to. */
54 unsigned int buf_max;
55 /** Error code. */
56 int err;
57 } MemData;
59 /** Get number of bytes available to read.
60 *
61 * @param data mem stream
62 * @return bytes
63 */
64 static inline int mem_len(struct MemData *data){
65 return data->hi - data->lo;
66 }
68 /** Get available space left in the buffer.
69 *
70 * @param data mem stream
71 * @return bytes
72 */
73 static inline int mem_room(struct MemData *data){
74 return data->buf_n - mem_len(data);
75 }
77 /** Get a pointer to the start of the data in the buffer.
78 *
79 * @param data mem stream
80 * @return lo pointer
81 */
82 static inline char * mem_lo(struct MemData *data){
83 return data->buf + (data->lo % data->buf_n);
84 }
86 /** Get a pointer to the end of the data in the buffer.
87 *
88 * @param data mem stream
89 * @return hi pointer
90 */
91 static inline char * mem_hi(struct MemData *data){
92 return data->buf + (data->hi % data->buf_n);
93 }
95 /** Get a pointer to the end of the buffer.
96 *
97 * @param data mem stream
98 * @return end pointer
99 */
100 static inline char * mem_end(struct MemData *data){
101 return data->buf + data->buf_n;
102 }
104 static int mem_error(IOStream *io);
105 static int mem_close(IOStream *io);
106 static void mem_free(IOStream *io);
107 static int mem_write(IOStream *io, const void *msg, size_t n);
108 static int mem_read(IOStream *io, void *buf, size_t n);
110 /** Minimum delta used to increment the buffer. */
111 static int delta_min = 256;
113 /** Methods for a memory stream. */
114 static IOMethods mem_methods = {
115 read: mem_read,
116 write: mem_write,
117 error: mem_error,
118 close: mem_close,
119 free: mem_free,
120 };
122 /** Get the memory stream state.
123 *
124 * @param io memory stream
125 * @return state
126 */
127 static inline MemData *get_mem_data(IOStream *io){
128 return (MemData*)io->data;
129 }
131 /** Get the number of bytes available to read.
132 *
133 * @param io memory stream
134 * @return number of bytes
135 */
136 int mem_stream_avail(IOStream *io){
137 MemData *data = get_mem_data(io);
138 return (data->err ? -data->err : mem_len(data));
139 }
141 /** Copy bytes from a memory stream into a buffer.
142 *
143 * @param data mem stream
144 * @param buf buffer
145 * @param n number of bytes to copy
146 */
147 static void mem_get(MemData *data, char *buf, size_t n){
148 char *start = mem_lo(data);
149 char *end = mem_end(data);
150 if (start + n < end) {
151 memcpy(buf, start, n);
152 } else {
153 int k = end - start;
154 memcpy(buf, start, k);
155 memcpy(buf + k, data->buf, n - k);
156 }
157 }
159 /** Copy bytes from a buffer into a memory stream.
160 *
161 * @param data mem stream
162 * @param buf buffer
163 * @param n number of bytes to copy
164 */
165 static void mem_put(MemData *data, const char *buf, size_t n){
166 char *start = mem_hi(data);
167 char *end = mem_end(data);
168 if(start + n < end){
169 memcpy(start, buf, n);
170 } else {
171 int k = end - start;
172 memcpy(start, buf, k);
173 memcpy(data->buf, buf + k, n - k);
174 }
175 }
177 /** Expand the buffer used by a memory stream.
178 *
179 * @param data mem stream
180 * @param extra number of bytes to expand by
181 * @return 0 on success, negative error otherwise
182 */
183 static int mem_expand(MemData *data, size_t extra){
184 int err = -ENOMEM;
185 int delta = (extra < delta_min ? delta_min : extra);
186 if(data->buf_max > 0){
187 int delta_max = data->buf_max - data->buf_n;
188 if(delta > delta_max){
189 delta = extra;
190 if(delta > delta_max) goto exit;
191 }
192 }
193 int buf_n = data->buf_n + delta;
194 char *buf = allocate(buf_n);
195 if(!buf) goto exit;
196 mem_get(data, buf, mem_len(data));
197 data->hi = mem_len(data);
198 data->lo = 0;
199 deallocate(data->buf);
200 data->buf = buf;
201 data->buf_n = buf_n;
202 err = 0;
203 exit:
204 if(err){
205 data->err = -err;
206 }
207 return err;
208 }
210 /** Write bytes from a buffer into a memory stream.
211 * The internal buffer is expanded as needed to hold the data,
212 * up to the stream maximum (if specified). If the buffer cannot
213 * be expanded -ENOMEM is returned.
214 *
215 * @param io mem stream
216 * @param buf buffer
217 * @param n number of bytes to write
218 * @return number of bytes written on success, negative error code otherwise
219 */
220 static int mem_write(IOStream *io, const void *msg, size_t n){
221 MemData *data = get_mem_data(io);
222 if(data->err) return -data->err;
223 int room = mem_room(data);
224 if(n > room){
225 int err = mem_expand(data, n - room);
226 if(err) return err;
227 }
228 mem_put(data, msg, n);
229 data->hi += n;
230 return n;
231 }
233 /** Read bytes from a memory stream into a buffer.
234 *
235 * @param io mem stream
236 * @param buf buffer
237 * @param n maximum number of bytes to read
238 * @return number of bytes read on success, negative error code otherwise
239 */
240 static int mem_read(IOStream *io, void *buf, size_t n){
241 MemData *data = get_mem_data(io);
242 if(data->err) return -data->err;
243 int k = mem_len(data);
244 if(n > k){
245 n = k;
246 }
247 mem_get(data, buf, n);
248 data->lo += n;
249 return n;
250 }
252 /** Test if a memory stream has an error.
253 *
254 * @param io mem stream
255 * @return 0 if ok, error code otherwise
256 */
257 static int mem_error(IOStream *io){
258 MemData *data = get_mem_data(io);
259 return data->err;
260 }
262 /** Close a memory stream.
263 *
264 * @param io mem stream
265 * @return 0
266 */
267 static int mem_close(IOStream *io){
268 MemData *data = get_mem_data(io);
269 if(!data->err){
270 data->err = ENOTCONN;
271 }
272 return 0;
273 }
275 /** Free a memory stream.
276 *
277 * @param io mem stream
278 */
279 static void mem_free(IOStream *io){
280 MemData *data = get_mem_data(io);
281 deallocate(data->buf);
282 memzero(data, sizeof(*data));
283 deallocate(data);
284 }
286 /** Allocate and initialise a memory stream.
287 *
288 * @param buf_n initial buffer size (0 means default)
289 * @param buf_max maximum buffer size (0 means no max)
290 * @return new stream (free using IOStream_close)
291 */
292 IOStream *mem_stream_new_size(size_t buf_n, size_t buf_max){
293 int err = -ENOMEM;
294 MemData *data = ALLOCATE(MemData);
295 if(!data) goto exit;
296 IOStream *io = ALLOCATE(IOStream);
297 if(!io) goto exit;
298 if(buf_n <= delta_min){
299 buf_n = delta_min;
300 }
301 if(buf_max > 0 && buf_max < buf_n){
302 buf_max = buf_n;
303 }
304 data->buf = allocate(buf_n);
305 if(!data->buf) goto exit;
306 data->buf_n = buf_n;
307 data->buf_max = buf_max;
308 io->methods = &mem_methods;
309 io->data = data;
310 io->nofree = 0;
311 err = 0;
312 exit:
313 if(err){
314 deallocate(data);
315 deallocate(io);
316 io = NULL;
317 }
318 return io;
319 }