aboutsummaryrefslogtreecommitdiff
path: root/advent-of-code/2023/lib/str.c
diff options
context:
space:
mode:
Diffstat (limited to 'advent-of-code/2023/lib/str.c')
-rw-r--r--advent-of-code/2023/lib/str.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/advent-of-code/2023/lib/str.c b/advent-of-code/2023/lib/str.c
new file mode 100644
index 0000000..511e45b
--- /dev/null
+++ b/advent-of-code/2023/lib/str.c
@@ -0,0 +1,143 @@
+// Copyright (C) 2023 Mistivia <i@mistivia.com>
+// Licensed under GPLv3. See LICENSE for details.
+
+#include "str.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vec.h"
+
+void *str_split(const char *str, char delim) {
+ void* ret = new_vec();
+
+ if (str == NULL) return NULL;
+ if (*str == '\n') {
+ return ret;
+ }
+ int count = 0;
+ const char *begin = str;
+ for (const char *p = str; *p != '\0'; p++) {
+ if (*p != delim && !(delim == '\0' && isspace(*p))) {
+ continue;
+ }
+ int size = p - begin;
+ if (size > 0) count++;
+ }
+ count++;
+
+ begin = str;
+ int i = 0;
+ bool finished = false;
+ for (const char *p = str; !finished; p++) {
+ if (*p == '\0') finished = true;
+ if (*p != delim && *p != '\0' && !(delim == '\0' && isspace(*p))) {
+ continue;
+ }
+ int size = p - begin;
+ if (size == 0) {
+ begin = p + 1;
+ continue;
+ }
+ char *buf = malloc(sizeof(char) * (size + 1));
+ buf[size] = '\0';
+ memcpy(buf, begin, size * sizeof(char));
+ begin = p + 1;
+ vec_push_back(ret, buf);
+ }
+ return ret;
+}
+
+char *str_strip(const char *str) {
+ if (str == NULL) return NULL;
+ int len = strlen(str);
+ const char *begin = str;
+ const char *end = str + len - 1;
+ while (isspace(*begin) && begin < end) {
+ begin++;
+ }
+ while (isspace(*end) && end >= begin) {
+ end--;
+ }
+ len = end - begin + 1;
+ char *buf = malloc(sizeof(char) * (len) + 1);
+ buf[len] = '\0';
+ memcpy(buf, begin, len);
+ return buf;
+}
+
+typedef struct {
+ size_t size;
+ size_t cap;
+ char *buf;
+} str_builder_t;
+
+// string stream
+void* new_ss() {
+ str_builder_t *self = malloc(sizeof(str_builder_t));
+ *self = (str_builder_t){.size = 0, .cap = 16};
+ self->buf = malloc(sizeof(char) * 17);
+ return self;
+}
+
+static void ss_reserve(str_builder_t *self, int extra) {
+ if (self->size + extra <= self->cap) {
+ return;
+ }
+ int new_cap = (self->size + extra) * 2;
+ self->buf = realloc(self->buf, new_cap + 1);
+ memset(self->buf + self->cap, 0, new_cap - self->cap + 1);
+ self->cap = new_cap;
+}
+
+void ss_add(void *self_, char *format, ...) {
+ str_builder_t *self = self_;
+ va_list va1;
+ va_list va2;
+ va_start(va1, format);
+ va_copy(va2, va1);
+ int size = vsnprintf(NULL, 0, format, va1);
+ ss_reserve(self, size);
+ vsnprintf(self->buf + self->size, self->cap - self->size + 1, format, va2);
+ self->size += size;
+}
+
+void ss_addc(void *self_, char c) {
+ str_builder_t *self = self_;
+ ss_reserve(self, 1);
+ self->buf[self->size] = c;
+ self->size++;
+}
+
+char *ss_cstr(void *self_) {
+ str_builder_t *self = self_;
+ return self->buf;
+}
+
+size_t ss_size(void *self_) {
+ str_builder_t *self = self_;
+ return self->size;
+}
+
+char *fgetline(FILE *fp) {
+ void *ss = new_ss();
+ while (true) {
+ int c = fgetc(fp);
+ if (c == EOF && ss_size(ss) == 0) return NULL;
+ if (c != EOF) ss_addc(ss, c);
+ if (c == EOF || c == '\n') return ss_cstr(ss);
+ }
+ return NULL;
+}
+
+int fpeek(FILE *fp) {
+ int c = fgetc(fp);
+ if (c == EOF) return c;
+ ungetc(c, fp);
+ return c;
+}