#include #include #include #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(); }