ref: 14c8610315e980655e7e9db9e5907ca1a7a0c4e9
parent: 34d04ad4c3672a1ab0eac8b985184239414c098e
author: cancel <cancel@cancel.fm>
date: Sat Jan 11 03:18:46 EST 2020
Change to use altnerate heap string implementation. `sdd` was the first attempt at making one of these individually-allocated string management/utility things. I didn't end up liking the design, so I tried again from scratch, and called the new one `oso`. Let's see how that one turns out. The name might change again in the future, though I feel better about the design of this one.
--- a/term_util.c
+++ b/term_util.c
@@ -1,5 +1,5 @@
#include "term_util.h"
-#include "sdd.h"
+#include "oso.h"
#include <ctype.h>
#include <form.h>
#include <menu.h>
@@ -564,7 +564,8 @@
void qform_add_text_line(Qform* qf, int id, char const* initial) {
FIELD* f = new_field(1, 30, 0, 0, 0, 0);
- set_field_buffer(f, 0, initial);
+ if (initial)
+ set_field_buffer(f, 0, initial);
set_field_userptr(f, (void*)(intptr_t)(id));
field_opts_off(f, O_WRAP | O_BLANK | O_STATIC);
qf->ncurses_fields[qf->fields_count] = f;
@@ -665,7 +666,7 @@
return NULL;
}
-bool qform_get_text_line(Qform const* qf, int id, sdd** out) {
+bool qform_get_text_line(Qform const* qf, int id, oso** out) {
FIELD* f = qform_find_field(qf, id);
if (!f)
return false;
@@ -674,6 +675,6 @@
if (!buf)
return false;
Usz trimmed = size_without_trailing_spaces(buf);
- *out = *out ? sdd_cpylen(*out, buf, trimmed) : sdd_newlen(buf, trimmed);
- return (bool)*out;
+ osoputlen(out, buf, trimmed);
+ return osolen(*out) > 0;
}
--- a/term_util.h
+++ b/term_util.h
@@ -4,7 +4,7 @@
#define CTRL_PLUS(c) ((c)&037)
-struct sdd;
+struct oso;
typedef enum {
C_natural,
@@ -143,6 +143,6 @@
void qform_push_to_nav(Qform* qf);
void qform_set_title(Qform* qf, char const* title);
bool qform_drive(Qform* qf, int key, Qform_action* out_action);
-bool qform_get_text_line(Qform const* qf, int id, struct sdd** out);
+bool qform_get_text_line(Qform const* qf, int id, struct oso** out);
extern Qnav_stack qnav_stack;
--- /dev/null
+++ b/thirdparty/oso.c
@@ -1,0 +1,232 @@
+#include "oso.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
+#if __has_attribute(noinline) && __has_attribute(noclone)
+#define OSO_NOINLINE __attribute__((noinline, noclone))
+#elif __has_attribute(noinline)
+#define OSO_NOINLINE __attribute__((noinline))
+#endif
+#elif defined(_MSC_VER)
+#define OSO_NOINLINE __declspec(noinline)
+#endif
+#ifndef OSO_NOINLINE
+#define OSO_NOINLINE
+#endif
+
+#define OSO_INTERNAL OSO_NOINLINE static
+#define OSO_HDR(s) ((oso_header *)s - 1)
+#define OSO_CAP_MAX (SIZE_MAX - (sizeof(oso_header) + 1))
+
+typedef struct oso {
+ size_t len;
+ size_t cap;
+} oso_header;
+
+OSO_INTERNAL oso *oso_impl_reallochdr(oso_header *hdr, size_t new_cap) {
+ if (hdr) {
+ oso_header *new_hdr = realloc(hdr, sizeof(oso_header) + new_cap + 1);
+ if (!new_hdr) {
+ free(hdr);
+ return NULL;
+ }
+ new_hdr->cap = new_cap;
+ return new_hdr + 1;
+ }
+ hdr = malloc(sizeof(oso_header) + new_cap + 1);
+ if (!hdr)
+ return NULL;
+ hdr->len = 0;
+ hdr->cap = new_cap;
+ ((char *)(hdr + 1))[0] = '\0';
+ return hdr + 1;
+}
+OSO_INTERNAL oso *oso_impl_catvprintf(oso *s, char const *fmt, va_list ap) {
+ size_t old_len;
+ int required;
+ va_list cpy;
+ va_copy(cpy, ap);
+ required = vsnprintf(NULL, 0, fmt, cpy);
+ va_end(cpy);
+ osomakeroomfor(&s, (size_t)required);
+ if (!s)
+ return NULL;
+ old_len = OSO_HDR(s)->len;
+ vsnprintf((char *)s + old_len, (size_t)required + 1, fmt, ap);
+ OSO_HDR(s)->len = old_len + (size_t)required;
+ return s;
+}
+
+OSO_NOINLINE
+void osoensurecap(oso **p, size_t new_cap) {
+ oso *s = *p;
+ if (new_cap > OSO_CAP_MAX) {
+ if (s) {
+ free(OSO_HDR(s));
+ *p = NULL;
+ }
+ return;
+ }
+ oso_header *hdr = NULL;
+ if (s) {
+ hdr = OSO_HDR(s);
+ if (hdr->cap >= new_cap)
+ return;
+ }
+ *p = oso_impl_reallochdr(hdr, new_cap);
+}
+
+OSO_NOINLINE
+void osomakeroomfor(oso **p, size_t add_len) {
+ oso *s = *p;
+ oso_header *hdr = NULL;
+ size_t new_cap;
+ if (s) {
+ hdr = OSO_HDR(s);
+ size_t len = hdr->len, cap = hdr->cap;
+ if (len > OSO_CAP_MAX - add_len) { // overflow, goodnight
+ free(hdr);
+ *p = NULL;
+ return;
+ }
+ new_cap = len + add_len;
+ if (cap >= new_cap)
+ return;
+ } else {
+ if (add_len > OSO_CAP_MAX)
+ return;
+ new_cap = add_len;
+ }
+ *p = oso_impl_reallochdr(hdr, new_cap);
+}
+
+void osoput(oso **p, char const *restrict cstr) {
+ osoputlen(p, cstr, strlen(cstr));
+}
+
+OSO_NOINLINE
+void osoputlen(oso **p, char const *restrict cstr, size_t len) {
+ oso *s = *p;
+ osoensurecap(&s, len);
+ if (s) {
+ OSO_HDR(s)->len = len;
+ memcpy((char *)s, cstr, len);
+ ((char *)s)[len] = '\0';
+ }
+ *p = s;
+}
+void osoputoso(oso **p, oso const *other) {
+ if (!other)
+ return;
+ osoputlen(p, (char const *)other, OSO_HDR(other)->len);
+}
+void osoputvprintf(oso **p, char const *fmt, va_list ap) {
+ *p = oso_impl_catvprintf(*p, fmt, ap);
+}
+void osoputprintf(oso **p, char const *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ *p = oso_impl_catvprintf(*p, fmt, ap);
+ va_end(ap);
+}
+void osocat(oso **p, char const *cstr) { osocatlen(p, cstr, strlen(cstr)); }
+OSO_NOINLINE
+void osocatlen(oso **p, char const *cstr, size_t len) {
+ oso *s = *p;
+ osomakeroomfor(&s, len);
+ if (s) {
+ oso_header *hdr = OSO_HDR(s);
+ size_t curr_len = hdr->len;
+ memcpy((char *)s + curr_len, cstr, len);
+ ((char *)s)[curr_len + len] = '\0';
+ hdr->len = curr_len + len;
+ }
+ *p = s;
+}
+void osocatoso(oso **p, oso const *other) {
+ if (!other)
+ return;
+ osocatlen(p, (char const *)other, OSO_HDR(other)->len);
+}
+void osocatvprintf(oso **p, char const *fmt, va_list ap) {
+ oso *s = *p;
+ if (s) {
+ OSO_HDR(s)->len = 0;
+ ((char *)s)[0] = '\0';
+ }
+ *p = oso_impl_catvprintf(s, fmt, ap);
+}
+void osocatprintf(oso **p, char const *fmt, ...) {
+ oso *s = *p;
+ if (s) {
+ OSO_HDR(s)->len = 0;
+ ((char *)s)[0] = '\0';
+ }
+ va_list ap;
+ va_start(ap, fmt);
+ *p = oso_impl_catvprintf(s, fmt, ap);
+ va_end(ap);
+}
+void osoclear(oso **p) {
+ oso *s = *p;
+ if (!s)
+ return;
+ OSO_HDR(s)->len = 0;
+ ((char *)s)[0] = '\0';
+}
+void osofree(oso *s) {
+ if (s)
+ free(OSO_HDR(s));
+}
+void osowipe(oso **p) {
+ osofree(*p);
+ *p = NULL;
+}
+void ososwap(oso const **a, oso const **b) {
+ oso const *tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+size_t osolen(oso const *s) { return s ? OSO_HDR(s)->len : 0; }
+size_t osocap(oso const *s) { return s ? OSO_HDR(s)->cap : 0; }
+void osolencap(oso const *s, size_t *out_len, size_t *out_cap) {
+ if (!s) {
+ *out_len = 0;
+ *out_cap = 0;
+ return;
+ }
+ oso_header *hdr = OSO_HDR(s);
+ *out_len = hdr->len;
+ *out_cap = hdr->cap;
+}
+size_t osoavail(oso const *s) {
+ if (!s)
+ return 0;
+ oso_header *h = OSO_HDR(s);
+ return h->cap - h->len;
+}
+
+void osotrim(oso *restrict s, char const *restrict cut_set) {
+ if (!s)
+ return;
+ char *str, *start, *end, *start_pos, *end_pos;
+ start_pos = start = str = (char *)s;
+ end_pos = end = str + OSO_HDR(s)->len - 1;
+ while (start_pos <= end && strchr(cut_set, *start_pos))
+ start_pos++;
+ while (end_pos > start_pos && strchr(cut_set, *end_pos))
+ end_pos--;
+ size_t len = (start_pos > end_pos) ? 0 : ((size_t)(end_pos - start_pos) + 1);
+ OSO_HDR(s)->len = len;
+ if (str != start_pos)
+ memmove(str, start_pos, len);
+ str[len] = '\0';
+}
+
+#undef OSO_HDR
+#undef OSO_NOINLINE
+#undef OSO_CAP_MAX
+#undef OSO_INTERNAL
--- /dev/null
+++ b/thirdparty/oso.h
@@ -1,0 +1,182 @@
+#pragma once
+// Heap-allocated string handling.
+// Inspired by antirez's sds and gingerBill's gb_string.h.
+//
+// "I need null-terminated strings to interact with libc and/or POSIX, and my
+// software isn't serious enough to warrant using arena or page allocation
+// strategies. Manually fussing with null-terminated strings with libc sucks,
+// even though we're allocating everything individually on the heap! Why can't
+// we at least get a nicer interface for the trade-off we've already made?"
+//
+// EXAMPLE
+// ---------
+// oso *mystring = NULL;
+// osoput(&mystring, "Hello World");
+// printf((char *)mystring);
+// osoput(&mystring, "How about some pancakes?");
+// printf((char *)mystring);
+// osocat(&mstring, " Sure!");
+// printf((char *)mystring);
+// osofree(mystring);
+//
+// > Hello World!
+// > How about some pancakes?
+// > How about some pancakes? Sure!
+//
+// RULES
+// -------
+// 1. `oso *` can always be cast to `char *`, but it's your job to check if
+// it's null before passing it to on something that doesn't tolerate null
+// pointers.
+//
+// 2. The functions defined in this header tolerate null pointers like this:
+//
+// `oso *` -> OK to be null.
+// `char const *` -> Must not be null.
+// `oso **` -> Must not be null, but the `oso *` pointed to
+// can be null. The pointed-to `oso *` may be
+// modified during the call.
+//
+// 3. `oso *` and `char const *` as arguments to the functions here must not
+// overlap in memory. During the call, the buffer pointed to by a `oso *`
+// might need to be reallocated in memory to make room for the `char const
+// *` contents, and if the `char const *` contents end up being moved by
+// that operation, the pointer will no longer be pointing at valid memory.
+// (This also applies to functions which accept two `oso *` as inputs.)
+//
+// Parameters with the type `oso *` are safe to pass as a null pointer. But
+// `oso **` parameters shouldn't be null. The `oso *` pointed to by the `oso
+// **` can be null, though. In other words, you need to do `&mystring` to pass
+// a `oso **` argument.
+//
+// During the function call, if the `oso *` pointed to by the `oso **` needs to
+// become non-null, or if the existing buffer needs to be moved to grow larger,
+// the `oso *` will be set to a new value.
+//
+// oso *mystring = NULL;
+// osolen(mystring); // Gives 0
+// osocat(&mystring, "waffles");
+// osolen(mystring); // Gives 7
+// osofree(mystring);
+//
+// NAMES
+// -------
+// osoput______ -> Copy a string into an oso string.
+// osocat______ -> Append a string onto the end of an oso string.
+// ______len -> Do it with an explicit length argument, so the C-string
+// doesn't have to be '\0'-terminated.
+// ______oso -> Do it with a second oso string.
+// ______printf -> Do it by using printf.
+//
+// ALLOC FAILURE
+// ---------------
+// If an allocation fails (including failing to reallocate) the `oso *` will be
+// set to null. If you decide to handle memory allocation failures, you'll need
+// to check for that.
+//
+// In the oso code, if a reallocation of an existing buffer fails (`realloc()`
+// returns null) then the old, still-valid buffer is immediately freed.
+// Therefore, in an out-of-memory situation, it's possible that you will *lose*
+// your strings without getting a chance to do something with the old buffers.
+//
+// Variations of the oso functions may be added in the future, with a _c suffix
+// or something, which preserve the old buffer and return an error code in the
+// event of a reallocation failure. I'm not sure how important this is, since
+// most existing libc-based software doesn't handle out-of-memory conditions
+// for small strings without imploding.
+//
+// (sds, for example, will lose your string *and* leak the old buffer if a
+// reallocation fails.)
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
+#if __has_attribute(format)
+#define OSO_PRINTF(...) __attribute__((format(printf, __VA_ARGS__)))
+#endif
+#if __has_attribute(nonnull)
+#define OSO_NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
+#endif
+#endif
+#ifndef OSO_PRINTF
+#define OSO_PRINTF(...)
+#endif
+#ifndef OSO_NONNULL
+#define OSO_NONNULL(...)
+#endif
+
+typedef struct oso oso;
+
+#define osoc(s) ((char const *)s)
+
+void osoput(oso **p, char const *cstr) OSO_NONNULL();
+// ^- Copies the '\0'-terminated string into the `oso *` string located at
+// `*p`. If `*p` is null or there isn't enough capacity to hold `cstr`, it
+// will be reallocated. The pointer value at `*p` will be updated if
+// necessary. `*p` and `cstr` must not point to overlapping memory.
+void osoputlen(oso **p, char const *cstr, size_t len) OSO_NONNULL();
+// ^- Same as above, but uses an additional parameter that specifies the length
+// of `cstr, and `cstr` does not have to be '\0'-terminated.
+// `*p` and `cstr` must not point to overlapping memory.
+void osoputoso(oso **p, oso const *other) OSO_NONNULL(1);
+// ^- Same as above, but using another `oso`. `*p` and `other` must not point
+// to overlapping memory.
+void osoputvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2)
+ OSO_PRINTF(2, 0);
+void osoputprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2)
+ OSO_PRINTF(2, 3);
+// ^- Same as above, but do it by using printf.
+
+void osocat(oso **p, char const *cstr) OSO_NONNULL();
+void osocatlen(oso **p, char const *cstr, size_t len) OSO_NONNULL();
+void osocatoso(oso **p, oso const *other) OSO_NONNULL(1);
+void osocatvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2)
+ OSO_PRINTF(2, 0);
+void osocatprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2)
+ OSO_PRINTF(2, 3);
+// ^- Append string to oso string. Same rules as `osoput` family.
+
+void osoensurecap(oso **p, size_t cap) OSO_NONNULL();
+// ^- Ensure that s has at least `cap` memory allocated for it. This does not
+// care about the strlen of the characters or the prefixed length count --
+// only the backing memory allocation.
+void osomakeroomfor(oso **p, size_t len) OSO_NONNULL();
+// ^- Ensure that s has enough allocated space after the '\0'-terminnation
+// character to hold an additional add_len characters. It does not adjust
+// the `length` number value, only the capacity, if necessary.
+//
+// Both `osoensurecap()` and `osomakeroomfor()` can be used to avoid making
+// multiple smaller reallactions as the string grows in the future. You can
+// also use them if you're going to modify the string buffer manually in
+// your own code, and need to create some space in the buffer.
+
+void osoclear(oso **p) OSO_NONNULL();
+// ^- Set len to 0, write '\0' at pos 0. Leaves allocated memory in place.
+void osofree(oso *s);
+// ^- You know. And calling with null is allowed.
+void osowipe(oso **p) OSO_NONNULL();
+// ^- It's like `osofree()`, except you give it a ptr-to-ptr, and it also sets
+// `*p` to null for you when it's done freeing the memory.
+void ososwap(oso const **a, oso const **b) OSO_NONNULL();
+// ^- Swaps the two pointers. Yeah, that's all it does. Why? Because it's
+// common when dealing memory management for individually allocated strings
+// and changing between old and new string values.
+void osopokelen(oso *s, size_t len) OSO_NONNULL();
+// ^- Manually updates length field. Doesn't do anything else for you.
+
+size_t osolen(oso const *s);
+// ^- Bytes in use by the string (not including the '\0' character.)
+size_t osocap(oso const *s);
+// ^- Bytes allocated on heap (not including the '\0' terminator.)
+void osolencap(oso const *s, size_t *out_len, size_t *out_cap)
+ OSO_NONNULL(2, 3);
+// ^- Get both the len and the cap in one call.
+size_t osoavail(oso const *s);
+// ^- osocap(s) - osolen(s)
+
+void osotrim(oso *restrict s, char const *restrict cut_set) OSO_NONNULL(2);
+// ^- Remove the characters in `cut_set` from the beginning and ending of `s`.
+
+#undef OSO_PRINTF
+#undef OSO_NONNULL
--- a/thirdparty/sdd.c
+++ /dev/null
@@ -1,198 +1,0 @@
-// Derived from gingerBill's public domain gb_string.h file.
-#include "sdd.h"
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
-#if __has_attribute(noinline) && __has_attribute(noclone)
-#define SDD_NOINLINE __attribute__((noinline, noclone))
-#elif __has_attribute(noinline)
-#define SDD_NOINLINE __attribute__((noinline))
-#endif
-#elif defined(_MSC_VER)
-#define SDD_NOINLINE __declspec(noinline)
-#endif
-#ifndef SDD_NOINLINE
-#define SDD_NOINLINE
-#endif
-
-#define SDD_INTERNAL SDD_NOINLINE static
-#define SDD_HDR(s) ((sdd_header *)s - 1)
-#define SDD_CAP_MAX (SIZE_MAX - (sizeof(sdd_header) + 1))
-
-typedef struct sdd {
- size_t len;
- size_t cap;
-} sdd_header;
-
-SDD_INTERNAL sdd *sdd_impl_new(char const *init, size_t len, size_t cap) {
- if (cap > SDD_CAP_MAX)
- return NULL;
- sdd_header *header = (sdd *)malloc(sizeof(sdd) + cap + 1);
- if (!header)
- return NULL;
- header->len = len;
- header->cap = cap;
- char *str = (char *)(header + 1);
- if (init)
- memcpy(str, init, len);
- str[len] = '\0';
- return (sdd *)str;
-}
-SDD_INTERNAL sdd *sdd_impl_reallochdr(sdd_header *hdr, size_t new_cap) {
- sdd_header *new_hdr = realloc(hdr, sizeof(sdd_header) + new_cap + 1);
- if (!new_hdr) {
- free(hdr);
- return NULL;
- }
- new_hdr->cap = new_cap;
- return new_hdr + 1;
-}
-SDD_INTERNAL sdd *sdd_impl_catvprintf(sdd *s, char const *fmt, va_list ap) {
- size_t old_len;
- int required;
- va_list cpy;
- va_copy(cpy, ap);
- required = vsnprintf(NULL, 0, fmt, cpy);
- va_end(cpy);
- if (s) {
- old_len = SDD_HDR(s)->len;
- s = sdd_makeroomfor(s, (size_t)required);
- } else {
- old_len = 0;
- s = sdd_newcap((size_t)required);
- }
- if (!s)
- return NULL;
- vsnprintf((char *)s + old_len, (size_t)required + 1, fmt, ap);
- SDD_HDR(s)->len = old_len + (size_t)required;
- return s;
-}
-
-sdd *sdd_new(char const *str) {
- size_t len = strlen(str);
- return sdd_impl_new(str, len, len);
-}
-sdd *sdd_newlen(char const *init, size_t len) {
- return sdd_impl_new(init, len, len);
-}
-sdd *sdd_newcap(size_t cap) { return sdd_impl_new(NULL, 0, cap); }
-sdd *sdd_dup(sdd const *str) {
- size_t len = SDD_HDR(str)->len;
- return sdd_impl_new((char const *)str, len, len);
-}
-sdd *sdd_newvprintf(char const *fmt, va_list ap) {
- return sdd_impl_catvprintf(NULL, fmt, ap);
-}
-sdd *sdd_newprintf(char const *fmt, ...) {
- sdd *s;
- va_list ap;
- va_start(ap, fmt);
- s = sdd_impl_catvprintf(NULL, fmt, ap);
- va_end(ap);
- return s;
-}
-void sdd_free(sdd *s) {
- if (!s)
- return;
- free(s - 1);
-}
-sdd *sdd_cpy(sdd *restrict s, char const *restrict cstr) {
- return sdd_cpylen(s, cstr, strlen(cstr));
-}
-SDD_NOINLINE
-sdd *sdd_cpylen(sdd *restrict s, char const *restrict cstr, size_t len) {
- s = sdd_ensurecap(s, len);
- if (!s)
- return NULL;
- SDD_HDR(s)->len = len;
- memcpy(s, cstr, len);
- ((char *)s)[len] = '\0';
- return s;
-}
-sdd *sdd_cpysdd(sdd *restrict s, sdd const *restrict other) {
- return sdd_cpylen(s, (char const *)other, SDD_HDR(other)->len);
-}
-sdd *sdd_cat(sdd *restrict s, char const *restrict other) {
- return sdd_catlen(s, other, strlen(other));
-}
-SDD_NOINLINE
-sdd *sdd_catlen(sdd *restrict s, char const *restrict other, size_t other_len) {
- size_t curr_len = SDD_HDR(s)->len;
- s = sdd_makeroomfor(s, other_len);
- if (!s)
- return NULL;
- memcpy((char *)s + curr_len, other, other_len);
- ((char *)s)[curr_len + other_len] = '\0';
- SDD_HDR(s)->len = curr_len + other_len;
- return s;
-}
-sdd *sdd_catsdd(sdd *restrict s, sdd const *restrict other) {
- return sdd_catlen(s, (char const *)other, SDD_HDR(other)->len);
-}
-sdd *sdd_catvprintf(sdd *restrict s, char const *fmt, va_list ap) {
- return sdd_impl_catvprintf(s, fmt, ap);
-}
-sdd *sdd_catprintf(sdd *restrict s, char const *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- s = sdd_impl_catvprintf(s, fmt, ap);
- va_end(ap);
- return s;
-}
-SDD_NOINLINE
-sdd *sdd_ensurecap(sdd *s, size_t new_cap) {
- sdd_header *hdr = SDD_HDR(s);
- if (new_cap > SDD_CAP_MAX) {
- free(hdr);
- return NULL;
- }
- if (hdr->cap >= new_cap)
- return s;
- return sdd_impl_reallochdr(hdr, new_cap);
-}
-SDD_NOINLINE
-sdd *sdd_makeroomfor(sdd *s, size_t add_len) {
- sdd_header *hdr = SDD_HDR(s);
- size_t len = hdr->len, cap = hdr->cap;
- if (len > SDD_CAP_MAX - add_len) { // overflow, goodnight
- free(hdr);
- return NULL;
- }
- size_t new_cap = len + add_len;
- if (cap >= new_cap)
- return s;
- return sdd_impl_reallochdr(hdr, new_cap);
-}
-size_t sdd_len(sdd const *s) { return SDD_HDR(s)->len; }
-size_t sdd_cap(sdd const *s) { return SDD_HDR(s)->cap; }
-size_t sdd_avail(sdd const *s) {
- sdd_header *h = SDD_HDR(s);
- return h->cap - h->len;
-}
-void sdd_clear(sdd *s) {
- SDD_HDR(s)->len = 0;
- ((char *)s)[0] = '\0';
-}
-void sdd_pokelen(sdd *s, size_t len) { SDD_HDR(s)->len = len; }
-void sdd_trim(sdd *restrict s, char const *restrict cut_set) {
- char *str, *start, *end, *start_pos, *end_pos;
- start_pos = start = str = (char *)s;
- end_pos = end = str + SDD_HDR(s)->len - 1;
- while (start_pos <= end && strchr(cut_set, *start_pos))
- start_pos++;
- while (end_pos > start_pos && strchr(cut_set, *end_pos))
- end_pos--;
- size_t len = (start_pos > end_pos) ? 0 : ((size_t)(end_pos - start_pos) + 1);
- SDD_HDR(s)->len = len;
- if (str != start_pos)
- memmove(str, start_pos, len);
- str[len] = '\0';
-}
-
-#undef SDD_HDR
-#undef SDD_NOINLINE
-#undef SDD_CAP_MAX
-#undef SDD_INTERNAL
--- a/thirdparty/sdd.h
+++ /dev/null
@@ -1,104 +1,0 @@
-// Strings, Dynamic, Dumb
-#pragma once
-#include <stdarg.h>
-#include <stddef.h>
-
-#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
-#if __has_attribute(format)
-#define SDD_PRINTF(n1, n2) __attribute__((format(printf, n1, n2)))
-#endif
-#if __has_attribute(nonnull)
-#define SDD_NONNULL(...) __attribute__((nonnull __VA_ARGS__))
-#endif
-#if __has_attribute(malloc) && __has_attribute(warn_unused_result)
-#define SDD_ALLOC __attribute__((malloc, warn_unused_result))
-#elif __has_attribute(warn_unused_result)
-#define SDD_ALLOC __attribute__((warn_unused_result))
-#endif
-#if __has_attribute(warn_unused_result)
-#define SDD_USED __attribute__((warn_unused_result))
-#endif
-#endif
-#ifndef SDD_PRINTF
-#define SDD_PRINTF(n1, n2)
-#endif
-#ifndef SDD_NONNULL
-#define SDD_NONNULL(...)
-#endif
-#ifndef SDD_ALLOC
-#define SDD_ALLOC
-#endif
-#ifndef SDD_USED
-#define SDD_USED
-#endif
-
-typedef struct sdd sdd;
-
-#define sddc(s) ((char *)s)
-#define sddcc(s) ((char const *)s)
-
-sdd *sdd_new(char const *s) SDD_NONNULL() SDD_ALLOC;
-// ^- Create new with copy of '\0'-terminated cstring.
-sdd *sdd_newlen(char const *s, size_t len) SDD_NONNULL() SDD_ALLOC;
-// ^- Same, but without calling strlen().
-// Resulting new string will be '\0'-terminated.
-sdd *sdd_newcap(size_t cap) SDD_ALLOC;
-// ^- 'Raw' new with a specific capacity.
-// Length will be set to 0, and '\0' written at position 0.
-sdd *sdd_dup(sdd const *s) SDD_ALLOC;
-// ^- Same as sdd_newlen(str, sdd_len(str))
-sdd *sdd_newvprintf(char const *fmt, va_list ap) SDD_ALLOC;
-sdd *sdd_newprintf(char const *fmt, ...) SDD_PRINTF(1, 2) SDD_ALLOC;
-// ^- Create new by using printf
-void sdd_free(sdd *s);
-// ^- Calling with null is allowed.
-
-sdd *sdd_cpy(sdd *restrict s, char const *restrict cstr) SDD_NONNULL() SDD_USED;
-// ^- Set `s` to contain the contents of `cstr`. This is really more like
-// "change into" rather than "copy".
-sdd *sdd_cpylen(sdd *restrict s, char const *restrict cstr, size_t len)
- SDD_NONNULL() SDD_USED;
-sdd *sdd_cpysdd(sdd *restrict s, sdd const *restrict other);
-
-sdd *sdd_cat(sdd *restrict s, char const *restrict other)
- SDD_NONNULL() SDD_USED;
-// ^- Appends contents. The two strings must not overlap in memory.
-sdd *sdd_catlen(sdd *restrict s, char const *restrict other, size_t len)
- SDD_NONNULL() SDD_USED;
-sdd *sdd_catsdd(sdd *restrict s, sdd const *restrict other)
- SDD_NONNULL() SDD_USED;
-sdd *sdd_catvprintf(sdd *restrict s, char const *fmt, va_list ap)
- SDD_NONNULL((1, 2)) SDD_USED;
-sdd *sdd_catprintf(sdd *restrict s, char const *fmt, ...) SDD_NONNULL((1, 2))
- SDD_PRINTF(2, 3) SDD_USED;
-// ^- Appends by using printf.
-
-size_t sdd_len(sdd const *s) SDD_NONNULL();
-// ^- Bytes used by string (excluding '\0' terminator)
-size_t sdd_cap(sdd const *s) SDD_NONNULL();
-// ^- Bytes allocated on heap (excluding '\0' terminator)
-size_t sdd_avail(sdd const *s) SDD_NONNULL();
-// ^- sdd_cap(s) - sdd_len(s)
-
-void sdd_clear(sdd *s) SDD_NONNULL();
-// ^- Set len to 0, write '\0' at pos 0. Leaves allocated memory in place.
-void sdd_pokelen(sdd *s, size_t len) SDD_NONNULL();
-// ^- Manually update length field. Doesn't do anything else for you.
-
-void sdd_trim(sdd *restrict s, char const *cut_set) SDD_NONNULL();
-// ^- Remove the characters in cut_set from the beginning and ending of s.
-sdd *sdd_ensurecap(sdd *s, size_t cap) SDD_NONNULL() SDD_USED;
-// ^- Ensure that s has at least cap memory allocated for it. This does not
-// care about the strlen of the characters or the prefixed length count --
-// only the backing memory allocation.
-sdd *sdd_makeroomfor(sdd *s, size_t add_len) SDD_NONNULL() SDD_USED;
-// ^- Ensure that s has enough allocated space after the valid,
-// null-terminated characters to hold an additional add_len characters. It
-// does not adjust the length, only the capacity, if necessary. Soon after
-// you call sdd_makeroomfor(), you probably will want to call sdd_pokelen(),
-// otherwise you're probably using it incorrectly.
-
-#undef SDD_PRINTF
-#undef SDD_NONNULL
-#undef SDD_ALLOC
-#undef SDD_USED
--- a/tool
+++ b/tool
@@ -323,7 +323,7 @@
out_exe=cli
;;
orca|tui)
- add source_files osc_out.c term_util.c sysmisc.c thirdparty/sdd.c tui_main.c
+ add source_files osc_out.c term_util.c sysmisc.c thirdparty/oso.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
--- a/tui_main.c
+++ b/tui_main.c
@@ -3,7 +3,7 @@
#include "field.h"
#include "gbuffer.h"
#include "osc_out.h"
-#include "sdd.h"
+#include "oso.h"
#include "sim.h"
#include "sysmisc.h"
#include "term_util.h"
@@ -2134,15 +2134,15 @@
qform_push_to_nav(qf);
}
-bool try_save_with_msg(Field* field, sdd const* str) {
- if (!sdd_len(str))
+bool try_save_with_msg(Field* field, oso const* str) {
+ if (!osolen(str))
return false;
- bool ok = hacky_try_save(field, sddc(str));
+ bool ok = hacky_try_save(field, osoc(str));
if (ok) {
- qmsg_printf_push(NULL, "Saved to:\n%s", sddc(str));
+ qmsg_printf_push(NULL, "Saved to:\n%s", osoc(str));
} else {
qmsg_printf_push("Error Saving File", "Unable to save file to:\n%s",
- sddc(str));
+ osoc(str));
}
return ok;
}
@@ -2380,7 +2380,7 @@
Argopt_portmidi_output_device},
#endif
{NULL, 0, NULL, 0}};
- sdd* file_name = NULL;
+ oso* file_name = NULL;
int undo_history_limit = 100;
char const* osc_hostname = NULL;
char const* osc_port = NULL;
@@ -2538,7 +2538,7 @@
if (optind == argc - 1) {
should_autosize_grid = false;
- file_name = sdd_new(argv[optind]);
+ osoput(&file_name, argv[optind]);
} else if (optind < argc - 1) {
fprintf(stderr, "Expected only 1 file argument.\n");
exit(1);
@@ -2572,18 +2572,17 @@
}
}
- if (file_name) {
- Field_load_error fle = field_load_file(sddc(file_name), &ged_state.field);
+ if (osolen(file_name)) {
+ Field_load_error fle = field_load_file(osoc(file_name), &ged_state.field);
if (fle != Field_load_error_ok) {
char const* errstr = field_load_error_string(fle);
fprintf(stderr, "File load error: %s.\n", errstr);
ged_deinit(&ged_state);
qnav_deinit();
- sdd_free(file_name);
+ osofree(file_name);
exit(1);
}
} else {
- file_name = sdd_newcap(0);
// Temp hacky stuff: we've crammed two code paths into the KEY_RESIZE event
// case. One of them is for the initial setup for an automatic grid size.
// The other is for actual resize events. We will factor this out into
@@ -2598,7 +2597,7 @@
(Usz)init_grid_dim_x, '.');
}
}
- ged_state.filename = sdd_len(file_name) ? sddc(file_name) : "unnamed";
+ ged_state.filename = osolen(file_name) ? osoc(file_name) : "unnamed";
ged_set_midi_mode(&ged_state, &midi_mode);
// Set up timer lib
@@ -2902,10 +2901,10 @@
push_confirm_new_file_menu();
break;
case Main_menu_open:
- push_open_form(sddc(file_name));
+ push_open_form(osoc(file_name));
break;
case Main_menu_save:
- if (sdd_len(file_name) > 0) {
+ if (osolen(file_name) > 0) {
try_save_with_msg(&ged_state.field, file_name);
} else {
push_save_as_form("");
@@ -2912,7 +2911,7 @@
}
break;
case Main_menu_save_as:
- push_save_as_form(sddc(file_name));
+ push_save_as_form(osoc(file_name));
break;
case Main_menu_set_tempo:
push_set_tempo_form(ged_state.bpm);
@@ -2986,7 +2985,7 @@
ged_make_cursor_visible(&ged_state);
ged_state.needs_remarking = true;
ged_state.is_draw_dirty = true;
- sdd_clear(file_name);
+ osoclear(&file_name);
ged_state.filename = "unnamed"; // slightly redundant
qnav_stack_pop();
pop_qnav_if_main_menu();
@@ -3022,17 +3021,17 @@
case Qform_action_type_submitted: {
switch (qform_id(qf)) {
case Open_form_id: {
- sdd* temp_name = NULL;
+ oso* temp_name = NULL;
if (qform_get_text_line(qf, Open_name_text_line_id, &temp_name) &&
- sdd_len(temp_name) > 0) {
+ osolen(temp_name) > 0) {
undo_history_push(&ged_state.undo_hist, &ged_state.field,
ged_state.tick_num);
Field_load_error fle =
- field_load_file(sddc(temp_name), &ged_state.field);
+ field_load_file(osoc(temp_name), &ged_state.field);
if (fle == Field_load_error_ok) {
qnav_stack_pop();
- file_name = sdd_cpysdd(file_name, temp_name);
- ged_state.filename = sddc(file_name);
+ osoputoso(&file_name, temp_name);
+ ged_state.filename = osoc(file_name);
mbuf_reusable_ensure_size(&ged_state.mbuf_r,
ged_state.field.height,
ged_state.field.width);
@@ -3048,43 +3047,43 @@
undo_history_pop(&ged_state.undo_hist, &ged_state.field,
&ged_state.tick_num);
qmsg_printf_push("Error Loading File", "%s:\n%s",
- sddc(temp_name),
+ osoc(temp_name),
field_load_error_string(fle));
}
}
- sdd_free(temp_name);
+ osofree(temp_name);
} break;
case Save_as_form_id: {
- sdd* temp_name = NULL;
+ oso* temp_name = NULL;
if (qform_get_text_line(qf, Save_as_name_id, &temp_name) &&
- sdd_len(temp_name) > 0) {
+ osolen(temp_name) > 0) {
qnav_stack_pop();
bool saved_ok = try_save_with_msg(&ged_state.field, temp_name);
if (saved_ok) {
- file_name = sdd_cpysdd(file_name, temp_name);
- ged_state.filename = sddc(file_name);
+ osoputoso(&file_name, temp_name);
+ ged_state.filename = osoc(file_name);
}
}
- sdd_free(temp_name);
+ osofree(temp_name);
} break;
case Set_tempo_form_id: {
- sdd* tmpstr = NULL;
+ oso* tmpstr = NULL;
if (qform_get_text_line(qf, Tempo_text_line_id, &tmpstr) &&
- sdd_len(tmpstr) > 0) {
- int newbpm = atoi(sddc(tmpstr));
+ osolen(tmpstr) > 0) {
+ int newbpm = atoi(osoc(tmpstr));
if (newbpm > 0) {
ged_state.bpm = (Usz)newbpm;
qnav_stack_pop();
}
}
- sdd_free(tmpstr);
+ osofree(tmpstr);
} break;
case Set_grid_dims_form_id: {
- sdd* tmpstr = NULL;
+ oso* tmpstr = NULL;
if (qform_get_text_line(qf, Tempo_text_line_id, &tmpstr) &&
- sdd_len(tmpstr) > 0) {
+ osolen(tmpstr) > 0) {
int newheight, newwidth;
- if (sscanf(sddc(tmpstr), "%dx%d", &newwidth, &newheight) == 2 &&
+ if (sscanf(osoc(tmpstr), "%dx%d", &newwidth, &newheight) == 2 &&
newheight > 0 && newwidth > 0 && newheight < ORCA_Y_MAX &&
newwidth < ORCA_X_MAX) {
if (ged_state.field.height != (Usz)newheight ||
@@ -3102,7 +3101,7 @@
qnav_stack_pop();
}
}
- sdd_free(tmpstr);
+ osofree(tmpstr);
} break;
}
} break;
@@ -3170,7 +3169,7 @@
case CTRL_PLUS('q'):
goto quit;
case CTRL_PLUS('o'):
- push_open_form(sddc(file_name));
+ push_open_form(osoc(file_name));
break;
case KEY_UP:
case CTRL_PLUS('k'):
@@ -3394,7 +3393,7 @@
break;
case CTRL_PLUS('s'):
// TODO duplicated with menu item code
- if (sdd_len(file_name) > 0) {
+ if (osolen(file_name) > 0) {
try_save_with_msg(&ged_state.field, file_name);
} else {
push_save_as_form("");
@@ -3428,7 +3427,7 @@
printf("\033[?2004h\n"); // Tell terminal to not use bracketed paste
endwin();
ged_deinit(&ged_state);
- sdd_free(file_name);
+ osofree(file_name);
midi_mode_deinit(&midi_mode);
#ifdef FEAT_PORTMIDI
if (portmidi_is_initialized)