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
|
void tags_free(TagsFile *f) {
free(f->file_data);
arr_free(f->tags);
memset(f, 0, sizeof *f);
}
void tags_read(Ted *ted, TagsFile *f) {
change_directory(ted->cwd);
Settings const *settings = &ted->settings;
char const *tags_filename = settings->tags_filename;
FILE *file = fopen(tags_filename, "rb");
tags_free(f);
if (file) {
fseek(file, 0, SEEK_END);
size_t file_size = (size_t)ftell(file);
fseek(file, 0, SEEK_SET);
char *file_data = ted_calloc(ted, file_size + 1, 1);
if (file_data) {
f->file_data = file_data;
fread(file_data, 1, file_size, file);
char *p = file_data;
while (1) {
// each line in the file is of the format:
// tag name\tfile name\taddress
// or
// tag name\tfile name\taddress;" additional information
char *end = p + strcspn(p, "\n");
bool eof = *end == '\0';
char *name = p;
char *name_end = strchr(name, '\t');
if (name_end) {
*name_end = '\0';
char *filename = name_end + 1;
char *filename_end = strchr(filename, '\t');
if (filename_end) {
*filename_end = '\0';
char *address = filename_end + 1;
char *address_end = address;
int backslashes = 0;
while (1) {
bool is_end = false;
switch (*address_end) {
case '\n':
case '\r':
is_end = true;
break;
case '\\':
++backslashes;
break;
case '/':
if (address_end != address && backslashes % 2 == 0)
is_end = true;
break;
}
if (is_end) break;
if (*address_end != '\\') backslashes = 0;
++address_end;
}
*address_end = '\0';
if (address_end - address > 2 && address_end[-2] == ';' && address_end[-1] == '"') {
address_end[-2] = '\0';
}
Tag tag = {.name = name, .file = filename, .address = address};
arr_add(f->tags, tag);
}
}
if (eof) break; // end of file
p = end + 1;
}
}
f->last_modified = time_last_modified(tags_filename);
fclose(file);
} else {
ted_seterr(ted, "tags file does not exist.");
}
}
void tags_read_if_changed(Ted *ted, TagsFile *f) {
Settings const *settings = &ted->settings;
char const *tags_filename = settings->tags_filename;
struct timespec modify_time = time_last_modified(tags_filename);
if (!timespec_eq(modify_time, f->last_modified)) {
tags_read(ted, f);
}
}
|