txtbuf.c (3012B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdarg.h> 5 6 #include "util.h" 7 #include "memory.h" 8 #include "txtbuf.h" 9 #include "assert.h" 10 11 txtbuf * 12 txtbuf_new(void) { 13 txtbuf *buf = ledit_malloc(sizeof(txtbuf)); 14 buf->text = NULL; 15 buf->cap = buf->len = 0; 16 return buf; 17 } 18 19 txtbuf * 20 txtbuf_new_from_char(char *str) { 21 txtbuf *buf = ledit_malloc(sizeof(txtbuf)); 22 buf->text = ledit_strdup(str); 23 buf->len = strlen(str); 24 buf->cap = buf->len + 1; 25 return buf; 26 } 27 28 txtbuf * 29 txtbuf_new_from_char_len(char *str, size_t len) { 30 txtbuf *buf = ledit_malloc(sizeof(txtbuf)); 31 buf->text = ledit_strndup(str, len); 32 buf->len = len; 33 buf->cap = len + 1; 34 return buf; 35 } 36 37 void 38 txtbuf_fmt(txtbuf *buf, char *fmt, ...) { 39 va_list args; 40 va_start(args, fmt); 41 int len = vsnprintf(buf->text, buf->cap, fmt, args); 42 /* FIXME: len can never be negative, right? */ 43 /* FIXME: maybe also shrink here */ 44 if ((size_t)len >= buf->cap) { 45 va_end(args); 46 va_start(args, fmt); 47 txtbuf_resize(buf, len); 48 vsnprintf(buf->text, buf->cap, fmt, args); 49 } 50 buf->len = len; 51 va_end(args); 52 } 53 54 void 55 txtbuf_set_text(txtbuf *buf, char *text) { 56 txtbuf_set_textn(buf, text, strlen(text)); 57 } 58 59 void 60 txtbuf_set_textn(txtbuf *buf, char *text, size_t len) { 61 txtbuf_resize(buf, len); 62 buf->len = len; 63 memmove(buf->text, text, len); 64 buf->text[buf->len] = '\0'; 65 } 66 67 void 68 txtbuf_append(txtbuf *buf, char *text) { 69 txtbuf_appendn(buf, text, strlen(text)); 70 } 71 72 /* FIXME: some sort of append that does not resize until there's not enough 73 space so a buffer that will be filled up anyways doesn't have to be 74 constantly resized */ 75 void 76 txtbuf_appendn(txtbuf *buf, char *text, size_t len) { 77 txtbuf_resize(buf, add_sz(buf->len, len)); 78 memmove(buf->text + buf->len, text, len); 79 buf->len += len; 80 buf->text[buf->len] = '\0'; 81 } 82 83 void 84 txtbuf_resize(txtbuf *buf, size_t sz) { 85 /* always leave room for extra \0 */ 86 size_t cap = ideal_array_size(buf->cap, add_sz(sz, 1)); 87 if (cap != buf->cap) { 88 buf->text = ledit_realloc(buf->text, cap); 89 buf->cap = cap; 90 } 91 } 92 93 void 94 txtbuf_destroy(txtbuf *buf) { 95 if (!buf) 96 return; 97 free(buf->text); 98 free(buf); 99 } 100 101 void 102 txtbuf_copy(txtbuf *dst, txtbuf *src) { 103 txtbuf_resize(dst, src->len); 104 if (src->text && dst->text) { 105 memcpy(dst->text, src->text, src->len); 106 dst->text[src->len] = '\0'; 107 } 108 dst->len = src->len; 109 } 110 111 txtbuf * 112 txtbuf_dup(txtbuf *src) { 113 txtbuf *dst = txtbuf_new(); 114 txtbuf_copy(dst, src); 115 return dst; 116 } 117 118 int 119 txtbuf_cmp(txtbuf *buf1, txtbuf *buf2) { 120 /* FIXME: I guess strcmp would be possible as well since it's nul-terminated now */ 121 /* FIXME: Test this because I was tired while writing it */ 122 int cmp = strncmp(buf1->text, buf2->text, LEDIT_MIN(buf1->len, buf2->len)); 123 if (cmp == 0) { 124 if (buf1->len < buf2->len) 125 return -1; 126 else if (buf1->len > buf2->len) 127 return 1; 128 } 129 return cmp; 130 } 131 132 int 133 txtbuf_eql(txtbuf *buf1, txtbuf *buf2) { 134 return txtbuf_cmp(buf1, buf2) == 0; 135 } 136 137 void 138 txtbuf_clear(txtbuf *buf) { 139 if (buf->len > 0) { 140 buf->len = 0; 141 buf->text[0] = '\0'; 142 } 143 }