summaryrefslogtreecommitdiff
path: root/txt.c
diff options
context:
space:
mode:
Diffstat (limited to 'txt.c')
-rw-r--r--txt.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/txt.c b/txt.c
new file mode 100644
index 0000000..b71bba3
--- /dev/null
+++ b/txt.c
@@ -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;
+}