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.
7 Basically, the contents of a circular buffer _always_ can be
8 acted on by standard GNU C string functions and regex
11 The buffers never grow in size, and provided you use the
12 cb_append() or cb_strcat() functions, you cannot overrun them.
17 #include <sys/types.h>
24 #define CB_MAGIC 0x133419A
34 #define CB_END_MAGIC 0x8014abcc
35 #define CB_SIZE (sizeof(struct circ_buffer) + sizeof(uint32_t))
38 #define EXTRA_VALIDATE(cb, buffer) \
40 if ( *((uint32_t *)(buffer + cb->max + 1)) != CB_END_MAGIC) \
41 printf("Memory for cbuf %p corrupted\n", cb); \
46 #define CB_SIZE (sizeof(struct circ_buffer) )
47 #define EXTRA_VALIDATE(buffer, cb)
51 #define DECODE(cb, buffer, args...) \
56 cb = (struct circ_buffer *)(buffer - sizeof(struct circ_buffer)); \
57 if (cb->magic != CB_MAGIC) \
59 EXTRA_VALIDATE(cb, buffer); \
62 /* Always null-terminate */
63 #define CB_MINSIZE (CB_SIZE + 1)
65 /* ======================================================= */
67 /* Returns # of bytes appended or -1 on error */
69 cb_append(char *buffer
, const char *data
, size_t len
)
71 struct circ_buffer
*cb
;
77 DECODE(cb
, buffer
, -1);
79 /* Too long for our buffer; truncate and get out */
81 memcpy(buffer
, data
+ (len
- cb
->max
), 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
);
94 memcpy(buffer
+ cb
->len
, data
, len
);
102 _cb_delete(struct circ_buffer
*cb
,
103 char *buffer
, char *spot
, size_t len
)
113 olen
-= (spot
- buffer
);
116 memmove(spot
, spot
+len
, (olen
- len
));
125 cb_delete(char *buffer
, char *spot
, size_t len
)
127 struct circ_buffer
*cb
;
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
;
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 */
154 cb_strcat(char *buffer
, const char *data
)
156 if (cb_append(buffer
, data
, strlen(data
)) > 0)
162 /* Create a new circular buffer from user-allocated or stack
163 memory passed in at *start */
165 cb_init(void *start
, size_t len
, size_t *retlen
)
167 struct circ_buffer
*ret
;
175 if (len
< CB_MINSIZE
) {
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]);
188 *((uint32_t *)(cooked
+ ret
->max
+ 1)) = CB_END_MAGIC
;
198 /* Clear the entire buffer */
200 _reset(struct circ_buffer
*cb
)
202 memset(&cb
[1], 0, cb
->max
);
208 cb_reset(char *buffer
)
210 struct circ_buffer
*cb
;
212 DECODE(cb
, buffer
, -1);
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
) {
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
240 cb_destroy(char *buffer
)
242 struct circ_buffer
*cb
;
244 DECODE(cb
, buffer
, NULL
);
251 /* By design, users can use strlen() on the buffer. This
252 allows use of binary data if desired */
254 cb_length(char *buffer
)
256 struct circ_buffer
*cb
;
258 DECODE(cb
, buffer
, 0);
272 cb_free(char *buffer
)
274 struct circ_buffer
*cb
;