-
Notifications
You must be signed in to change notification settings - Fork 0
/
editor.c
121 lines (89 loc) · 2.56 KB
/
editor.c
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
#include "editor.h"
#include "util.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
void editor_insert(struct editor *ed, char *data, size_t len, size_t at) {
if (!ed->writable)
die(1, "editor_delete", "buffer is opened as read-only");
if (at > ed->len)
die(1, "editor_insert", "insert out of bounds: %lu", at);
size_t new_len = ed->len + len;
bool buf_too_small = new_len > ed->cap;
// Allocate new buffer if old buffer too small, else use old buffer
char *buf = buf_too_small ? malloc(new_len) : ed->data;
memmove(buf, ed->data, at);
memmove(buf + at + len, ed->data + at, ed->len - at);
memcpy(buf + at, data, len);
if (buf_too_small)
free(ed->data);
ed->data = buf;
ed->len = new_len;
ed->cap = buf_too_small ? new_len : ed->cap;
}
void editor_delete(struct editor *ed, size_t len, size_t at) {
if (!ed->writable)
die(1, "editor_delete", "buffer is opened as read-only");
if (at + len > ed->len)
die(1, "editor_delete", "delete out of bounds: %lu -> %lu", at, at + len);
memmove(ed->data + at, ed->data + at + len, ed->len - at - len);
ed->len -= len;
}
void editor_flush(struct editor *ed) {
if (!ed->writable)
die(1, "editor_flush", "buffer is opened as read-only");
// Goto start of file and write data
if (lseek(ed->file, 0, SEEK_SET) == -1)
die_errno("editor_flush");
ssize_t nwrite = write(ed->file, ed->data, ed->len);
if (nwrite == -1)
die_errno("editor_flush");
int res;
// Truncate file to new length and sync
res = ftruncate(ed->file, ed->len);
if (res == -1)
die_errno("editor_flush");
res = fsync(ed->file);
if (res == -1)
die_errno("editor_flush");
}
struct editor editor_open(char *path) {
struct editor ed;
// try open file as read/write
ed.file = open(path, O_RDWR);
ed.writable = true;
if (ed.file == -1) {
// try re-opening file as read-only
if (errno == EACCES) {
ed.file = open(path, O_RDONLY);
ed.writable = false;
}
if (ed.file == -1)
die_errno("editor_open");
}
struct stat st;
fstat(ed.file, &st);
size_t file_len = st.st_size;
ed.data = malloc(file_len);
ssize_t nread = read(ed.file, ed.data, file_len);
if (nread == -1)
die_errno("editor_open");
ed.len = file_len;
ed.cap = file_len;
return ed;
}
void editor_close(struct editor *ed) {
ed->len = 0;
ed->cap = 0;
free(ed->data);
if (close(ed->file) == -1)
die_errno("editor_close");
ed->writable = false;
}