aboutsummaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-02-04 15:23:59 -0500
committerBruce Hill <bruce@bruce-hill.com>2024-02-04 15:23:59 -0500
commit98f0c51119f9d42d733f44cb516b1c2bcd9061af (patch)
tree39ab4fa635f858b76b9a8bbf84701c2788d5f498 /util.c
Initial commit
Diffstat (limited to 'util.c')
-rw-r--r--util.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/util.c b/util.c
new file mode 100644
index 00000000..4ee5ef7a
--- /dev/null
+++ b/util.c
@@ -0,0 +1,84 @@
+#include <ctype.h>
+#include <gc.h>
+#include <gc/cord.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+
+public char *heap_strn(const char *str, size_t len)
+{
+ if (!str) return NULL;
+ if (len == 0) return "";
+ char *heaped = GC_MALLOC_ATOMIC(len + 1);
+ memcpy(heaped, str, len);
+ heaped[len] = '\0';
+ return heaped;
+}
+
+public char *heap_str(const char *str)
+{
+ if (!str) return NULL;
+ return heap_strn(str, strlen(str));
+}
+
+public char *heap_strf(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ char *tmp = NULL;
+ int len = vasprintf(&tmp, fmt, args);
+ if (len < 0) return NULL;
+ va_end(args);
+ char *ret = heap_strn(tmp, (size_t)len);
+ free(tmp);
+ return ret;
+}
+
+// Name mangling algorithm to produce valid identifiers:
+// Escape individual chars as "_x%02X"
+// Things being escaped:
+// - Leading digit
+// - Non alphanumeric/non-underscore characters
+// - "_" when followed by "x" and two uppercase hex digits
+public char *mangle(const char *name)
+{
+ size_t len = 0;
+ for (const char *p = name; *p; p++) {
+ if ((!isalnum(*p) && *p != '_') // Non-identifier character
+ || (p == name && isdigit(*p)) // Leading digit
+ || (p[0] == '_' && p[1] == 'x' && strspn(p+2, "ABCDEF0123456789") >= 2)) { // Looks like hex escape
+ len += strlen("_x00"); // Hex escape
+ } else {
+ len += 1;
+ }
+ }
+ char *mangled = GC_MALLOC_ATOMIC(len + 1);
+ char *dest = mangled;
+ for (const char *src = name; *src; src++) {
+ if ((!isalnum(*src) && *src != '_') // Non-identifier character
+ || (src == name && isdigit(*src)) // Leading digit
+ || (src[0] == '_' && src[1] == 'x' && strspn(src+2, "ABCDEF0123456789") >= 2)) { // Looks like hex escape
+ dest += sprintf(dest, "_x%02X", *src); // Hex escape
+ } else {
+ *(dest++) = *src;
+ }
+ }
+ mangled[len] = '\0';
+ return mangled;
+}
+
+CORD CORD_asprintf(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ CORD c = NULL;
+ CORD_vsprintf(&c, fmt, args);
+ va_end(args);
+ return c;
+}
+
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0