summaryrefslogtreecommitdiff
path: root/doc.c
diff options
context:
space:
mode:
Diffstat (limited to 'doc.c')
-rw-r--r--doc.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/doc.c b/doc.c
new file mode 100644
index 0000000..3478f8b
--- /dev/null
+++ b/doc.c
@@ -0,0 +1,143 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "doc.h"
+#include "err.h"
+
+/* text */
+
+static struct {
+ char *buf;
+ size_t len, cap;
+} txt;
+
+void txt_init(void) {
+ txt.buf = malloc(1);
+ if (!txt.buf) efatal("txt_init");
+ txt.buf[0] = 0;
+ txt.len = 0;
+ txt.cap = 1;
+}
+
+void txt_fini(void) {
+ free(txt.buf);
+}
+
+void txt_grow(size_t n) {
+ size_t cap = txt.cap;
+ size_t len = txt.len + n;
+ if (cap < len) {
+ while (cap < len) cap <<= 1;
+ char *s = realloc(txt.buf, cap);
+ if (!s) efatal("txt_grow");
+ txt.cap = cap;
+ txt.buf = s;
+ }
+}
+
+/* docs */
+
+struct doc {
+ size_t ofs, len, idx;
+};
+
+#define DOC_MAX 32
+
+static struct doc docv[DOC_MAX] = {
+ {
+
+ .ofs = 0,
+ .len = 0,
+ .idx = 0
+ }
+};
+
+static size_t docn = 0, doci = 0;
+
+void doc_pop(void) {
+ if (docn > 0) {
+ docn--;
+ if (doci > 0) doci--;
+ }
+}
+
+void doc_shift(void) {
+ if (docn > 0) {
+ docn--;
+ memmove(txt.buf, txt.buf + docv[0].len, txt.len - docv[0].len);
+ memmove(&docv[0], &docv[1], docn * sizeof(struct doc));
+ docv[0].ofs = 0;
+ for (int i = 1; i < docn; i++) {
+ docv[i].idx = docv[i - 1].ofs + (docv[i].idx - docv[i].ofs);
+ docv[i].ofs = docv[i - 1].ofs + docv[i - 1].len;
+ }
+ if (docn > 0 && doci >= docn) doci = docn - 1;
+ }
+}
+
+void doc_new(void) {
+ while (docn >= DOC_MAX) {
+ doc_shift();
+ }
+ if (doci < docn) {
+ txt.len = docv[doci].ofs;
+ docn = doci;
+ }
+ memset(&docv[docn], 0, sizeof(struct doc));
+ docv[docn].ofs = txt.len;
+ docv[docn].idx = txt.len;
+ doci = docn++;
+}
+
+void doc_add(const char *buf, size_t n) {
+ txt_grow(n);
+ memcpy(&txt.buf[txt.len], buf, n);
+ txt.len += n;
+ docv[doci].len += n;
+}
+
+void doc_adds(const char *s) {
+ doc_add(s, strlen(s));
+}
+
+void doc_prev(void) {
+ if (doci > 0) doci--;
+}
+
+void doc_next(void) {
+ if (doci < docn) doci++;
+}
+
+void doc_back_line(void) {
+ if (doci >= docn) return;
+ struct doc *d = &docv[doci];
+ size_t i = d->idx;
+ while (i > 0 && txt.buf[d->idx] != '\n') i--;
+ if (i > 0) i--;
+ while (i > 0 && txt.buf[d->idx] != '\n') i--;
+ if (i > 0) i++;
+ d->idx = i;
+}
+
+void doc_print_line(void) {
+ if (doci >= docn) return;
+ struct doc *d = &docv[doci];
+ size_t i = d->idx;
+ size_t n = d->ofs + d->len;
+ while (i < n && txt.buf[d->idx] != '\n') {
+ putchar(txt.buf[i++]);
+ }
+ if (i < n) i++;
+ d->idx = i;
+}
+
+void doc_init(void) {
+ txt_init();
+ doc_new();
+ doc_adds("Type ? for command help.\n");
+}
+
+void doc_fini(void) {
+ txt_fini();
+}