6
|
1 #include <stdbool.h>
|
|
2 #include <stdio.h>
|
|
3 #include <stdlib.h>
|
13
|
4 #include <string.h>
|
6
|
5 #include <unistd.h>
|
|
6 #include <fcntl.h>
|
|
7 #include <err.h>
|
|
8
|
|
9 #include "array.h"
|
15
|
10 #include "mode.h"
|
8
|
11 #include "place.h"
|
6
|
12 #include "files.h"
|
15
|
13 #include "directive.h"
|
6
|
14
|
|
15 struct incdir {
|
|
16 const char *name;
|
|
17 bool issystem;
|
|
18 };
|
|
19
|
|
20 DECLARRAY(incdir);
|
|
21 DEFARRAY(incdir, );
|
|
22
|
|
23 static struct incdirarray quotepath, bracketpath;
|
|
24
|
|
25 ////////////////////////////////////////////////////////////
|
|
26 // management
|
|
27
|
|
28 static
|
|
29 struct incdir *
|
|
30 incdir_create(const char *name, bool issystem)
|
|
31 {
|
|
32 struct incdir *id;
|
|
33
|
|
34 id = domalloc(sizeof(*id));
|
|
35 id->name = name;
|
|
36 id->issystem = issystem;
|
|
37 return id;
|
|
38 }
|
|
39
|
|
40 static
|
|
41 void
|
|
42 incdir_destroy(struct incdir *id)
|
|
43 {
|
|
44 free(id);
|
|
45 }
|
|
46
|
|
47 void
|
|
48 files_init(void)
|
|
49 {
|
|
50 incdirarray_init("epath);
|
|
51 incdirarray_init(&bracketpath);
|
|
52 }
|
|
53
|
9
|
54 DESTROYALL_ARRAY(incdir, );
|
6
|
55
|
|
56 void
|
|
57 files_cleanup(void)
|
|
58 {
|
|
59 incdirarray_destroyall("epath);
|
|
60 incdirarray_cleanup("epath);
|
|
61 incdirarray_destroyall(&bracketpath);
|
|
62 incdirarray_cleanup(&bracketpath);
|
|
63 }
|
|
64
|
|
65 ////////////////////////////////////////////////////////////
|
|
66 // path setup
|
|
67
|
|
68 void
|
|
69 files_addquotepath(const char *dir, bool issystem)
|
|
70 {
|
|
71 struct incdir *id;
|
|
72
|
|
73 id = incdir_create(dir, issystem);
|
|
74 incdirarray_add("epath, id, NULL);
|
|
75 }
|
|
76
|
|
77 void
|
|
78 files_addbracketpath(const char *dir, bool issystem)
|
|
79 {
|
|
80 struct incdir *id;
|
|
81
|
|
82 id = incdir_create(dir, issystem);
|
|
83 incdirarray_add(&bracketpath, id, NULL);
|
|
84 }
|
|
85
|
|
86 ////////////////////////////////////////////////////////////
|
|
87 // parsing
|
|
88
|
15
|
89 static
|
|
90 size_t
|
|
91 findnl(const char *buf, size_t start, size_t limit)
|
|
92 {
|
|
93 size_t i;
|
|
94
|
|
95 for (i=start; i<limit; i++) {
|
|
96 if (buf[i] == '\n') {
|
|
97 return i;
|
|
98 }
|
|
99 }
|
|
100 return limit;
|
|
101 }
|
|
102
|
|
103 static
|
6
|
104 void
|
15
|
105 file_read(const struct placefile *pf, int fd, const char *name)
|
|
106 {
|
|
107 struct place linestartplace, nextlinestartplace, ptmp;
|
|
108 size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp;
|
|
109 ssize_t result;
|
|
110 bool ateof = false;
|
|
111 char *buf;
|
|
112
|
|
113 place_setfilestart(&linestartplace, pf);
|
|
114 nextlinestartplace = linestartplace;
|
|
115
|
|
116 bufmax = 128;
|
|
117 bufend = 0;
|
|
118 linestart = 0;
|
|
119 lineend = 0;
|
|
120 buf = domalloc(bufmax);
|
|
121
|
|
122 while (1) {
|
|
123 if (lineend >= bufend) {
|
|
124 /* do not have a whole line in the buffer; read more */
|
|
125 if (linestart > 0 && bufend > linestart) {
|
|
126 /* slide to beginning of buffer */
|
|
127 memmove(buf, buf+linestart, bufend-linestart);
|
|
128 bufend -= linestart;
|
|
129 lineend -= linestart;
|
|
130 linestart = 0;
|
|
131 }
|
|
132 if (bufend >= bufmax) {
|
|
133 /* need bigger buffer */
|
|
134 bufmax *= 2;
|
|
135 buf = dorealloc(buf, bufmax);
|
|
136 }
|
|
137
|
|
138 if (ateof) {
|
|
139 /* don't read again, in case it's a socket */
|
|
140 result = 0;
|
|
141 } else {
|
|
142 result = read(fd, buf+bufend, bufmax - bufend);
|
|
143 }
|
|
144
|
|
145 if (result == -1) {
|
|
146 /* read error */
|
|
147 warn("%s", name);
|
|
148 complain_fail();
|
|
149 } else if (result == 0 && bufend == linestart) {
|
|
150 /* eof */
|
|
151 ateof = true;
|
|
152 break;
|
|
153 } else if (result == 0) {
|
|
154 /* eof in middle of line */
|
|
155 ateof = true;
|
|
156 ptmp = linestartplace;
|
|
157 ptmp.column += bufend - linestart;
|
|
158 complain(&ptmp, "No newline at end of file");
|
|
159 if (mode.werror) {
|
|
160 complain_fail();
|
|
161 }
|
|
162 assert(bufend < bufmax);
|
|
163 lineend = bufend++;
|
|
164 buf[lineend] = '\n';
|
|
165 } else {
|
|
166 tmp = bufend;
|
|
167 bufend += (size_t)result;
|
|
168 lineend = findnl(buf, tmp, bufend);
|
|
169 }
|
|
170 /* loop in case we still don't have a whole line */
|
|
171 continue;
|
|
172 }
|
|
173
|
|
174 /* have a line */
|
|
175 assert(buf[lineend] == '\n');
|
|
176 buf[lineend] = '\0';
|
|
177 nextlinestart = lineend+1;
|
|
178 nextlinestartplace.line++;
|
|
179
|
|
180 /* check for CR/NL */
|
|
181 if (lineend > 0 && buf[lineend-1] == '\r') {
|
|
182 buf[lineend-1] = '\0';
|
|
183 lineend--;
|
|
184 }
|
|
185
|
|
186 /* check for continuation line */
|
|
187 if (lineend > 0 && buf[lineend-1]=='\\') {
|
|
188 lineend--;
|
|
189 tmp = nextlinestart - lineend;
|
|
190 if (bufend > nextlinestart) {
|
|
191 memmove(buf+lineend, buf+nextlinestart,
|
|
192 bufend - nextlinestart);
|
|
193 }
|
|
194 bufend -= tmp;
|
|
195 nextlinestart -= tmp;
|
|
196 lineend = findnl(buf, lineend, bufend);
|
|
197 /* might not have a whole line, so loop */
|
|
198 continue;
|
|
199 }
|
|
200
|
|
201 /* line now goes from linestart to lineend */
|
|
202 assert(buf[lineend] == '\0');
|
|
203 if (lineend > linestart) {
|
|
204 directive_gotline(&linestartplace,
|
|
205 buf+linestart, lineend-linestart);
|
|
206 }
|
|
207
|
|
208 linestart = nextlinestart;
|
|
209 lineend = findnl(buf, linestart, bufend);
|
|
210 linestartplace = nextlinestartplace;
|
|
211 }
|
|
212
|
|
213 directive_goteof(&linestartplace);
|
|
214 free(buf);
|
|
215 }
|
6
|
216
|
|
217 ////////////////////////////////////////////////////////////
|
|
218 // path search
|
|
219
|
|
220 static
|
13
|
221 char *
|
|
222 mkfilename(const char *dir, const char *file)
|
|
223 {
|
|
224 size_t dlen, flen, rlen;
|
|
225 char *ret;
|
|
226 bool needslash = false;
|
|
227
|
|
228 dlen = strlen(dir);
|
|
229 flen = strlen(file);
|
|
230 if (dlen > 0 && dir[dlen-1] != '/') {
|
|
231 needslash = true;
|
|
232 }
|
|
233
|
|
234 rlen = dlen + (needslash ? 1 : 0) + flen;
|
|
235 ret = domalloc(rlen + 1);
|
|
236 strcpy(ret, dir);
|
|
237 if (needslash) {
|
|
238 strcat(ret, "/");
|
|
239 }
|
|
240 strcat(ret, file);
|
|
241 return ret;
|
|
242 }
|
|
243
|
|
244 static
|
6
|
245 int
|
|
246 file_tryopen(const char *file)
|
|
247 {
|
|
248 int fd;
|
|
249
|
15
|
250 /* XXX check for non-regular files */
|
|
251
|
6
|
252 fd = open(file, O_RDONLY);
|
|
253 if (fd < 0) {
|
|
254 return -1;
|
|
255 }
|
15
|
256
|
6
|
257 return fd;
|
|
258 }
|
|
259
|
|
260 static
|
|
261 void
|
|
262 file_search(struct place *place, struct incdirarray *path, const char *name)
|
|
263 {
|
|
264 unsigned i, num;
|
|
265 struct incdir *id;
|
13
|
266 const struct placefile *pf;
|
6
|
267 char *file;
|
|
268 int fd;
|
|
269
|
|
270 assert(place != NULL);
|
|
271
|
|
272 num = incdirarray_num(path);
|
|
273 for (i=0; i<num; i++) {
|
|
274 id = incdirarray_get(path, i);
|
13
|
275 file = mkfilename(id->name, name);
|
6
|
276 fd = file_tryopen(file);
|
|
277 if (fd >= 0) {
|
13
|
278 pf = place_addfile(place, file, id->issystem);
|
15
|
279 file_read(pf, fd, file);
|
13
|
280 free(file);
|
6
|
281 close(fd);
|
|
282 return;
|
|
283 }
|
|
284 free(file);
|
|
285 }
|
|
286 complain(place, "Include file %s not found", name);
|
|
287 complain_fail();
|
|
288 }
|
|
289
|
|
290 void
|
|
291 file_readquote(struct place *place, const char *name)
|
|
292 {
|
|
293 file_search(place, "epath, name);
|
|
294 }
|
|
295
|
|
296 void
|
|
297 file_readbracket(struct place *place, const char *name)
|
|
298 {
|
|
299 file_search(place, &bracketpath, name);
|
|
300 }
|
|
301
|
|
302 void
|
|
303 file_readabsolute(struct place *place, const char *name)
|
|
304 {
|
13
|
305 const struct placefile *pf;
|
6
|
306 int fd;
|
|
307
|
|
308 assert(place != NULL);
|
|
309
|
|
310 fd = file_tryopen(name);
|
|
311 if (fd < 0) {
|
|
312 warn("%s", name);
|
|
313 die();
|
|
314 }
|
13
|
315 pf = place_addfile(place, name, false);
|
15
|
316 file_read(pf, fd, name);
|
6
|
317 close(fd);
|
|
318 }
|