-
Notifications
You must be signed in to change notification settings - Fork 0
/
io.c
121 lines (83 loc) · 2.69 KB
/
io.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 "io.h"
#include "util.h"
#include <stdio.h>
// FIXME: these all leak. make them use `arena`s
struct path_components path_components(const char *path) {
const char *last_slash = strrchr(path, '/');
if (last_slash == NULL) {
return (struct path_components){.dir = ".", .file = strdup(path)};
}
size_t dir_len = last_slash - path;
const char *file_part = last_slash + 1;
char *dir = nonnull_malloc(dir_len + 1);
strncpy(dir, path, dir_len);
dir[dir_len] = '\0';
return (struct path_components){.dir = dir, .file = strdup(file_part)};
}
char *path_combine(const char *l, const char *r) {
size_t l_len = strlen(l);
size_t r_len = strlen(r);
size_t total = l_len + 1 + r_len + 1;
char *path = nonnull_malloc(sizeof(*path) * total);
char *head = path;
memcpy(head, l, l_len);
head += l_len;
*head++ = '/';
memcpy(head, r, r_len);
head += r_len;
*head++ = '\0';
return path;
}
char *path_replace_ext(const char *path, const char *ext) {
DEBUG_ASSERT(ext[0] != '.', "ext should not start with the `.`");
// NOTE: if given no extension, this will append
// this is useful because it gives the invariant that the returned file is
// always a valid different file e.g
// * `path_replace_ext("foo.c", "o")` -> `foo.o`
// * `path_replace_ext("foo", "o")` -> `foo.o`
const char *dot = strrchr(path, '.');
size_t prefix_len = dot ? dot - path : strlen(path);
size_t ext_len = strlen(ext);
size_t res_sz = prefix_len + 1 + ext_len + 1;
char *buff = nonnull_malloc(sizeof(*buff) * res_sz);
size_t head = 0;
strncpy(&buff[head], path, prefix_len);
head += prefix_len;
buff[head++] = '.';
strcpy(&buff[head], ext);
head += ext_len;
buff[head++] = '\0';
DEBUG_ASSERT(head == res_sz, "str copy of wrong size");
return buff;
}
char *path_add_ext(const char *path, const char *ext) {
DEBUG_ASSERT(ext[0] != '.', "ext should not start with the `.`");
size_t path_len = strlen(path);
size_t ext_len = strlen(ext);
size_t res_sz = path_len + 1 + ext_len + 1;
char *buff = nonnull_malloc(sizeof(*buff) * res_sz);
size_t head = 0;
strncpy(&buff[head], path, path_len);
head += path_len;
buff[head++] = '.';
strcpy(&buff[head], ext);
head += ext_len;
buff[head++] = '\0';
DEBUG_ASSERT(head == res_sz, "str copy of wrong size");
return buff;
}
char *read_file(const char *path) {
FILE *f = fopen(path, "r");
if (!f) {
return NULL;
}
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
invariant_assert(fsize != -1L, "ftell failed");
rewind(f);
char *content = nonnull_malloc((unsigned long)fsize + 1);
fread(content, (unsigned long)fsize, 1, f);
fclose(f);
content[fsize] = '\0';
return content;
}