2
* Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
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.
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.
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
20
* IOStream subtype for input and output to memory.
21
* Usable from user or kernel code (with __KERNEL__ defined).
24
#include "sys_string.h"
25
#include "mem_stream.h"
28
/** Internal state for a memory stream.
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.
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
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.
44
typedef struct MemData {
47
/** Low marker - start of readable area. */
49
/** High marker - end of readable area, start of writeable area. */
51
/** Size of the buffer. */
53
/** Maximum size the buffer can grow to. */
59
/** Get number of bytes available to read.
61
* @param data mem stream
64
static inline int mem_len(struct MemData *data){
65
return data->hi - data->lo;
68
/** Get available space left in the buffer.
70
* @param data mem stream
73
static inline int mem_room(struct MemData *data){
74
return data->buf_n - mem_len(data);
77
/** Get a pointer to the start of the data in the buffer.
79
* @param data mem stream
82
static inline char * mem_lo(struct MemData *data){
83
return data->buf + (data->lo % data->buf_n);
86
/** Get a pointer to the end of the data in the buffer.
88
* @param data mem stream
91
static inline char * mem_hi(struct MemData *data){
92
return data->buf + (data->hi % data->buf_n);
95
/** Get a pointer to the end of the buffer.
97
* @param data mem stream
100
static inline char * mem_end(struct MemData *data){
101
return data->buf + data->buf_n;
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 = {
122
/** Get the memory stream state.
124
* @param io memory stream
127
static inline MemData *get_mem_data(IOStream *io){
128
return (MemData*)io->data;
131
/** Get the number of bytes available to read.
133
* @param io memory stream
134
* @return number of bytes
136
int mem_stream_avail(IOStream *io){
137
MemData *data = get_mem_data(io);
138
return (data->err ? -data->err : mem_len(data));
141
/** Copy bytes from a memory stream into a buffer.
143
* @param data mem stream
145
* @param n number of bytes to copy
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);
154
memcpy(buf, start, k);
155
memcpy(buf + k, data->buf, n - k);
159
/** Copy bytes from a buffer into a memory stream.
161
* @param data mem stream
163
* @param n number of bytes to copy
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);
169
memcpy(start, buf, n);
172
memcpy(start, buf, k);
173
memcpy(data->buf, buf + k, n - k);
177
/** Expand the buffer used by a memory stream.
179
* @param data mem stream
180
* @param extra number of bytes to expand by
181
* @return 0 on success, negative error otherwise
183
static int mem_expand(MemData *data, size_t extra){
185
int delta = (extra < delta_min ? delta_min : extra);
188
if(data->buf_max > 0){
189
int delta_max = data->buf_max - data->buf_n;
190
if(delta > delta_max){
192
if(delta > delta_max) goto exit;
195
buf_n = data->buf_n + delta;
196
buf = allocate(buf_n);
198
mem_get(data, buf, mem_len(data));
199
data->hi = mem_len(data);
201
deallocate(data->buf);
212
/** Write bytes from a buffer into a memory stream.
213
* The internal buffer is expanded as needed to hold the data,
214
* up to the stream maximum (if specified). If the buffer cannot
215
* be expanded -ENOMEM is returned.
217
* @param io mem stream
219
* @param n number of bytes to write
220
* @return number of bytes written on success, negative error code otherwise
222
static int mem_write(IOStream *io, const void *msg, size_t n){
224
MemData *data = get_mem_data(io);
225
if(data->err) return -data->err;
226
room = mem_room(data);
228
int err = mem_expand(data, n - room);
231
mem_put(data, msg, n);
236
/** Read bytes from a memory stream into a buffer.
238
* @param io mem stream
240
* @param n maximum number of bytes to read
241
* @return number of bytes read on success, negative error code otherwise
243
static int mem_read(IOStream *io, void *buf, size_t n){
245
MemData *data = get_mem_data(io);
246
if(data->err) return -data->err;
251
mem_get(data, buf, n);
256
/** Test if a memory stream has an error.
258
* @param io mem stream
259
* @return 0 if ok, error code otherwise
261
static int mem_error(IOStream *io){
262
MemData *data = get_mem_data(io);
266
/** Close a memory stream.
268
* @param io mem stream
271
static int mem_close(IOStream *io){
272
MemData *data = get_mem_data(io);
274
data->err = ENOTCONN;
279
/** Free a memory stream.
281
* @param io mem stream
283
static void mem_free(IOStream *io){
284
MemData *data = get_mem_data(io);
285
deallocate(data->buf);
286
memzero(data, sizeof(*data));
290
/** Allocate and initialise a memory stream.
292
* @param buf_n initial buffer size (0 means default)
293
* @param buf_max maximum buffer size (0 means no max)
294
* @return new stream (free using IOStream_close)
296
IOStream *mem_stream_new_size(size_t buf_n, size_t buf_max){
298
MemData *data = ALLOCATE(MemData);
301
io = ALLOCATE(IOStream);
303
if(buf_n <= delta_min){
306
if(buf_max > 0 && buf_max < buf_n){
309
data->buf = allocate(buf_n);
310
if(!data->buf) goto exit;
312
data->buf_max = buf_max;
313
io->methods = &mem_methods;