aboutsummaryrefslogtreecommitdiff
path: root/src/str.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/str.c')
-rw-r--r--src/str.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/str.c b/src/str.c
new file mode 100644
index 0000000..22aebac
--- /dev/null
+++ b/src/str.c
@@ -0,0 +1,131 @@
+#include "str.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char **str_split(char *str, char delim) {
+ char **ret;
+
+ if (str == NULL) return NULL;
+ if (*str == '\n') {
+ ret = malloc(sizeof(char *));
+ *ret = NULL;
+ return ret;
+ }
+ int count = 0;
+ char *begin = str;
+ for (char *p = str; *p != '\0'; p++) {
+ if (*p != delim && !(delim == '\0' && isspace(*p))) {
+ continue;
+ }
+ int size = p - begin;
+ if (size > 0) count++;
+ }
+ count++;
+ ret = malloc((count + 1) * sizeof(char *));
+ memset(ret, 0, (count + 1) * sizeof(char *));
+
+ begin = str;
+ int i = 0;
+ bool finished = false;
+ for (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;
+ ret[i] = buf;
+ i++;
+ }
+ return ret;
+}
+
+void destroy_str_list(char **list) {
+ char **p = list;
+ while (*p != NULL) {
+ free(*p);
+ p++;
+ }
+ free(list);
+}
+
+char *str_strip(char *str) {
+ if (str == NULL) return NULL;
+ int len = strlen(str);
+ char *begin = str;
+ 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;
+}
+
+void init_str_builder(str_builder_t *sb) {
+ *sb = (str_builder_t){.size = 0, .cap = 16};
+ sb->buf = malloc(sizeof(char) * 17);
+}
+
+static void sb_reserve(str_builder_t *sb, int extra) {
+ if (sb->size + extra <= sb->cap) {
+ return;
+ }
+ int new_cap = (sb->size + extra) * 2;
+ sb->buf = realloc(sb->buf, new_cap + 1);
+ memset(sb->buf + sb->cap, 0, new_cap - sb->cap + 1);
+ sb->cap = new_cap;
+}
+
+void str_builder_append(str_builder_t *sb, char *format, ...) {
+ va_list va1;
+ va_list va2;
+ va_start(va1, format);
+ va_copy(va2, va1);
+ int size = vsnprintf(NULL, 0, format, va1);
+ sb_reserve(sb, size);
+ vsnprintf(sb->buf + sb->size, sb->cap - sb->size + 1, format, va2);
+}
+
+void str_builder_append_char(str_builder_t *sb, char c) {
+ sb_reserve(sb, 1);
+ sb->buf[sb->size] = c;
+ sb->size++;
+}
+
+char *fgetline(FILE *fp) {
+ str_builder_t sb;
+ init_str_builder(&sb);
+ while (true) {
+ int c = fgetc(fp);
+ if (c == EOF && sb.size == 0) return NULL;
+ if (c != EOF) str_builder_append_char(&sb, c);
+ if (c == EOF || c == '\n') return sb.buf;
+ }
+ return NULL;
+}
+
+int fpeek(FILE *fp) {
+ int c = fgetc(fp);
+ if (c == EOF) return c;
+ ungetc(c, fp);
+ return c;
+}