summaryrefslogtreecommitdiff
path: root/scripts/neostr.h
diff options
context:
space:
mode:
authorGeorge Abbott <george@gabbott.dev>2025-01-26 11:38:37 +0000
committerGeorge Abbott <george@gabbott.dev>2025-01-26 11:38:37 +0000
commitf6372e58ad54560919a061d33689c81281aa902c (patch)
tree576113f09e6cb2ceed53af1a3dff298cdce2424d /scripts/neostr.h
parent52c4d3793e09bb95f154880fd1372333f94f66cd (diff)
misc
Diffstat (limited to 'scripts/neostr.h')
-rw-r--r--scripts/neostr.h178
1 files changed, 178 insertions, 0 deletions
diff --git a/scripts/neostr.h b/scripts/neostr.h
new file mode 100644
index 0000000..68991ed
--- /dev/null
+++ b/scripts/neostr.h
@@ -0,0 +1,178 @@
+/* neostr: various functions for manipulating strings.
+ * char* is the main type that is manipulated, and there is no expectation of
+ * Unicode, though I could implement support at some point.
+ */
+
+/* Given a string, replace all instances of orig with with, ensuring that only
+ * one allocation is made.
+ */
+
+#define owned
+#define borrowed
+#define str_discard_const (char*)
+void dbg(const char *fmt, ...);
+
+owned const char *
+neostr_replace_all(const char *haystack, const char *orig, const char *with)
+{
+ int count, to_malloc;
+ size_t len_orig, len_with;
+ char *buf, *index_from, *index_to, *buf_cpos, *haystack_tmp, *ss;
+
+ len_orig = strlen(orig);
+ len_with = strlen(with);
+
+ count = 0;
+ haystack_tmp = str_discard_const haystack;
+ for (;;)
+ {
+ ss = strstr(haystack_tmp, orig);
+ if (!ss)
+ break;
+ count++;
+ haystack_tmp += (ss - haystack_tmp) + len_orig;
+ }
+
+ /* Allocate the new buffer */
+ to_malloc = strlen(haystack)
+ - (count * len_orig)
+ + (count * len_with);
+
+ buf = (char*)malloc(to_malloc);
+ memset(buf, 0, to_malloc);
+
+ /* Copy until the text to substitute is found, then copy the new text into
+ * buf, incrementing the counter in the haystack by len_orig.
+ */
+ index_from = str_discard_const haystack;
+ buf_cpos = buf;
+ while ((index_to = strstr(index_from, orig)) != NULL)
+ {
+ memcpy(buf_cpos, index_from, (index_to - index_from));
+ buf_cpos += (index_to - index_from);
+ memcpy(buf_cpos, with, len_with);
+ buf_cpos += len_with;
+ index_from = index_to + len_orig;
+ }
+
+ /* Finally, copy any remaining non-substituted contents. */
+ memcpy(buf_cpos, index_from, strlen(haystack) - (index_from - haystack));
+ buf[to_malloc] = '\0';
+
+ return buf;
+}
+
+/* In a single allocation, replace all instances of the prefix at the start of
+ * the line with a circumfix, at the start and end of the line.
+ */
+owned char *
+neostr_linewise_replace_prefix_with_circumfix(const char *haystack,
+ const char *prefix,
+ const char *circumfix_start,
+ const char *circumfix_end)
+{
+ int prefix_len = strlen(prefix),
+ circumfix_start_len = strlen(circumfix_start),
+ circumfix_end_len = strlen(circumfix_end);
+
+ /* Count of affected lines */
+ int count = 0;
+ char *haystack_tmp = str_discard_const haystack, *nl;
+ for (;;)
+ {
+ nl = strstr(haystack_tmp, "\n");
+ if (!nl)
+ break;
+ count++;
+ haystack_tmp += (nl - haystack_tmp) + 1;
+ }
+ dbg("count :: %d\n", count);
+
+ int to_malloc = strlen(haystack)
+ - (count * prefix_len)
+ + (count * (circumfix_start_len + circumfix_start_len));
+ dbg("prefix_with_circumfix: to malloc %d bytes\n", to_malloc);
+
+ char *buf = malloc(to_malloc);
+ if (!buf)
+ return NULL;
+
+ /* Copy into the buffer. */
+ /* 1) Copy until the first strstr of '\n'.
+ * 2) If the line begins with prefix:
+ * 2a) Copy circumfix_start.
+ * 2b) Copy from the (strstr + prefix_len) to the next strstr of '\n'.
+ * 2c) Copy circumfix_end.
+ * 2z) Else, just copy the whole line until strstr of '\n'.
+ * 3) Once strstr of '\n' returns NULL, just copy until the end of the string.
+ *
+ * Given it is always linewise, at any given time, line_begin and line_end refer to the line.
+ */
+
+
+ char *line_begin, *line_end;
+ int line_len;
+ char *buf_idx;
+
+ buf_idx = buf;
+ line_begin = str_discard_const haystack;
+ line_end = strstr(haystack, "\n");
+ line_len = line_end - line_begin;
+ dbg("Initialized line: %.*s", line_len, line_begin);
+
+ while (true)
+ {
+ dbg("\n\nBegun loop.\n");
+ dbg("Sizeof haystack: %d; Sizeof line begin offset: %d\n", strlen(haystack), line_begin - haystack);
+ dbg("Sizeof alloc: %d; Sizeof buf: %d\n", to_malloc, buf_idx - buf);
+ dbg("Strncmp of [%.*s] and [%s]\n", prefix_len, line_begin, prefix);
+ if (strncmp(line_begin, prefix, prefix_len) == 0)
+ {
+ dbg(" Circumfix line [%.*s].\n", line_len, line_begin);
+ memcpy(buf_idx, circumfix_start, circumfix_start_len);
+ buf_idx += circumfix_start_len;
+
+ memcpy(buf_idx, line_begin + prefix_len, line_len - prefix_len);
+ buf_idx += (line_len - prefix_len);
+
+ memcpy(buf_idx, circumfix_end, circumfix_end_len);
+ buf_idx += circumfix_end_len;
+ }
+ else
+ {
+ dbg(" Normal line [%.*s].\n", line_len, line_begin);
+ memcpy(buf_idx, line_begin, line_len);
+ buf_idx += line_len;
+ }
+
+ dbg("Buf is [%.*s]\n", buf_idx - buf, buf);
+ /* Append the newline. */
+ *buf_idx = '\n';
+ buf_idx++;
+
+ /* Go to next line. */
+ while (true)
+ {
+ line_begin = line_end + 1;
+ line_end = strstr(line_begin, "\n");
+ if (!line_end)
+ goto final_line;
+ line_len = line_end - line_begin;
+
+ if (line_len == 0)
+ {
+ dbg("Line length zero.\n");
+ *buf_idx = '\n';
+ buf_idx++;
+ continue;
+ }
+ break;
+ }
+ }
+
+final_line:
+ dbg("final line{{%.*s}}\n", (haystack + strlen(haystack)), line_begin);
+ memcpy(buf_idx, line_begin, (haystack + strlen(haystack)) - line_begin);
+
+ return buf;
+}