buf.c (2929B)
1 #include <string.h> 2 #include <stdlib.h> 3 4 #include "buf.h" 5 6 #ifdef __cplusplus 7 extern "C" { 8 #endif // __cplusplus 9 10 #ifndef MAX 11 #define MAX(a,b) ((a)>(b)?(a):(b)) 12 #endif 13 14 #ifndef MIN 15 #define MIN(a,b) ((a)<(b)?(a):(b)) 16 #endif 17 18 #ifndef NULL 19 #define NULL ((void*)0) 20 #endif 21 22 #define ARRAY_SIZE(x) ((sizeof x) / (sizeof *x)) 23 24 const char *error_messages[] = { 25 "Unknown error", 26 "Missing subject", 27 "Missing source", 28 }; 29 30 #define BUF_ERRNO_UNKNOWN -1 31 #define BUF_ERRNO_OK 0 32 #define BUF_ERRNO_MISSING_SUBJECT 1 33 #define BUF_ERRNO_MISSING_SOURCE 2 34 35 static void *(*_realloc)(void* ptr,size_t size) = realloc; 36 static void (*_free)(void* ptr) = free; 37 38 void buf_set_allocator(void *(*realloc)(void*,size_t), void (*free)(void*)) { 39 _realloc = realloc; 40 _free = free; 41 } 42 43 const char *buf_error(int errno) { 44 45 // No error 46 if (!errno) return NULL; 47 48 // Known error 49 if ((errno > 0) && ((size_t)errno < ARRAY_SIZE(error_messages))) { 50 return error_messages[errno]; 51 } 52 53 // Unknown error 54 return error_messages[0]; 55 } 56 57 int buf_append(struct buf *subject, const char *source, const size_t length) { 58 if (!subject) return BUF_ERRNO_MISSING_SUBJECT; 59 if (!source) return BUF_ERRNO_MISSING_SOURCE; 60 61 // Initial alloc if blank buffer 62 if (!subject->alloc) { 63 size_t l = MAX(32, length); 64 subject->alloc = _realloc(NULL, l); 65 subject->dat = subject->alloc; 66 subject->cap = l; 67 subject->len = 0; 68 goto lbl_buf_append_copy; // Simply skips cap checks 69 } 70 71 // Eject consumed data if we need space 72 if ( 73 (subject->dat != subject->alloc) && 74 ((subject->len + length) > subject->cap) 75 ) { 76 size_t diff = subject->dat - subject->alloc; 77 memmove(subject->alloc, subject->dat, subject->len); 78 subject->cap += diff; 79 subject->dat = subject->alloc; 80 } 81 82 // Grow buffer if still not enough space 83 if ((subject->len + length) > subject->cap) { 84 subject->cap = MAX(32, subject->cap * 2); 85 subject->alloc = _realloc(subject->alloc, subject->cap); 86 subject->dat = subject->alloc; 87 } 88 89 // Add the data to the end 90 lbl_buf_append_copy: 91 memcpy(subject->dat + subject->len, source, length); 92 subject->len += length; 93 94 return BUF_ERRNO_OK; 95 } 96 97 int buf_append_byte(struct buf *subject, const char value) { 98 return buf_append(subject, &value, sizeof(char)); 99 } 100 101 size_t buf_consume(struct buf *subject, size_t length) { 102 if (!subject) return 0; 103 if (length <= 0) return 0; 104 105 size_t n = MIN(length, subject->len); 106 subject->dat += n; 107 subject->len -= n; 108 subject->cap -= n; 109 110 return n; 111 } 112 113 /** 114 * Clears out all data from the buffer 115 */ 116 int buf_clear(struct buf *subject) { 117 if (!subject) return BUF_ERRNO_MISSING_SUBJECT; 118 119 if (subject->alloc) { 120 _free(subject->alloc); 121 subject->alloc = NULL; 122 } 123 124 subject->dat = NULL; 125 subject->len = 0; 126 subject->cap = 0; 127 128 return BUF_ERRNO_OK; 129 } 130 131 #ifdef __cplusplus 132 } // extern "C" { 133 #endif // __cplusplus