diff options
author | wrmr | 2024-11-02 19:33:08 -0500 |
---|---|---|
committer | wrmr | 2024-11-02 19:33:08 -0500 |
commit | 610808a5902adad751a4acdbcc310803a51fed5d (patch) | |
tree | 76599dc60cccf6a3765f484dfa1b19e1af88efa1 | |
parent | 58214ec5f982c1b97aadce254c958a5f922c9724 (diff) |
very different document data structure
-rw-r--r-- | buf.c | 28 | ||||
-rw-r--r-- | buf.h | 15 | ||||
-rw-r--r-- | design.txt | 5 | ||||
-rw-r--r-- | doc.c | 157 | ||||
-rw-r--r-- | doc.h | 27 | ||||
-rw-r--r-- | main.c | 45 | ||||
-rw-r--r-- | nav.c | 62 | ||||
-rw-r--r-- | nav.h | 19 | ||||
-rw-r--r-- | parse.c | 17 | ||||
-rw-r--r-- | parse.h | 9 |
10 files changed, 189 insertions, 195 deletions
diff --git a/buf.c b/buf.c new file mode 100644 index 0000000..dd93116 --- /dev/null +++ b/buf.c @@ -0,0 +1,28 @@ +#include <stdlib.h> +#include "buf.h" +#include "err.h" + +void buf_init(struct buf *b, size_t n) { + b->buf = calloc(1, n); + if (!b->buf) { + efatal("buf_init"); + } + b->cap = n; + b->sz = 0; +} + +void buf_grow(struct buf *b, size_t n) { + size_t sz = b->sz + n; + size_t c = b->cap; + if (sz > c) { + while (sz > c) c <<= 1; + char *p = realloc(b->buf, c); + if (!p) efatal("buf_grow"); + b->buf = p; + b->cap = c; + } +} + +void buf_free(struct buf *b) { + free(b->buf); +} diff --git a/buf.h b/buf.h new file mode 100644 index 0000000..fdf0c52 --- /dev/null +++ b/buf.h @@ -0,0 +1,15 @@ +#ifndef BUF_H +#define BUF_H + +#include <stddef.h> + +struct buf { + size_t sz, cap; + char *buf; +}; + +void buf_init(struct buf *, size_t); +void buf_grow(struct buf *, size_t); +void buf_free(struct buf *); + +#endif diff --git a/design.txt b/design.txt index 84fa2f0..e884d76 100644 --- a/design.txt +++ b/design.txt @@ -2,3 +2,8 @@ WORM'S LINE BROWSER ===================== Design Considerations + +LINE HEADER ++---------------------+---------+--------+---------+ +| dist to prev header | link nr | length | text... | ++---------------------+---------+--------+---------+ diff --git a/doc.c b/doc.c index 3478f8b..658315c 100644 --- a/doc.c +++ b/doc.c @@ -5,139 +5,48 @@ #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, +void doc_init(struct doc *d) { + buf_init(&d->txt, sizeof(struct doc_line)); + buf_init(&d->lnk, 1); + d->txt.sz = sizeof(struct doc_line); + *(struct doc_line *)d->txt.buf = (struct doc_line) { + .prev = 0, + .link = DOC_LINK_NONE, .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--; + }; + d->latest = 0; } -void doc_next(void) { - if (doci < docn) doci++; +void doc_fini(struct doc *d) { + buf_free(&d->txt); + buf_free(&d->lnk); } -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_new_line(struct doc *d) { + size_t here = d->latest, there = d->txt.sz; + buf_grow(&d->txt, sizeof(struct doc_line)); + *(struct doc_line *)&d->txt.buf[there] = (struct doc_line) { + .prev = there - here, + .link = DOC_LINK_NONE, + .len = 0 + }; + d->txt.sz += sizeof(struct doc_line); + d->latest = there; } -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_add_line(struct doc *d, const char *s) { + doc_add_text(d, s); + doc_new_line(d); } -void doc_init(void) { - txt_init(); - doc_new(); - doc_adds("Type ? for command help.\n"); +void doc_add_text(struct doc *d, const char *s) { + doc_add_textn(d, s, strlen(s)); } -void doc_fini(void) { - txt_fini(); +void doc_add_textn(struct doc *d, const char *s, size_t n) { + buf_grow(&d->txt, n); + memcpy(&d->txt.buf[d->txt.sz], s, n); + struct doc_line *dl = (struct doc_line *)&d->txt.buf[d->latest]; + d->txt.sz += n; + dl->len += n; } diff --git a/doc.h b/doc.h index 3c5dfcc..5e9c18c 100644 --- a/doc.h +++ b/doc.h @@ -1,6 +1,8 @@ #ifndef DOC_H #define DOC_H +#include "buf.h" + enum doc_type { TYPE_UNKNOWN, TYPE_GOPHERDOC, @@ -8,17 +10,24 @@ enum doc_type { TYPE_PLAIN, }; -void doc_new(void); -void doc_prev(void); -void doc_next(void); +#define DOC_LINK_NONE 0xffff + +struct doc_line { + unsigned short prev, link, len; + char txt[]; +}; -void doc_add(const char *, size_t); -void doc_adds(const char *); +struct doc { + struct buf txt, lnk; + size_t latest; +}; -void doc_back_line(void); -void doc_print_line(void); +void doc_init(struct doc *); +void doc_fini(struct doc *); -void doc_init(void); -void doc_fini(void); +void doc_new_line(struct doc *); +void doc_add_line(struct doc *, const char *); +void doc_add_text(struct doc *, const char *); +void doc_add_textn(struct doc *, const char *, size_t); #endif diff --git a/main.c b/main.c index adc488a..64343bc 100644 --- a/main.c +++ b/main.c @@ -7,30 +7,10 @@ #include "doc.h" #include "net.h" #include "err.h" +#include "nav.h" /* pagination */ -size_t pg_lines() { - return 24; -} - -void pg_down(void) { - size_t lines = pg_lines(); - while (lines--) doc_print_line(); -} - -void pg_up(void) { - size_t lines = pg_lines() << 1; - while (lines--) doc_back_line(); - pg_down(); -} - -void pg_redraw(void) { - size_t lines = pg_lines(); - while (lines--) doc_back_line(); - pg_down(); -} - /* navigation */ int nav_to(const char *url) { @@ -56,7 +36,7 @@ struct cmd { /* cmd is mutated when trimming strings * returns whether to quit */ -int cmd_do(char *cmd) { +int cmd_do(char *cmd, struct nav_state *ns) { switch (*cmd) { case 'q': puts("goodbye!"); @@ -74,13 +54,13 @@ int cmd_do(char *cmd) { } break; case 'b': - pg_up(); + nav_pg_up(ns); break; case '\0': - pg_down(); + nav_pg_down(ns); break; case 'r': - pg_redraw(); + nav_redraw(ns); break; case 'g': if (nav_to(cmd + 1)) perr("navigation failure"); @@ -108,23 +88,16 @@ int cmd_get(char *buf, size_t n) { return !!fgets(buf, n, stdin); } -void init(void) { - doc_init(); -} - -void fini(void) { - doc_fini(); -} - int main(void) { + struct nav_state ns; char cmd_buf[1024]; - init(); - atexit(fini); + nav_init(&ns); while (cmd_get(cmd_buf, sizeof cmd_buf)) { cmd_trim(cmd_buf, sizeof cmd_buf); - if (cmd_do(cmd_buf)) { + if (cmd_do(cmd_buf, &ns)) { break; } } + nav_fini(&ns); return 0; } diff --git a/nav.c b/nav.c new file mode 100644 index 0000000..82cf71a --- /dev/null +++ b/nav.c @@ -0,0 +1,62 @@ +#include <string.h> +#include <stdio.h> +#include "nav.h" + +void nav_init(struct nav_state *ns) { + memset(ns, 0, sizeof *ns); + ns->histc = 1; + doc_init(&ns->histv[0]); + doc_add_text(&ns->histv[0], "Type ? for command help."); +} + +void nav_fini(struct nav_state *ns) { + for (size_t i = 0; i < ns->histc; i++) { + doc_fini(&ns->histv[i]); + } +} + +size_t pg_lines(void) { + return 24; +} + +struct doc_line *nav_cur_line(struct nav_state *ns) { + return (struct doc_line *)&ns->histv[ns->cur_doc].txt.buf[ns->cur_ofs[ns->cur_doc]]; +} + +int nav_line_up(struct nav_state *ns) { + if (ns->cur_ofs[ns->cur_doc] > 0) { + ns->cur_ofs[ns->cur_doc] -= nav_cur_line(ns)->prev; + return 1; + } else { + return 0; + } +} + +int nav_line_down(struct nav_state *ns) { + struct doc_line *l = nav_cur_line(ns); + if (ns->cur_ofs[ns->cur_doc] + sizeof(struct doc_line) + l->len < ns->histv[ns->cur_doc].txt.sz) { + ns->cur_ofs[ns->cur_doc] += l->len + sizeof(struct doc_line); + return 1; + } else { + return 0; + } +} + +void nav_pg_up(struct nav_state *ns) { + size_t lines = pg_lines() << 1; + while (lines-- && nav_line_up(ns)); + nav_pg_down(ns); +} + +void nav_pg_down(struct nav_state *ns) { + size_t lines = pg_lines(); + while (lines--) { + struct doc_line *l = nav_cur_line(ns); + fwrite(l->txt, 1, l->len, stdout); + putchar('\n'); + if (!nav_line_down(ns)) break; + } +} + +void nav_redraw(struct nav_state *ns) { +} diff --git a/nav.h b/nav.h new file mode 100644 index 0000000..baefba9 --- /dev/null +++ b/nav.h @@ -0,0 +1,19 @@ +#ifndef NAV_H +#define NAV_H + +#include "doc.h" +#define HIST_MAX 32 + +struct nav_state { + size_t histc, cur_doc; + struct doc histv[HIST_MAX]; + size_t cur_ofs[HIST_MAX]; +}; + +void nav_init(struct nav_state *ns); +void nav_fini(struct nav_state *ns); +void nav_pg_up(struct nav_state *ns); +void nav_pg_down(struct nav_state *ns); +void nav_redraw(struct nav_state *ns); + +#endif diff --git a/parse.c b/parse.c deleted file mode 100644 index 8061257..0000000 --- a/parse.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "parse.h" - -int parse_doc(enum doc_type doct, int (*line_get)(char **, size_t *)) { - char *s; - size_t n; - switch (doct) { - case TYPE_PLAIN: - doc_new(); - while (line_get(&s, &n)) { - doc_add(s, n); - doc_add("\n", 1); - } - return 0; - default: - return -1; - } -} diff --git a/parse.h b/parse.h deleted file mode 100644 index 1267b3c..0000000 --- a/parse.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef PARSE_H -#define PARSE_H - -#include <stddef.h> -#include "doc.h" - -int parse_doc(enum doc_type doct, int (*line_get)(char **, size_t *)); - -#endif |