1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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;
}
|