Drop -Werror
[pmc.git] / cbuf.c
blob4dc4bb2e5381084c52f6776f3845a12a779ff2ac
1 /*
2 Simple circular C-string buffer
3 TODO: use page size memcopy for performance; shift by whole page
4 sizes at a time instead of a couple of bytes.
5 TODO: cb_printf()
7 Basically, the contents of a circular buffer _always_ can be
8 acted on by standard GNU C string functions and regex
9 functions.
11 The buffers never grow in size, and provided you use the
12 cb_append() or cb_strcat() functions, you cannot overrun them.
14 -- Lon
16 #include <string.h>
17 #include <sys/types.h>
18 #include <errno.h>
19 #include <stdint.h>
20 #include <cbuf.h>
21 #include <malloc.h>
22 #include <unistd.h>
24 #define CB_MAGIC 0x133419A
26 struct circ_buffer {
27 uint32_t magic;
28 uint32_t pad;
29 size_t max;
30 size_t len;
33 #ifdef DEBUG
34 #define CB_END_MAGIC 0x8014abcc
35 #define CB_SIZE (sizeof(struct circ_buffer) + sizeof(uint32_t))
36 #include <stdio.h>
37 #include <fcntl.h>
38 #define EXTRA_VALIDATE(cb, buffer) \
39 do { \
40 if ( *((uint32_t *)(buffer + cb->max + 1)) != CB_END_MAGIC) \
41 printf("Memory for cbuf %p corrupted\n", cb); \
42 } while(0)
44 #else
46 #define CB_SIZE (sizeof(struct circ_buffer) )
47 #define EXTRA_VALIDATE(buffer, cb)
49 #endif
51 #define DECODE(cb, buffer, args...) \
52 do { \
53 errno = EINVAL; \
54 if (!buffer) \
55 return args; \
56 cb = (struct circ_buffer *)(buffer - sizeof(struct circ_buffer)); \
57 if (cb->magic != CB_MAGIC) \
58 return args; \
59 EXTRA_VALIDATE(cb, buffer); \
60 } while(0)
62 /* Always null-terminate */
63 #define CB_MINSIZE (CB_SIZE + 1)
65 /* ======================================================= */
67 /* Returns # of bytes appended or -1 on error */
68 int
69 cb_append(char *buffer, const char *data, size_t len)
71 struct circ_buffer *cb;
72 size_t olen;
74 if (!data || !len)
75 return 0;
77 DECODE(cb, buffer, -1);
79 /* Too long for our buffer; truncate and get out */
80 if (len > cb->max) {
81 memcpy(buffer, data + (len - cb->max), cb->max);
82 cb->len = cb->max;
83 return cb->max;
86 /* Not enough space - memmove to make space
87 and copy in last bits */
88 if ((cb->len + len) > cb->max) {
89 olen = cb->len + len - cb->max;
90 memmove(buffer, buffer + olen, cb->max - olen);
91 cb->len -= olen;
94 memcpy(buffer + cb->len, data, len);
95 cb->len += len;
96 buffer[cb->len] = 0;
97 return len;
101 static int
102 _cb_delete(struct circ_buffer *cb,
103 char *buffer, char *spot, size_t len)
105 size_t olen;
107 if (!len)
108 return 0;
109 if (len > cb->len)
110 return 0;
112 olen = cb->len;
113 olen -= (spot - buffer);
114 if (len > olen)
115 len = olen;
116 memmove(spot, spot+len, (olen - len));
117 cb->len -= len;
118 buffer[cb->len] = 0;
120 return (int)len;
125 cb_delete(char *buffer, char *spot, size_t len)
127 struct circ_buffer *cb;
129 if (!spot || !len)
130 return 0;
132 DECODE(cb, buffer, -1);
134 return _cb_delete(cb, buffer, spot, len);
139 cb_backspace(char *buffer, size_t len)
141 struct circ_buffer *cb;
143 if (!len)
144 return 0;
146 DECODE(cb, buffer, -1);
148 return _cb_delete(cb, buffer, &buffer[cb->len-len], len);
152 /* convenience function; operates like strcat, incl. return value */
153 char *
154 cb_strcat(char *buffer, const char *data)
156 if (cb_append(buffer, data, strlen(data)) > 0)
157 return buffer;
158 return NULL;
162 /* Create a new circular buffer from user-allocated or stack
163 memory passed in at *start */
164 char *
165 cb_init(void *start, size_t len, size_t *retlen)
167 struct circ_buffer *ret;
168 char *cooked;
170 if (!start) {
171 errno = EINVAL;
172 return NULL;
175 if (len < CB_MINSIZE) {
176 errno = ENOMEM;
177 return NULL;
180 memset(start, 0, len);
182 ret = (struct circ_buffer *)start;
183 ret->max = len - (CB_MINSIZE); /* header and trailer, if DEBUG */
184 ret->magic = CB_MAGIC;
186 cooked = (char *)(&ret[1]);
187 #ifdef DEBUG
188 *((uint32_t *)(cooked + ret->max + 1)) = CB_END_MAGIC;
189 #endif
191 if (retlen)
192 *retlen = ret->max;
194 return cooked;
198 /* Clear the entire buffer */
199 static inline void
200 _reset(struct circ_buffer *cb)
202 memset(&cb[1], 0, cb->max);
203 cb->len = 0;
208 cb_reset(char *buffer)
210 struct circ_buffer *cb;
212 DECODE(cb, buffer, -1);
214 _reset(cb);
215 return 0;
219 /* Take the first count bytes off the front of the buffer */
221 cb_discard(char *buffer, size_t count)
223 struct circ_buffer *cb;
225 DECODE(cb, buffer, -1);
227 if (count >= cb->max) {
228 _reset(cb);
229 return cb->max;
232 return _cb_delete(cb, buffer, buffer, count);
236 /* Invalidate a circular buffer and return the pointer the
237 user fed to us when he/she called cb_init() so they may
238 free it */
239 void *
240 cb_destroy(char *buffer)
242 struct circ_buffer *cb;
244 DECODE(cb, buffer, NULL);
246 cb->magic = 0;
247 return (void *)cb;
251 /* By design, users can use strlen() on the buffer. This
252 allows use of binary data if desired */
253 size_t
254 cb_length(char *buffer)
256 struct circ_buffer *cb;
258 DECODE(cb, buffer, 0);
260 return cb->len;
264 size_t
265 cb_minsize(void)
267 return CB_MINSIZE;
271 void
272 cb_free(char *buffer)
274 struct circ_buffer *cb;
276 DECODE(cb, buffer);
278 free(cb);