From 09d9d53ecece8d36d8338d9f90c76ae220367f0f Mon Sep 17 00:00:00 2001 From: cancel Date: Tue, 7 Jan 2020 07:20:13 +0900 Subject: [PATCH] Add start of gbstring.h/.c Derived from gingerBill's public domain gb_string.h --- thirdparty/gbstring.c | 290 ++++++++++++++++++++++++++++++++++++++++++ thirdparty/gbstring.h | 41 ++++++ tool | 2 +- 3 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 thirdparty/gbstring.c create mode 100644 thirdparty/gbstring.h diff --git a/thirdparty/gbstring.c b/thirdparty/gbstring.c new file mode 100644 index 0000000..fb7b8f4 --- /dev/null +++ b/thirdparty/gbstring.c @@ -0,0 +1,290 @@ +#include "gbstring.h" +#include +#include +#include + +// Derived from gingerBill's public domain gb_string.h file. + +/* Examples: */ +/* C example */ +#if 0 +#include +#include +#include "gbstring.h" + +int main(int argc, char **argv) { + gbs str = gbs_new("Hello"); + gbs other_str = gbs_newlen(", ", 2); + str = gbs_catgbs(str, other_str); + str = gbs_cat(str, "world!"); + + printf("%s\n", str); // Hello, world! + + printf("str length = %d\n", gbs_len(str)); + + str = gbs_cpy(str, "Potato soup"); + printf("%s\n", str); // Potato soup + + str = gbs_cpy(str, "Hello"); + other_str = gbs_cpy(other_str, "Pizza"); + if (gbs_streq(str, other_str)) + printf("Not called\n"); + else + printf("Called\n"); + + str = gbs_cpy(str, "Ab.;!...AHello World ??"); + str = gbs_trim(str, "Ab.;!. ?"); + printf("%s\n", str); // "Hello World" + + gbs_free(str); + gbs_free(other_str); + +} +#endif + +typedef struct gbStringHeader { + size_t len; + size_t cap; +} gbStringHeader; + +#define GB_STRING_HEADER(s) ((gbStringHeader *)s - 1) + +static void gbs_setlen(gbs str, size_t len) { + GB_STRING_HEADER(str)->len = len; +} + +static void gbs_setcap(gbs str, size_t cap) { + GB_STRING_HEADER(str)->cap = cap; +} +gbs gbs_empty(void) { return gbs_newlen(NULL, 0); } + +gbs gbs_newlen(void const *init_str, size_t len) { + gbs str; + gbStringHeader *header; + size_t header_size = sizeof(gbStringHeader); + void *ptr = malloc(header_size + len + 1); + if (ptr == NULL) + return NULL; + if (!init_str) + memset(ptr, 0, header_size + len + 1); + + str = (char *)ptr + header_size; + header = GB_STRING_HEADER(str); + header->len = len; + header->cap = len; + if (len && init_str) + memcpy(str, init_str, len); + str[len] = '\0'; + + return str; +} + +gbs gbs_new(char const *str) { + size_t len = str ? strlen(str) : 0; + return gbs_newlen(str, len); +} + +void gbs_free(gbs str) { + if (str == NULL) + return; + + free((gbStringHeader *)str - 1); +} + +gbs gbs_dup(gbs const str) { return gbs_newlen(str, gbs_len(str)); } + +size_t gbs_len(gbs const str) { return GB_STRING_HEADER(str)->len; } + +size_t gbs_cap(gbs const str) { return GB_STRING_HEADER(str)->cap; } + +size_t gbs_avail(gbs const str) { + gbStringHeader *h = GB_STRING_HEADER(str); + if (h->cap > h->len) + return h->cap - h->len; + return 0; +} + +void gbs_clear(gbs str) { + gbs_setlen(str, 0); + str[0] = '\0'; +} + +gbs gbs_catlen(gbs str, void const *other, size_t other_len) { + size_t curr_len = gbs_len(str); + + str = gbs_makeroomfor(str, other_len); + if (str == NULL) + return NULL; + + memcpy(str + curr_len, other, other_len); + str[curr_len + other_len] = '\0'; + gbs_setlen(str, curr_len + other_len); + + return str; +} + +gbs gbs_catgbs(gbs str, gbs const other) { + return gbs_catlen(str, other, gbs_len(other)); +} + +gbs gbs_cat(gbs str, char const *other) { + return gbs_catlen(str, other, strlen(other)); +} + +gbs gbs_cpylen(gbs str, char const *cstr, size_t len) { + if (gbs_cap(str) < len) { + str = gbs_makeroomfor(str, len - gbs_len(str)); + if (str == NULL) + return NULL; + } + + memcpy(str, cstr, len); + str[len] = '\0'; + gbs_setlen(str, len); + + return str; +} +gbs gbs_cpy(gbs str, char const *cstr) { + return gbs_cpylen(str, cstr, strlen(cstr)); +} + +static void *gb__string_realloc(void *ptr, size_t old_size, size_t new_size) { + void *new_ptr; + if (!ptr) + return malloc(new_size); + + if (new_size < old_size) + new_size = old_size; + + if (old_size == new_size) + return ptr; + + new_ptr = malloc(new_size); + if (!new_ptr) + return NULL; + + memcpy(new_ptr, ptr, old_size); + + free(ptr); + + return new_ptr; +} + +gbs gbs_makeroomfor(gbs str, size_t add_len) { + size_t len = gbs_len(str); + size_t new_len = len + add_len; + void *ptr, *new_ptr; + size_t available, old_size, new_size; + + available = gbs_avail(str); + if (available >= add_len) /* Return if there is enough space left */ + return str; + + ptr = (char *)str - sizeof(gbStringHeader); + old_size = sizeof(gbStringHeader) + gbs_len(str) + 1; + new_size = sizeof(gbStringHeader) + new_len + 1; + + new_ptr = gb__string_realloc(ptr, old_size, new_size); + if (new_ptr == NULL) + return NULL; + str = (char *)new_ptr + sizeof(gbStringHeader); + + gbs_setcap(str, new_len); + + return str; +} + +size_t gbs_totalmemused(gbs const s) { + size_t cap = gbs_cap(s); + return sizeof(gbStringHeader) + cap; +} + +bool gbs_streq(gbs const lhs, gbs const rhs) { + size_t lhs_len, rhs_len, i; + lhs_len = gbs_len(lhs); + rhs_len = gbs_len(rhs); + if (lhs_len != rhs_len) + return false; + + for (i = 0; i < lhs_len; i++) { + if (lhs[i] != rhs[i]) + return false; + } + + return true; +} + +gbs gbs_trim(gbs str, char const *cut_set) { + char *start, *end, *start_pos, *end_pos; + size_t len; + + start_pos = start = str; + end_pos = end = str + gbs_len(str) - 1; + + while (start_pos <= end && strchr(cut_set, *start_pos)) + start_pos++; + while (end_pos > start_pos && strchr(cut_set, *end_pos)) + end_pos--; + + len = (start_pos > end_pos) ? 0 : ((size_t)(end_pos - start_pos) + 1); + + if (str != start_pos) + memmove(str, start_pos, len); + str[len] = '\0'; + + gbs_setlen(str, len); + + return str; +} + +gbs gbs_catvprintf(gbs s, const char *fmt, va_list ap) { + va_list cpy; + char staticbuf[1024], *buf = staticbuf, *t; + size_t buflen = strlen(fmt) * 2; + + /* We try to start using a static buffer for speed. + * If not possible we revert to heap allocation. */ + if (buflen > sizeof(staticbuf)) { + buf = malloc(buflen); + if (buf == NULL) + return NULL; + } else { + buflen = sizeof(staticbuf); + } + + /* Try with buffers two times bigger every time we fail to + * fit the string in the current buffer size. */ + while (1) { + buf[buflen - 2] = '\0'; + va_copy(cpy, ap); + vsnprintf(buf, buflen, fmt, cpy); + va_end(cpy); + if (buf[buflen - 2] != '\0') { + if (buf != staticbuf) + free(buf); + buflen *= 2; + buf = malloc(buflen); + if (buf == NULL) + return NULL; + continue; + } + break; + } + + /* Finally concat the obtained string to the SDS string and return it. */ + t = gbs_cat(s, buf); + if (buf != staticbuf) + free(buf); + return t; +} + +gbs gbs_catprintf(gbs s, char const *fmt, ...) { + va_list ap; + char *t; + va_start(ap, fmt); + t = gbs_catvprintf(s, fmt, ap); + va_end(ap); + return t; +} + +#undef GB_STRING_HEADER diff --git a/thirdparty/gbstring.h b/thirdparty/gbstring.h new file mode 100644 index 0000000..526b890 --- /dev/null +++ b/thirdparty/gbstring.h @@ -0,0 +1,41 @@ +#pragma once +#include +#include +#include + +typedef char *gbs; + +gbs gbs_empty(void); +gbs gbs_newlen(void const *str, size_t len); +gbs gbs_new(char const *str); +void gbs_free(gbs str); + +gbs gbs_dup(gbs const str); + +size_t gbs_len(gbs const str); +size_t gbs_cap(gbs const str); +size_t gbs_avail(gbs const str); + +void gbs_clear(gbs str); + +gbs gbs_catlen(gbs str, void const *other, size_t len); +gbs gbs_cat(gbs str, char const *other); +gbs gbs_catgbs(gbs str, gbs const other); + +gbs gbs_cpylen(gbs str, char const *cstr, size_t len); +gbs gbs_cpy(gbs str, char const *cstr); + +gbs gbs_makeroomfor(gbs str, size_t add_len); + +bool gbs_streq(gbs const lhs, gbs const rhs); + +gbs gbs_trim(gbs str, char const *cut_set); + +gbs gbs_catvprintf(gbs str, const char *fmt, va_list ap); +gbs gbs_catprintf(gbs str, char const *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 2, 3))) +#endif + ; + +size_t gbs_totalmemused(gbs const str); diff --git a/tool b/tool index 056d785..e9b8492 100755 --- a/tool +++ b/tool @@ -308,7 +308,7 @@ build_target() { out_exe=cli ;; orca|tui) - add source_files osc_out.c term_util.c sysmisc.c tui_main.c + add source_files osc_out.c term_util.c sysmisc.c thirdparty/gbstring.c tui_main.c add cc_flags -D_XOPEN_SOURCE_EXTENDED=1 # thirdparty headers (like sokol_time.h) should get -isystem for their # include dir so that any warnings they generate with our warning flags