libdatatypes 0.3.2
Abstract datatypes for C.
Loading...
Searching...
No Matches
buffer.c
Go to the documentation of this file.
1/***************************************************************************
2 begin........: April 2015
3 copyright....: Sebastian Fedrau
4 email........: sebastian.fedrau@gmail.com
5 ***************************************************************************/
6
7/***************************************************************************
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License v3 as published by
10 the Free Software Foundation.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License v3 for more details.
16 ***************************************************************************/
22#define _GNU_SOURCE
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28#include <limits.h>
29#include <assert.h>
30
31#include "buffer.h"
32
34#define RETURN_IF_INVALID(b) if(!buffer_is_valid(b)) return
35#define RETURN_VAL_IF_INVALID(b, v) if(!buffer_is_valid(b)) return v
36#define BUFFER_LIMIT (SSIZE_MAX - 1)
37#define EXCEEDS_BUFFER_MAX_SIZE(buf, len) buf->max_size - buf->len < len
40Buffer *
41buffer_new(size_t max_size)
42{
43 assert(max_size > 0 && max_size <= BUFFER_LIMIT);
44
45 Buffer *buf = (Buffer *)malloc(sizeof(Buffer));
46
47 if(!buf)
48 {
49 perror("malloc()");
50 abort();
51 }
52
53 buffer_init(buf, max_size);
54
55 return buf;
56}
57
58void
59buffer_init(Buffer *buf, size_t max_size)
60{
61 assert(buf != NULL);
62 assert(max_size > 0 && max_size <= BUFFER_LIMIT);
63
64 memset(buf, 0, sizeof(Buffer));
65
66 buf->max_size = max_size;
67 buf->msize = 64;
68 buf->valid = true;
69 buf->data = (char *)malloc(buf->msize);
70
71 if(!buf->data)
72 {
73 perror("malloc()");
74 abort();
75 }
76}
77
78void
80{
81 assert(buf != NULL);
82
83 free(buf->data);
84}
85
86void
88{
89 assert(buf != NULL);
90
91 buffer_free(buf);
92 free(buf);
93}
94
95void
97{
98 assert(buf != NULL);
99
100 buf->len = 0;
101 buf->valid = true;
102}
103
104size_t
106{
107 assert(buf != NULL);
108
109 RETURN_VAL_IF_INVALID(buf, 0);
110
111 return buf->len;
112}
113
114bool
116{
117 assert(buf != NULL);
118
119 return buf->valid;
120}
121
122bool
124{
125 assert(buf != NULL);
126
127 RETURN_VAL_IF_INVALID(buf, false);
128
129 return buf->len == 0;
130}
131
132static size_t
133_buffer_new_realloc_size(size_t from, size_t to)
134{
135 assert(from < to);
136
137 size_t size = from;
138
139 while(size < to)
140 {
141 size *= 2;
142
143 if(size < from)
144 {
145 size = to;
146 }
147 }
148
149 return size;
150}
151
152bool
153buffer_fill(Buffer *buf, const char *data, size_t len)
154{
155 assert(buf != NULL);
156 assert(data != NULL);
157
158 RETURN_VAL_IF_INVALID(buf, false);
159
160 if(EXCEEDS_BUFFER_MAX_SIZE(buf, len))
161 {
162 fprintf(stderr, "%s(): buffer exceeds allowed maximum size.\n", __func__);
163 buf->valid = false;
164 }
165 else
166 {
167 if(len > buf->msize - buf->len)
168 {
169 size_t new_size = _buffer_new_realloc_size(buf->msize, buf->msize + len);
170
171 buf->msize = new_size;
172 buf->data = (char *)realloc(buf->data, new_size);
173
174 if(!buf->data)
175 {
176 perror("realloc()");
177 abort();
178 }
179 }
180
181 memcpy(buf->data + buf->len, data, len);
182 buf->len += len;
183 }
184
185 return buf->valid;
186}
187
188ssize_t
189buffer_fill_from_fd(Buffer *buf, int fd, size_t count)
190{
191 assert(buf != NULL);
192 assert(fd >= 0);
193 assert(count <= buf->max_size);
194
195 RETURN_VAL_IF_INVALID(buf, 0);
196
197 ssize_t bytes;
198 char data[count];
199
200 if((bytes = read(fd, data, count)) > 0)
201 {
202 if(!buffer_fill(buf, data, bytes))
203 {
204 bytes = -1;
205 }
206 }
207 else if(bytes == -1)
208 {
209 perror("read()");
210 }
211
212 return bytes;
213}
214
215static void
216_buffer_copy_to_string(const Buffer *buf, size_t count, char **dst, size_t *len)
217{
218 assert(buf != NULL);
219 assert(dst != NULL);
220 assert(len != NULL);
221 assert(count <= buf->len);
222
223 if(count + 1 > *len)
224 {
225 *len = count;
226 *dst = (char *)realloc(*dst, count + 1);
227
228 if(!*dst)
229 {
230 perror("realloc()");
231 abort();
232 }
233 }
234
235 memcpy(*dst, buf->data, count);
236 (*dst)[count] = '\0';
237}
238
239bool
240buffer_read_line(Buffer *buf, char **dst, size_t *len)
241{
242 assert(buf != NULL);
243 assert(dst != NULL);
244 assert(len != NULL);
245
246 RETURN_VAL_IF_INVALID(buf, false);
247
248 char *ptr;
249 bool found = false;
250
251 if((ptr = memchr(buf->data, '\n', buf->len)))
252 {
253 size_t slen = ptr - buf->data;
254
255 _buffer_copy_to_string(buf, slen, dst, len);
256
257 buf->len -= slen + 1;
258 memmove(buf->data, ptr + 1, buf->len);
259
260 found = true;
261 }
262
263 return found;
264}
265
266bool
267buffer_flush(const Buffer *buf, char **dst, size_t *len)
268{
269 assert(buf != NULL);
270 assert(dst != NULL);
271 assert(len != NULL);
272
273 RETURN_VAL_IF_INVALID(buf, false);
274
275 bool flushed = false;
276
277 if(buf->len)
278 {
279 _buffer_copy_to_string(buf, buf->len, dst, len);
280 flushed = true;
281 }
282
283 return flushed;
284}
285
286char *
288{
289 assert(buf != NULL);
290
291 RETURN_VAL_IF_INVALID(buf, NULL);
292
293 char *str = NULL;
294
295 if(buf->len)
296 {
297 str = (char *)malloc(buf->len + 1);
298
299 if(!str)
300 {
301 perror("malloc()");
302 abort();
303 }
304
305 memcpy(str, buf->data, buf->len);
306 str[buf->len] = '\0';
307 }
308
309 return str;
310}
311
Buffer * buffer_new(size_t max_size)
Definition buffer.c:41
ssize_t buffer_fill_from_fd(Buffer *buf, int fd, size_t count)
Definition buffer.c:189
bool buffer_flush(const Buffer *buf, char **dst, size_t *len)
Definition buffer.c:267
bool buffer_fill(Buffer *buf, const char *data, size_t len)
Definition buffer.c:153
bool buffer_is_empty(const Buffer *buf)
Definition buffer.c:123
char * buffer_to_string(const Buffer *buf)
Definition buffer.c:287
size_t buffer_len(const Buffer *buf)
Definition buffer.c:105
void buffer_destroy(Buffer *buf)
Definition buffer.c:87
bool buffer_read_line(Buffer *buf, char **dst, size_t *len)
Definition buffer.c:240
void buffer_clear(Buffer *buf)
Definition buffer.c:96
bool buffer_is_valid(const Buffer *buf)
Definition buffer.c:115
void buffer_init(Buffer *buf, size_t max_size)
Definition buffer.c:59
void buffer_free(Buffer *buf)
Definition buffer.c:79
Byte buffer.
size_t len
Definition buffer.h:43
size_t msize
Definition buffer.h:45
bool valid
Definition buffer.h:47
size_t max_size
Definition buffer.h:41
char * data
Definition buffer.h:39
A byte buffer. If the data exceeds the maximum length the buffer becomes invalid and new data is igno...
Definition buffer.h:37