diff options
Diffstat (limited to 'txt.c')
| -rw-r--r-- | txt.c | 122 |
1 files changed, 122 insertions, 0 deletions
@@ -0,0 +1,122 @@ +#include <stdint.h> +#include <stddef.h> + +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include "wrmr.h" +#include "dynarr.h" +#include "txt.h" + +void txt_insert_piece(Txt *b, u32 pi, TxtBufIdx buf, u32 ofs, u32 n) { + DA_FIT(&b->ptbl, b->ptbl.n + 1); + MOVE(&b->ptbl.v[pi+1], &b->ptbl.v[pi], b->ptbl.n - pi); + b->ptbl.v[pi] = (TxtPiece) { buf, ofs, n }; + b->ptbl.n++; +} + +void txt_remove_piece(Txt *b, u32 pi) { + if (pi + 1 < b->ptbl.n) { + MOVE(&b->ptbl.v[pi], &b->ptbl.v[pi+1], b->ptbl.n - (pi + 1)); + } + b->ptbl.n--; +} + +u32 txt_split_piece(Txt *b, u32 pi, u32 i) { + TxtPiece *p = &b->ptbl.v[pi]; + if (i == 0) return pi; + if (i == p->n) return pi + 1; + txt_insert_piece(b, pi + 1, p->buf, p->ofs + i, p->n - i); + b->ptbl.v[pi].n = i; + return pi + 1; +} + +TxtLoc txt_at(Txt *b, u32 cur) { + for (u32 i = 0; i < b->ptbl.n; i++) { + if (cur <= b->ptbl.v[i].n) { + return (TxtLoc) { i, cur }; + } + cur -= b->ptbl.v[i].n; + } + return (TxtLoc) { 0, 0 }; +} + +void txt_buf_append(Txt *b, TxtBufIdx bi, const char *s, u32 n) { + TxtBuf *buf = &b->buf[bi]; + if (buf->n + n > buf->c) { + buf->c = stdc_bit_ceil(buf->n + n); + buf->s = realloc(buf->s, buf->c); + if (!buf->s) FAIL_WITH_MSG("realloc failure"); + } + memcpy(&buf->s[buf->n], s, n); + buf->n += n; +} + +u32 txt_insert(Txt *b, u32 cur, const char *s, u32 n) { + TxtLoc l = txt_at(b, cur); + if (l.p < b->ptbl.n) { + TxtPiece *p = &b->ptbl.v[l.p]; + int mid = p->ofs + l.i < b->buf[p->buf].n; + if (p->buf == TXT_SRC || mid) { + l.p = txt_split_piece(b, l.p, l.i); + txt_insert_piece(b, l.p, TXT_ADD, b->buf[TXT_ADD].n, 0); + } + } else { + txt_insert_piece(b, l.p, TXT_ADD, b->buf[TXT_ADD].n, 0); + } + TxtPiece *p = &b->ptbl.v[l.p]; + txt_buf_append(b, p->buf, s, n); + p->n += n; + b->len += n; + return cur + n; +} + +u32 txt_insert_c(Txt *b, u32 cur, char ch) { + /* TODO: utf-8 char */ + return txt_insert(b, cur, &ch, 1); +} + +u32 txt_delete(Txt *b, u32 cur, u32 n) { + TxtLoc l = txt_at(b, cur); + txt_split_piece(b, l.p, l.i); + TxtPiece *p = &b->ptbl.v[l.p]; + if (n > cur) n = cur; + cur -= n; + b->len -= n; + while (n > p->n) { + n -= p->n; + if (l.p + 1 < b->ptbl.n) txt_remove_piece(b, l.p); + b->ptbl.n--; + if (!l.p) return cur; + l.p--; + p = &b->ptbl.v[l.p]; + } + p->n -= n; + if (p->n == 0) txt_remove_piece(b, l.p); + return cur; +} + +int txt_open(Txt *b, const char *path) { + struct stat sb; + int fd = open(path, O_RDONLY); + if (fd == -1) return -1; + if (fstat(fd, &sb)) { + close(fd); + return -1; + } + void *m = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (m == MAP_FAILED) { + close(fd); + return -1; + } + memset(b, 0, sizeof(TxtBuf)); + b->buf[TXT_SRC].s = m; + b->buf[TXT_SRC].n = sb.st_size; + b->buf[TXT_SRC].c = sb.st_size; + b->len = sb.st_size; + close(fd); + txt_insert_piece(b, 0, TXT_SRC, 0, b->len); + return 0; +} |
