txtbuf.c (4171B)
1 /* 2 * Copyright (c) 2021-2024 lumidify <nobody@lumidify.org> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <stdarg.h> 21 22 #include "memory.h" 23 #include "txtbuf.h" 24 25 txtbuf * 26 txtbuf_new(void) { 27 txtbuf *buf = ltk_malloc(sizeof(txtbuf)); 28 buf->text = NULL; 29 buf->cap = buf->len = 0; 30 return buf; 31 } 32 33 txtbuf * 34 txtbuf_new_from_char(const char *str) { 35 txtbuf *buf = ltk_malloc(sizeof(txtbuf)); 36 buf->text = ltk_strdup(str); 37 buf->len = strlen(str); 38 buf->cap = buf->len + 1; 39 return buf; 40 } 41 42 txtbuf * 43 txtbuf_new_from_char_len(const char *str, size_t len) { 44 txtbuf *buf = ltk_malloc(sizeof(txtbuf)); 45 buf->text = ltk_strndup(str, len); 46 buf->len = len; 47 buf->cap = len + 1; 48 return buf; 49 } 50 51 void 52 txtbuf_fmt(txtbuf *buf, const char *fmt, ...) { 53 va_list args; 54 va_start(args, fmt); 55 int len = vsnprintf(buf->text, buf->cap, fmt, args); 56 /* FIXME: len can never be negative, right? */ 57 /* FIXME: maybe also shrink here */ 58 if ((size_t)len >= buf->cap) { 59 va_end(args); 60 va_start(args, fmt); 61 txtbuf_resize(buf, len); 62 vsnprintf(buf->text, buf->cap, fmt, args); 63 } 64 buf->len = len; 65 va_end(args); 66 } 67 68 void 69 txtbuf_set_text(txtbuf *buf, const char *text) { 70 txtbuf_set_textn(buf, text, strlen(text)); 71 } 72 73 void 74 txtbuf_set_textn(txtbuf *buf, const char *text, size_t len) { 75 txtbuf_resize(buf, len); 76 buf->len = len; 77 memmove(buf->text, text, len); 78 buf->text[buf->len] = '\0'; 79 } 80 81 void 82 txtbuf_append(txtbuf *buf, const char *text) { 83 txtbuf_appendn(buf, text, strlen(text)); 84 } 85 86 /* FIXME: some sort of append that does not resize until there's not enough 87 space so a buffer that will be filled up anyways doesn't have to be 88 constantly resized */ 89 void 90 txtbuf_appendn(txtbuf *buf, const char *text, size_t len) { 91 /* FIXME: overflow protection here and everywhere else */ 92 txtbuf_resize(buf, buf->len + len); 93 memmove(buf->text + buf->len, text, len); 94 buf->len += len; 95 buf->text[buf->len] = '\0'; 96 } 97 98 void 99 txtbuf_resize(txtbuf *buf, size_t sz) { 100 /* always leave room for extra \0 */ 101 size_t cap = ideal_array_size(buf->cap, sz + 1); 102 if (cap != buf->cap) { 103 buf->text = ltk_realloc(buf->text, cap); 104 buf->cap = cap; 105 } 106 } 107 108 void 109 txtbuf_destroy(txtbuf *buf) { 110 if (!buf) 111 return; 112 free(buf->text); 113 free(buf); 114 } 115 116 void 117 txtbuf_copy(txtbuf *dst, txtbuf *src) { 118 txtbuf_resize(dst, src->len); 119 if (src->text && dst->text) { 120 memcpy(dst->text, src->text, src->len); 121 dst->text[src->len] = '\0'; 122 } 123 dst->len = src->len; 124 } 125 126 txtbuf * 127 txtbuf_dup(txtbuf *src) { 128 txtbuf *dst = txtbuf_new(); 129 txtbuf_copy(dst, src); 130 return dst; 131 } 132 133 char * 134 txtbuf_get_textcopy(txtbuf *buf) { 135 return buf->text ? ltk_strndup(buf->text, buf->len) : ltk_strdup(""); 136 } 137 138 const char * 139 txtbuf_get_text(txtbuf *buf) { 140 return buf->text; 141 } 142 143 size_t 144 txtbuf_len(txtbuf *buf) { 145 return buf->len; 146 } 147 148 /* FIXME: proper "normalize" function to add nul-termination if needed */ 149 int 150 txtbuf_cmp(txtbuf *buf1, txtbuf *buf2) { 151 /* FIXME: I guess strcmp would be possible as well since it's nul-terminated now */ 152 /* FIXME: Test this because I was tired while writing it */ 153 int cmp = strncmp(buf1->text, buf2->text, buf1->len < buf2->len ? buf1->len : buf2->len); 154 if (cmp == 0) { 155 if (buf1->len < buf2->len) 156 return -1; 157 else if (buf1->len > buf2->len) 158 return 1; 159 } 160 return cmp; 161 } 162 163 int 164 txtbuf_eql(txtbuf *buf1, txtbuf *buf2) { 165 return txtbuf_cmp(buf1, buf2) == 0; 166 } 167 168 void 169 txtbuf_clear(txtbuf *buf) { 170 if (buf->len > 0) { 171 buf->len = 0; 172 buf->text[0] = '\0'; 173 } 174 }