diff options
Diffstat (limited to 'doc.c')
-rw-r--r-- | doc.c | 143 |
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(); +} |