txtbuf.c (3291B)
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 = ltk_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(const char *str) { 21 txtbuf *buf = ltk_malloc(sizeof(txtbuf)); 22 buf->text = ltk_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(const char *str, size_t len) { 30 txtbuf *buf = ltk_malloc(sizeof(txtbuf)); 31 buf->text = ltk_strndup(str, len); 32 buf->len = len; 33 buf->cap = len + 1; 34 return buf; 35 } 36 37 void 38 txtbuf_fmt(txtbuf *buf, const 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, const char *text) { 56 txtbuf_set_textn(buf, text, strlen(text)); 57 } 58 59 void 60 txtbuf_set_textn(txtbuf *buf, const 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, const 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, const char *text, size_t len) { 77 /* FIXME: overflow protection here and everywhere else */ 78 txtbuf_resize(buf, buf->len + len); 79 memmove(buf->text + buf->len, text, len); 80 buf->len += len; 81 buf->text[buf->len] = '\0'; 82 } 83 84 void 85 txtbuf_resize(txtbuf *buf, size_t sz) { 86 /* always leave room for extra \0 */ 87 size_t cap = ideal_array_size(buf->cap, sz + 1); 88 if (cap != buf->cap) { 89 buf->text = ltk_realloc(buf->text, cap); 90 buf->cap = cap; 91 } 92 } 93 94 void 95 txtbuf_destroy(txtbuf *buf) { 96 if (!buf) 97 return; 98 free(buf->text); 99 free(buf); 100 } 101 102 void 103 txtbuf_copy(txtbuf *dst, txtbuf *src) { 104 txtbuf_resize(dst, src->len); 105 if (src->text && dst->text) { 106 memcpy(dst->text, src->text, src->len); 107 dst->text[src->len] = '\0'; 108 } 109 dst->len = src->len; 110 } 111 112 txtbuf * 113 txtbuf_dup(txtbuf *src) { 114 txtbuf *dst = txtbuf_new(); 115 txtbuf_copy(dst, src); 116 return dst; 117 } 118 119 char * 120 txtbuf_get_textcopy(txtbuf *buf) { 121 return buf->text ? ltk_strndup(buf->text, buf->len) : ltk_strdup(""); 122 } 123 124 /* FIXME: proper "normalize" function to add nul-termination if needed */ 125 int 126 txtbuf_cmp(txtbuf *buf1, txtbuf *buf2) { 127 /* FIXME: I guess strcmp would be possible as well since it's nul-terminated now */ 128 /* FIXME: Test this because I was tired while writing it */ 129 int cmp = strncmp(buf1->text, buf2->text, buf1->len < buf2->len ? buf1->len : buf2->len); 130 if (cmp == 0) { 131 if (buf1->len < buf2->len) 132 return -1; 133 else if (buf1->len > buf2->len) 134 return 1; 135 } 136 return cmp; 137 } 138 139 int 140 txtbuf_eql(txtbuf *buf1, txtbuf *buf2) { 141 return txtbuf_cmp(buf1, buf2) == 0; 142 } 143 144 void 145 txtbuf_clear(txtbuf *buf) { 146 if (buf->len > 0) { 147 buf->len = 0; 148 buf->text[0] = '\0'; 149 } 150 }