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