├── .gitignore ├── Makefile ├── package.json ├── .github └── workflows │ └── tests.yml ├── History.md ├── Readme.md ├── buffer.h ├── test.c └── buffer.c /.gitignore: -------------------------------------------------------------------------------- 1 | test 2 | *.o 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: buffer.c test.c 3 | @$(CC) $^ -std=c99 -o $@ 4 | @./test 5 | 6 | .PHONY: test 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "buffer", 3 | "version": "0.4.0", 4 | "repo": "clibs/buffer", 5 | "description": "Higher level C-string utilities", 6 | "keywords": ["buf", "buffer", "string", "str", "util", "utils"], 7 | "license": "MIT", 8 | "src": ["buffer.c", "buffer.h"] 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | - run: sudo apt install -y valgrind 11 | - run: make test 12 | - run: valgrind --leak-check=full --error-exitcode=5 ./test 13 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.4.0 / 2015-01-05 3 | ================== 4 | 5 | * refactor 6 | * buffer: Remove printf() statement 7 | * Add `buffer_appendf()` (#10, marcomorain) 8 | 9 | 0.3.0 / 2014-12-24 10 | ================== 11 | 12 | * travis: Fail the build if any memory is leaked 13 | * test: Fix memory leaks 14 | * travis: setup 15 | * Add `buffer_append_n(buffer_t *, const char *, size_t)` 16 | 17 | 0.2.1 / 2014-12-23 18 | ================== 19 | 20 | * fix header guard 21 | * fix compilation on linux 22 | * Add missing null terminator after realloc (buffer resize) 23 | * Make it safe to always use `data` as a character string 24 | 25 | 0.2.0 / 2013-01-05 26 | ================== 27 | 28 | * add print_buffer() 29 | * add buffer_compact() 30 | 31 | 0.1.0 / 2012-12-26 32 | ================== 33 | 34 | * add trim functions 35 | * add buffer_clear(buffer_t *self) 36 | * add buffer_fill(buffer_t *self, int c) 37 | * add buffer_new_with_string_length(char *str, size_t len) 38 | * add buffer_new_with_copy(char *str) 39 | * add buffer_indexof() 40 | 41 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # buffer 3 | 4 | Tiny C string manipulation library. 5 | 6 | ## Installation 7 | 8 | Install with [clib](https://github.com/clibs/clib): 9 | 10 | ``` 11 | $ clib install clibs/buffer 12 | ``` 13 | 14 | ## API 15 | 16 | ```c 17 | buffer_t * 18 | buffer_new(); 19 | 20 | buffer_t * 21 | buffer_new_with_size(size_t n); 22 | 23 | buffer_t * 24 | buffer_new_with_string(char *str); 25 | 26 | buffer_t * 27 | buffer_new_with_string_length(char *str, size_t len); 28 | 29 | buffer_t * 30 | buffer_new_with_copy(char *str); 31 | 32 | size_t 33 | buffer_size(buffer_t *self); 34 | 35 | size_t 36 | buffer_length(buffer_t *self); 37 | 38 | void 39 | buffer_free(buffer_t *self); 40 | 41 | int 42 | buffer_prepend(buffer_t *self, char *str); 43 | 44 | int 45 | buffer_append(buffer_t *self, char *str); 46 | 47 | int 48 | buffer_equals(buffer_t *self, buffer_t *other); 49 | 50 | ssize_t 51 | buffer_indexof(buffer_t *self, char *str); 52 | 53 | buffer_t * 54 | buffer_slice(buffer_t *self, size_t from, ssize_t to); 55 | 56 | ssize_t 57 | buffer_compact(buffer_t *self); 58 | 59 | void 60 | buffer_fill(buffer_t *self, int c); 61 | 62 | void 63 | buffer_clear(buffer_t *self); 64 | 65 | void 66 | buffer_trim_left(buffer_t *self); 67 | 68 | void 69 | buffer_trim_right(buffer_t *self); 70 | 71 | void 72 | buffer_trim(buffer_t *self); 73 | 74 | void 75 | buffer_print(buffer_t *self); 76 | 77 | #define buffer_string(self) (self->data) 78 | ``` 79 | 80 | ## License 81 | 82 | MIT 83 | -------------------------------------------------------------------------------- /buffer.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // buffer.h 4 | // 5 | // Copyright (c) 2012 TJ Holowaychuk 6 | // 7 | 8 | #ifndef BUFFER_H 9 | #define BUFFER_H 1 10 | 11 | #include 12 | 13 | /* 14 | * Default buffer size. 15 | */ 16 | 17 | #ifndef BUFFER_DEFAULT_SIZE 18 | #define BUFFER_DEFAULT_SIZE 64 19 | #endif 20 | 21 | /* 22 | * Buffer struct. 23 | */ 24 | 25 | typedef struct { 26 | size_t len; 27 | char *alloc; 28 | char *data; 29 | } buffer_t; 30 | 31 | // prototypes 32 | 33 | buffer_t * 34 | buffer_new(); 35 | 36 | buffer_t * 37 | buffer_new_with_size(size_t n); 38 | 39 | buffer_t * 40 | buffer_new_with_string(char *str); 41 | 42 | buffer_t * 43 | buffer_new_with_string_length(char *str, size_t len); 44 | 45 | buffer_t * 46 | buffer_new_with_copy(char *str); 47 | 48 | size_t 49 | buffer_size(buffer_t *self); 50 | 51 | size_t 52 | buffer_length(buffer_t *self); 53 | 54 | void 55 | buffer_free(buffer_t *self); 56 | 57 | int 58 | buffer_prepend(buffer_t *self, char *str); 59 | 60 | int 61 | buffer_append(buffer_t *self, const char *str); 62 | 63 | int 64 | buffer_appendf(buffer_t *self, const char *format, ...); 65 | 66 | int 67 | buffer_append_n(buffer_t *self, const char *str, size_t len); 68 | 69 | int 70 | buffer_equals(buffer_t *self, buffer_t *other); 71 | 72 | ssize_t 73 | buffer_indexof(buffer_t *self, char *str); 74 | 75 | buffer_t * 76 | buffer_slice(buffer_t *self, size_t from, ssize_t to); 77 | 78 | ssize_t 79 | buffer_compact(buffer_t *self); 80 | 81 | void 82 | buffer_fill(buffer_t *self, int c); 83 | 84 | void 85 | buffer_clear(buffer_t *self); 86 | 87 | void 88 | buffer_trim_left(buffer_t *self); 89 | 90 | void 91 | buffer_trim_right(buffer_t *self); 92 | 93 | void 94 | buffer_trim(buffer_t *self); 95 | 96 | void 97 | buffer_print(buffer_t *self); 98 | 99 | #define buffer_string(self) (self->data) 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // test.c 4 | // 5 | // Copyright (c) 2012 TJ Holowaychuk 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "buffer.h" 13 | 14 | void 15 | equal(char *a, char *b) { 16 | if (strcmp(a, b)) { 17 | printf("\n"); 18 | printf(" expected: '%s'\n", a); 19 | printf(" actual: '%s'\n", b); 20 | printf("\n"); 21 | exit(1); 22 | } 23 | } 24 | 25 | void 26 | test_buffer_new() { 27 | buffer_t *buf = buffer_new(); 28 | assert(BUFFER_DEFAULT_SIZE == buffer_size(buf)); 29 | assert(0 == buffer_length(buf)); 30 | buffer_free(buf); 31 | } 32 | 33 | void 34 | test_buffer_new_with_size() { 35 | buffer_t *buf = buffer_new_with_size(1024); 36 | assert(1024 == buffer_size(buf)); 37 | assert(0 == buffer_length(buf)); 38 | buffer_free(buf); 39 | } 40 | 41 | void 42 | test_buffer_append() { 43 | buffer_t *buf = buffer_new(); 44 | assert(0 == buffer_append(buf, "Hello")); 45 | assert(0 == buffer_append(buf, " World")); 46 | assert(strlen("Hello World") == buffer_length(buf)); 47 | equal("Hello World", buffer_string(buf)); 48 | buffer_free(buf); 49 | } 50 | 51 | void 52 | test_buffer_append_n() { 53 | buffer_t *buf = buffer_new(); 54 | assert(0 == buffer_append_n(buf, "subway", 3)); 55 | assert(0 == buffer_append_n(buf, "marines", 6)); 56 | assert(strlen("submarine") == buffer_length(buf)); 57 | equal("submarine", buffer_string(buf)); 58 | buffer_free(buf); 59 | } 60 | 61 | void 62 | test_buffer_append__grow() { 63 | buffer_t *buf = buffer_new_with_size(10); 64 | assert(0 == buffer_append(buf, "Hello")); 65 | assert(0 == buffer_append(buf, " tobi")); 66 | assert(0 == buffer_append(buf, " was")); 67 | assert(0 == buffer_append(buf, " here")); 68 | 69 | char *str = "Hello tobi was here"; 70 | equal(str, buffer_string(buf)); 71 | assert(1024 == buffer_size(buf)); 72 | assert(strlen(str) == buffer_length(buf)); 73 | buffer_free(buf); 74 | } 75 | 76 | void 77 | test_buffer_prepend() { 78 | buffer_t *buf = buffer_new(); 79 | assert(0 == buffer_append(buf, " World")); 80 | assert(0 == buffer_prepend(buf, "Hello")); 81 | assert(strlen("Hello World") == buffer_length(buf)); 82 | equal("Hello World", buffer_string(buf)); 83 | buffer_free(buf); 84 | } 85 | 86 | void 87 | test_buffer_slice() { 88 | buffer_t *buf = buffer_new(); 89 | buffer_append(buf, "Tobi Ferret"); 90 | 91 | buffer_t *a = buffer_slice(buf, 2, 8); 92 | equal("Tobi Ferret", buffer_string(buf)); 93 | equal("bi Fer", buffer_string(a)); 94 | 95 | buffer_free(buf); 96 | buffer_free(a); 97 | } 98 | 99 | void 100 | test_buffer_slice__range_error() { 101 | buffer_t *buf = buffer_new_with_copy("Tobi Ferret"); 102 | buffer_t *a = buffer_slice(buf, 10, 2); 103 | assert(NULL == a); 104 | buffer_free(buf); 105 | } 106 | 107 | void 108 | test_buffer_slice__end() { 109 | buffer_t *buf = buffer_new_with_copy("Tobi Ferret"); 110 | 111 | buffer_t *a = buffer_slice(buf, 5, -1); 112 | equal("Tobi Ferret", buffer_string(buf)); 113 | equal("Ferret", buffer_string(a)); 114 | 115 | buffer_t *b = buffer_slice(buf, 5, -3); 116 | equal("Ferr", buffer_string(b)); 117 | 118 | buffer_t *c = buffer_slice(buf, 8, -1); 119 | equal("ret", buffer_string(c)); 120 | 121 | buffer_free(buf); 122 | buffer_free(a); 123 | buffer_free(b); 124 | buffer_free(c); 125 | } 126 | 127 | void 128 | test_buffer_slice__end_overflow() { 129 | buffer_t *buf = buffer_new_with_copy("Tobi Ferret"); 130 | buffer_t *a = buffer_slice(buf, 5, 1000); 131 | equal("Tobi Ferret", buffer_string(buf)); 132 | equal("Ferret", buffer_string(a)); 133 | buffer_free(a); 134 | buffer_free(buf); 135 | } 136 | 137 | void 138 | test_buffer_equals() { 139 | buffer_t *a = buffer_new_with_copy("Hello"); 140 | buffer_t *b = buffer_new_with_copy("Hello"); 141 | 142 | assert(1 == buffer_equals(a, b)); 143 | 144 | buffer_append(b, " World"); 145 | assert(0 == buffer_equals(a, b)); 146 | 147 | buffer_free(a); 148 | buffer_free(b); 149 | } 150 | 151 | void test_buffer_formatting() { 152 | buffer_t *buf = buffer_new(); 153 | int result = buffer_appendf(buf, "%d %s", 3, "cow"); 154 | assert(0 == result); 155 | equal("3 cow", buffer_string(buf)); 156 | result = buffer_appendf(buf, " - 0x%08X", 0xdeadbeef); 157 | assert(0 == result); 158 | equal("3 cow - 0xDEADBEEF", buffer_string(buf)); 159 | buffer_free(buf); 160 | } 161 | 162 | void 163 | test_buffer_indexof() { 164 | buffer_t *buf = buffer_new_with_copy("Tobi is a ferret"); 165 | 166 | ssize_t i = buffer_indexof(buf, "is"); 167 | assert(5 == i); 168 | 169 | i = buffer_indexof(buf, "a"); 170 | assert(8 == i); 171 | 172 | i = buffer_indexof(buf, "something"); 173 | assert(-1 == i); 174 | 175 | buffer_free(buf); 176 | } 177 | 178 | void 179 | test_buffer_fill() { 180 | buffer_t *buf = buffer_new_with_copy("Hello"); 181 | assert(5 == buffer_length(buf)); 182 | 183 | buffer_fill(buf, 0); 184 | assert(0 == buffer_length(buf)); 185 | buffer_free(buf); 186 | } 187 | 188 | void 189 | test_buffer_clear() { 190 | buffer_t *buf = buffer_new_with_copy("Hello"); 191 | assert(5 == buffer_length(buf)); 192 | 193 | buffer_clear(buf); 194 | assert(0 == buffer_length(buf)); 195 | buffer_free(buf); 196 | } 197 | 198 | void 199 | test_buffer_trim() { 200 | buffer_t *buf = buffer_new_with_copy(" Hello\n\n "); 201 | buffer_trim(buf); 202 | equal("Hello", buffer_string(buf)); 203 | buffer_free(buf); 204 | 205 | buf = buffer_new_with_copy(" Hello\n\n "); 206 | buffer_trim_left(buf); 207 | equal("Hello\n\n ", buffer_string(buf)); 208 | buffer_free(buf); 209 | 210 | buf = buffer_new_with_copy(" Hello\n\n "); 211 | buffer_trim_right(buf); 212 | equal(" Hello", buffer_string(buf)); 213 | buffer_free(buf); 214 | } 215 | 216 | void 217 | test_buffer_compact() { 218 | buffer_t *buf = buffer_new_with_copy(" Hello\n\n "); 219 | buffer_trim(buf); 220 | assert(5 == buffer_length(buf)); 221 | assert(10 == buffer_size(buf)); 222 | 223 | ssize_t removed = buffer_compact(buf); 224 | assert(5 == removed); 225 | assert(5 == buffer_length(buf)); 226 | assert(5 == buffer_size(buf)); 227 | equal("Hello", buffer_string(buf)); 228 | 229 | buffer_free(buf); 230 | } 231 | 232 | void 233 | test_buffer_prepend_issue_15() { 234 | buffer_t *file = buffer_new(); 235 | assert(0 == buffer_append(file, "layout.bk.html")); 236 | assert(0 == buffer_prepend(file, "./example/")); 237 | assert(strlen("./example/layout.bk.html") == buffer_length(file)); 238 | equal("./example/layout.bk.html", buffer_string(file)); 239 | buffer_free(file); 240 | } 241 | 242 | int 243 | main(){ 244 | test_buffer_new(); 245 | test_buffer_new_with_size(); 246 | test_buffer_append(); 247 | test_buffer_append__grow(); 248 | test_buffer_append_n(); 249 | test_buffer_prepend(); 250 | test_buffer_slice(); 251 | test_buffer_slice__range_error(); 252 | test_buffer_slice__end(); 253 | test_buffer_slice__end_overflow(); 254 | test_buffer_equals(); 255 | test_buffer_formatting(); 256 | test_buffer_indexof(); 257 | test_buffer_fill(); 258 | test_buffer_clear(); 259 | test_buffer_trim(); 260 | test_buffer_compact(); 261 | test_buffer_prepend_issue_15(); 262 | printf("\n \e[32m\u2713 \e[90mok\e[0m\n\n"); 263 | return 0; 264 | } 265 | -------------------------------------------------------------------------------- /buffer.c: -------------------------------------------------------------------------------- 1 | // 2 | // buffer.c 3 | // 4 | // Copyright (c) 2012 TJ Holowaychuk 5 | // 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "buffer.h" 14 | 15 | // TODO: shared with reference counting 16 | // TODO: linked list for append/prepend etc 17 | 18 | /* 19 | * Compute the nearest multiple of `a` from `b`. 20 | */ 21 | 22 | #define nearest_multiple_of(a, b) \ 23 | (((b) + ((a) - 1)) & ~((a) - 1)) 24 | 25 | /* 26 | * Allocate a new buffer with BUFFER_DEFAULT_SIZE. 27 | */ 28 | 29 | buffer_t * 30 | buffer_new() { 31 | return buffer_new_with_size(BUFFER_DEFAULT_SIZE); 32 | } 33 | 34 | /* 35 | * Allocate a new buffer with `n` bytes. 36 | */ 37 | 38 | buffer_t * 39 | buffer_new_with_size(size_t n) { 40 | buffer_t *self = malloc(sizeof(buffer_t)); 41 | if (!self) return NULL; 42 | self->len = n; 43 | self->data = self->alloc = calloc(n + 1, 1); 44 | return self; 45 | } 46 | 47 | /* 48 | * Allocate a new buffer with `str`. 49 | */ 50 | 51 | buffer_t * 52 | buffer_new_with_string(char *str) { 53 | return buffer_new_with_string_length(str, strlen(str)); 54 | } 55 | 56 | /* 57 | * Allocate a new buffer with `str` and `len`. 58 | */ 59 | 60 | buffer_t * 61 | buffer_new_with_string_length(char *str, size_t len) { 62 | buffer_t *self = malloc(sizeof(buffer_t)); 63 | if (!self) return NULL; 64 | self->len = len; 65 | self->data = self->alloc = str; 66 | return self; 67 | } 68 | 69 | /* 70 | * Allocate a new buffer with a copy of `str`. 71 | */ 72 | 73 | buffer_t * 74 | buffer_new_with_copy(char *str) { 75 | size_t len = strlen(str); 76 | buffer_t *self = buffer_new_with_size(len); 77 | if (!self) return NULL; 78 | memcpy(self->alloc, str, len); 79 | self->data = self->alloc; 80 | return self; 81 | } 82 | 83 | /* 84 | * Deallocate excess memory, the number 85 | * of bytes removed or -1. 86 | */ 87 | 88 | ssize_t 89 | buffer_compact(buffer_t *self) { 90 | size_t len = buffer_length(self); 91 | size_t rem = self->len - len; 92 | char *buf = calloc(len + 1, 1); 93 | if (!buf) return -1; 94 | memcpy(buf, self->data, len); 95 | free(self->alloc); 96 | self->len = len; 97 | self->data = self->alloc = buf; 98 | return rem; 99 | } 100 | 101 | /* 102 | * Free the buffer. 103 | */ 104 | 105 | void 106 | buffer_free(buffer_t *self) { 107 | free(self->alloc); 108 | free(self); 109 | } 110 | 111 | /* 112 | * Return buffer size. 113 | */ 114 | 115 | size_t 116 | buffer_size(buffer_t *self) { 117 | return self->len; 118 | } 119 | 120 | /* 121 | * Return string length. 122 | */ 123 | 124 | size_t 125 | buffer_length(buffer_t *self) { 126 | return strlen(self->data); 127 | } 128 | 129 | /* 130 | * Resize to hold `n` bytes. 131 | */ 132 | 133 | int 134 | buffer_resize(buffer_t *self, size_t n) { 135 | n = nearest_multiple_of(1024, n); 136 | self->len = n; 137 | self->alloc = self->data = realloc(self->alloc, n + 1); 138 | if (!self->alloc) return -1; 139 | self->alloc[n] = '\0'; 140 | return 0; 141 | } 142 | 143 | /* 144 | * Append a printf-style formatted string to the buffer. 145 | */ 146 | 147 | int buffer_appendf(buffer_t *self, const char *format, ...) { 148 | va_list ap; 149 | va_list tmpa; 150 | char *dst = NULL; 151 | int length = 0; 152 | int required = 0; 153 | int bytes = 0; 154 | 155 | va_start(ap, format); 156 | 157 | length = buffer_length(self); 158 | 159 | // First, we compute how many bytes are needed 160 | // for the formatted string and allocate that 161 | // much more space in the buffer. 162 | va_copy(tmpa, ap); 163 | required = vsnprintf(NULL, 0, format, tmpa); 164 | va_end(tmpa); 165 | if (-1 == buffer_resize(self, length + required)) { 166 | va_end(ap); 167 | return -1; 168 | } 169 | 170 | // Next format the string into the space that we 171 | // have made room for. 172 | dst = self->data + length; 173 | bytes = vsnprintf(dst, 1 + required, format, ap); 174 | va_end(ap); 175 | 176 | return bytes < 0 177 | ? -1 178 | : 0; 179 | } 180 | 181 | /* 182 | * Append `str` to `self` and return 0 on success, -1 on failure. 183 | */ 184 | 185 | int 186 | buffer_append(buffer_t *self, const char *str) { 187 | return buffer_append_n(self, str, strlen(str)); 188 | } 189 | 190 | /* 191 | * Append the first `len` bytes from `str` to `self` and 192 | * return 0 on success, -1 on failure. 193 | */ 194 | int 195 | buffer_append_n(buffer_t *self, const char *str, size_t len) { 196 | size_t prev = strlen(self->data); 197 | size_t needed = len + prev; 198 | 199 | // enough space 200 | if (self->len > needed) { 201 | strncat(self->data, str, len); 202 | return 0; 203 | } 204 | 205 | // resize 206 | int ret = buffer_resize(self, needed); 207 | if (-1 == ret) return -1; 208 | strncat(self->data, str, len); 209 | 210 | return 0; 211 | } 212 | 213 | /* 214 | * Prepend `str` to `self` and return 0 on success, -1 on failure. 215 | */ 216 | 217 | int 218 | buffer_prepend(buffer_t *self, char *str) { 219 | size_t len = strlen(str); 220 | size_t prev = strlen(self->data); 221 | size_t needed = len + prev; 222 | 223 | // enough space 224 | if (self->len > needed) goto move; 225 | 226 | // resize 227 | int ret = buffer_resize(self, needed); 228 | if (-1 == ret) return -1; 229 | 230 | // move 231 | move: 232 | memmove(self->data + len, self->data, prev + 1); 233 | memcpy(self->data, str, len); 234 | 235 | return 0; 236 | } 237 | 238 | /* 239 | * Return a new buffer based on the `from..to` slice of `buf`, 240 | * or NULL on error. 241 | */ 242 | 243 | buffer_t * 244 | buffer_slice(buffer_t *buf, size_t from, ssize_t to) { 245 | size_t len = strlen(buf->data); 246 | 247 | // bad range 248 | if (to < from) return NULL; 249 | 250 | // relative to end 251 | if (to < 0) to = len - ~to; 252 | 253 | // cap end 254 | if (to > len) to = len; 255 | 256 | size_t n = to - from; 257 | buffer_t *self = buffer_new_with_size(n); 258 | memcpy(self->data, buf->data + from, n); 259 | return self; 260 | } 261 | 262 | /* 263 | * Return 1 if the buffers contain equivalent data. 264 | */ 265 | 266 | int 267 | buffer_equals(buffer_t *self, buffer_t *other) { 268 | return 0 == strcmp(self->data, other->data); 269 | } 270 | 271 | /* 272 | * Return the index of the substring `str`, or -1 on failure. 273 | */ 274 | 275 | ssize_t 276 | buffer_indexof(buffer_t *self, char *str) { 277 | char *sub = strstr(self->data, str); 278 | if (!sub) return -1; 279 | return sub - self->data; 280 | } 281 | 282 | /* 283 | * Trim leading whitespace. 284 | */ 285 | 286 | void 287 | buffer_trim_left(buffer_t *self) { 288 | int c; 289 | while ((c = *self->data) && isspace(c)) { 290 | ++self->data; 291 | } 292 | } 293 | 294 | /* 295 | * Trim trailing whitespace. 296 | */ 297 | 298 | void 299 | buffer_trim_right(buffer_t *self) { 300 | int c; 301 | size_t i = buffer_length(self) - 1; 302 | while ((c = self->data[i]) && isspace(c)) { 303 | self->data[i--] = 0; 304 | } 305 | } 306 | 307 | /* 308 | * Trim trailing and leading whitespace. 309 | */ 310 | 311 | void 312 | buffer_trim(buffer_t *self) { 313 | buffer_trim_left(self); 314 | buffer_trim_right(self); 315 | } 316 | 317 | /* 318 | * Fill the buffer with `c`. 319 | */ 320 | 321 | void 322 | buffer_fill(buffer_t *self, int c) { 323 | memset(self->data, c, self->len); 324 | } 325 | 326 | /* 327 | * Fill the buffer with 0. 328 | */ 329 | 330 | void 331 | buffer_clear(buffer_t *self) { 332 | buffer_fill(self, 0); 333 | } 334 | 335 | /* 336 | * Print a hex dump of the buffer. 337 | */ 338 | 339 | void 340 | buffer_print(buffer_t *self) { 341 | int i; 342 | size_t len = self->len; 343 | 344 | printf("\n "); 345 | 346 | // hex 347 | for (i = 0; i < len; ++i) { 348 | printf(" %02x", self->alloc[i]); 349 | if ((i + 1) % 8 == 0) printf("\n "); 350 | } 351 | 352 | printf("\n"); 353 | } 354 | --------------------------------------------------------------------------------