files.c revision 1.1 1 1.1 dholland /*-
2 1.1 dholland * Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
3 1.1 dholland * All rights reserved.
4 1.1 dholland *
5 1.1 dholland * This code is derived from software contributed to The NetBSD Foundation
6 1.1 dholland * by David A. Holland.
7 1.1 dholland *
8 1.1 dholland * Redistribution and use in source and binary forms, with or without
9 1.1 dholland * modification, are permitted provided that the following conditions
10 1.1 dholland * are met:
11 1.1 dholland * 1. Redistributions of source code must retain the above copyright
12 1.1 dholland * notice, this list of conditions and the following disclaimer.
13 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 dholland * notice, this list of conditions and the following disclaimer in the
15 1.1 dholland * documentation and/or other materials provided with the distribution.
16 1.1 dholland *
17 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 1.1 dholland * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 1.1 dholland * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 1.1 dholland * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 1.1 dholland * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 1.1 dholland * POSSIBILITY OF SUCH DAMAGE.
28 1.1 dholland */
29 1.1 dholland
30 1.1 dholland #include <stdio.h>
31 1.1 dholland #include <stdlib.h>
32 1.1 dholland #include <string.h>
33 1.1 dholland #include <unistd.h>
34 1.1 dholland #include <fcntl.h>
35 1.1 dholland #include <errno.h>
36 1.1 dholland
37 1.1 dholland #include "bool.h"
38 1.1 dholland #include "array.h"
39 1.1 dholland #include "mode.h"
40 1.1 dholland #include "place.h"
41 1.1 dholland #include "files.h"
42 1.1 dholland #include "directive.h"
43 1.1 dholland
44 1.1 dholland struct incdir {
45 1.1 dholland const char *name;
46 1.1 dholland bool issystem;
47 1.1 dholland };
48 1.1 dholland
49 1.1 dholland DECLARRAY(incdir, static UNUSED);
50 1.1 dholland DEFARRAY(incdir, static);
51 1.1 dholland
52 1.1 dholland static struct incdirarray quotepath, bracketpath;
53 1.1 dholland
54 1.1 dholland ////////////////////////////////////////////////////////////
55 1.1 dholland // management
56 1.1 dholland
57 1.1 dholland static
58 1.1 dholland struct incdir *
59 1.1 dholland incdir_create(const char *name, bool issystem)
60 1.1 dholland {
61 1.1 dholland struct incdir *id;
62 1.1 dholland
63 1.1 dholland id = domalloc(sizeof(*id));
64 1.1 dholland id->name = name;
65 1.1 dholland id->issystem = issystem;
66 1.1 dholland return id;
67 1.1 dholland }
68 1.1 dholland
69 1.1 dholland static
70 1.1 dholland void
71 1.1 dholland incdir_destroy(struct incdir *id)
72 1.1 dholland {
73 1.1 dholland dofree(id, sizeof(*id));
74 1.1 dholland }
75 1.1 dholland
76 1.1 dholland void
77 1.1 dholland files_init(void)
78 1.1 dholland {
79 1.1 dholland incdirarray_init("epath);
80 1.1 dholland incdirarray_init(&bracketpath);
81 1.1 dholland }
82 1.1 dholland
83 1.1 dholland DESTROYALL_ARRAY(incdir, );
84 1.1 dholland
85 1.1 dholland void
86 1.1 dholland files_cleanup(void)
87 1.1 dholland {
88 1.1 dholland incdirarray_destroyall("epath);
89 1.1 dholland incdirarray_cleanup("epath);
90 1.1 dholland incdirarray_destroyall(&bracketpath);
91 1.1 dholland incdirarray_cleanup(&bracketpath);
92 1.1 dholland }
93 1.1 dholland
94 1.1 dholland ////////////////////////////////////////////////////////////
95 1.1 dholland // path setup
96 1.1 dholland
97 1.1 dholland void
98 1.1 dholland files_addquotepath(const char *dir, bool issystem)
99 1.1 dholland {
100 1.1 dholland struct incdir *id;
101 1.1 dholland
102 1.1 dholland id = incdir_create(dir, issystem);
103 1.1 dholland incdirarray_add("epath, id, NULL);
104 1.1 dholland }
105 1.1 dholland
106 1.1 dholland void
107 1.1 dholland files_addbracketpath(const char *dir, bool issystem)
108 1.1 dholland {
109 1.1 dholland struct incdir *id;
110 1.1 dholland
111 1.1 dholland id = incdir_create(dir, issystem);
112 1.1 dholland incdirarray_add(&bracketpath, id, NULL);
113 1.1 dholland }
114 1.1 dholland
115 1.1 dholland ////////////////////////////////////////////////////////////
116 1.1 dholland // parsing
117 1.1 dholland
118 1.1 dholland /*
119 1.1 dholland * Find the end of the logical line. End of line characters that are
120 1.1 dholland * commented out do not count.
121 1.1 dholland */
122 1.1 dholland static
123 1.1 dholland size_t
124 1.1 dholland findeol(const char *buf, size_t start, size_t limit)
125 1.1 dholland {
126 1.1 dholland size_t i;
127 1.1 dholland int incomment = 0;
128 1.1 dholland bool inquote = false;
129 1.1 dholland char quote = '\0';
130 1.1 dholland
131 1.1 dholland for (i=start; i<limit; i++) {
132 1.1 dholland if (incomment) {
133 1.1 dholland if (i+1 < limit && buf[i] == '*' && buf[i+1] == '/') {
134 1.1 dholland i++;
135 1.1 dholland incomment = 0;
136 1.1 dholland }
137 1.1 dholland } else if (!inquote && i+1 < limit &&
138 1.1 dholland buf[i] == '/' && buf[i+1] == '*') {
139 1.1 dholland i++;
140 1.1 dholland incomment = 1;
141 1.1 dholland } else if (i+1 < limit &&
142 1.1 dholland buf[i] == '\\' && buf[i+1] != '\n') {
143 1.1 dholland i++;
144 1.1 dholland } else if (!inquote && (buf[i] == '"' || buf[i] == '\'')) {
145 1.1 dholland inquote = true;
146 1.1 dholland quote = buf[i];
147 1.1 dholland } else if (inquote && buf[i] == quote) {
148 1.1 dholland inquote = false;
149 1.1 dholland } else if (buf[i] == '\n') {
150 1.1 dholland return i;
151 1.1 dholland }
152 1.1 dholland }
153 1.1 dholland return limit;
154 1.1 dholland }
155 1.1 dholland
156 1.1 dholland static
157 1.1 dholland unsigned
158 1.1 dholland countnls(const char *buf, size_t start, size_t limit)
159 1.1 dholland {
160 1.1 dholland size_t i;
161 1.1 dholland unsigned count = 0;
162 1.1 dholland
163 1.1 dholland for (i=start; i<limit; i++) {
164 1.1 dholland if (buf[i] == '\n') {
165 1.1 dholland count++;
166 1.1 dholland if (count == 0) {
167 1.1 dholland /* just return the max and error downstream */
168 1.1 dholland return count - 1;
169 1.1 dholland }
170 1.1 dholland }
171 1.1 dholland }
172 1.1 dholland return count;
173 1.1 dholland }
174 1.1 dholland
175 1.1 dholland static
176 1.1 dholland void
177 1.1 dholland file_read(const struct placefile *pf, int fd, const char *name, bool toplevel)
178 1.1 dholland {
179 1.1 dholland struct lineplace places;
180 1.1 dholland struct place ptmp;
181 1.1 dholland size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp;
182 1.1 dholland ssize_t result;
183 1.1 dholland bool ateof = false;
184 1.1 dholland char *buf;
185 1.1 dholland
186 1.1 dholland place_setfilestart(&places.current, pf);
187 1.1 dholland places.nextline = places.current;
188 1.1 dholland
189 1.1 dholland if (name) {
190 1.1 dholland debuglog(&places.current, "Reading file %s", name);
191 1.1 dholland } else {
192 1.1 dholland debuglog(&places.current, "Reading standard input");
193 1.1 dholland }
194 1.1 dholland
195 1.1 dholland bufmax = 128;
196 1.1 dholland bufend = 0;
197 1.1 dholland linestart = 0;
198 1.1 dholland lineend = 0;
199 1.1 dholland buf = domalloc(bufmax);
200 1.1 dholland
201 1.1 dholland while (1) {
202 1.1 dholland if (lineend >= bufend) {
203 1.1 dholland /* do not have a whole line in the buffer; read more */
204 1.1 dholland assert(bufend >= linestart);
205 1.1 dholland if (linestart > 0 && bufend > linestart) {
206 1.1 dholland /* slide to beginning of buffer */
207 1.1 dholland memmove(buf, buf+linestart, bufend-linestart);
208 1.1 dholland bufend -= linestart;
209 1.1 dholland lineend -= linestart;
210 1.1 dholland linestart = 0;
211 1.1 dholland }
212 1.1 dholland if (bufend >= bufmax) {
213 1.1 dholland /* need bigger buffer */
214 1.1 dholland buf = dorealloc(buf, bufmax, bufmax*2);
215 1.1 dholland bufmax = bufmax*2;
216 1.1 dholland /* just in case someone's screwing around */
217 1.1 dholland if (bufmax > 0xffffffff) {
218 1.1 dholland complain(&places.current,
219 1.1 dholland "Input line too long");
220 1.1 dholland die();
221 1.1 dholland }
222 1.1 dholland }
223 1.1 dholland
224 1.1 dholland if (ateof) {
225 1.1 dholland /* don't read again, in case it's a socket */
226 1.1 dholland result = 0;
227 1.1 dholland } else {
228 1.1 dholland result = read(fd, buf+bufend, bufmax - bufend);
229 1.1 dholland }
230 1.1 dholland
231 1.1 dholland if (result == -1) {
232 1.1 dholland /* read error */
233 1.1 dholland complain(NULL, "%s: %s",
234 1.1 dholland name, strerror(errno));
235 1.1 dholland complain_fail();
236 1.1 dholland } else if (result == 0 && bufend == linestart) {
237 1.1 dholland /* eof */
238 1.1 dholland ateof = true;
239 1.1 dholland break;
240 1.1 dholland } else if (result == 0) {
241 1.1 dholland /* eof in middle of line */
242 1.1 dholland ateof = true;
243 1.1 dholland ptmp = places.current;
244 1.1 dholland place_addcolumns(&ptmp, bufend - linestart);
245 1.1 dholland if (buf[bufend - 1] == '\n') {
246 1.1 dholland complain(&ptmp, "Unclosed comment");
247 1.1 dholland complain_fail();
248 1.1 dholland } else {
249 1.1 dholland complain(&ptmp,
250 1.1 dholland "No newline at end of file");
251 1.1 dholland }
252 1.1 dholland if (mode.werror) {
253 1.1 dholland complain_fail();
254 1.1 dholland }
255 1.1 dholland assert(bufend < bufmax);
256 1.1 dholland lineend = bufend++;
257 1.1 dholland buf[lineend] = '\n';
258 1.1 dholland } else {
259 1.1 dholland bufend += (size_t)result;
260 1.1 dholland lineend = findeol(buf, linestart, bufend);
261 1.1 dholland }
262 1.1 dholland /* loop in case we still don't have a whole line */
263 1.1 dholland continue;
264 1.1 dholland }
265 1.1 dholland
266 1.1 dholland /* have a line */
267 1.1 dholland assert(buf[lineend] == '\n');
268 1.1 dholland buf[lineend] = '\0';
269 1.1 dholland nextlinestart = lineend+1;
270 1.1 dholland place_addlines(&places.nextline, 1);
271 1.1 dholland
272 1.1 dholland /* check for CR/NL */
273 1.1 dholland if (lineend > 0 && buf[lineend-1] == '\r') {
274 1.1 dholland buf[lineend-1] = '\0';
275 1.1 dholland lineend--;
276 1.1 dholland }
277 1.1 dholland
278 1.1 dholland /* check for continuation line */
279 1.1 dholland if (lineend > 0 && buf[lineend-1]=='\\') {
280 1.1 dholland lineend--;
281 1.1 dholland tmp = nextlinestart - lineend;
282 1.1 dholland if (bufend > nextlinestart) {
283 1.1 dholland memmove(buf+lineend, buf+nextlinestart,
284 1.1 dholland bufend - nextlinestart);
285 1.1 dholland }
286 1.1 dholland bufend -= tmp;
287 1.1 dholland nextlinestart -= tmp;
288 1.1 dholland lineend = findeol(buf, linestart, bufend);
289 1.1 dholland /* might not have a whole line, so loop */
290 1.1 dholland continue;
291 1.1 dholland }
292 1.1 dholland
293 1.1 dholland /* line now goes from linestart to lineend */
294 1.1 dholland assert(buf[lineend] == '\0');
295 1.1 dholland
296 1.1 dholland /* count how many commented-out newlines we swallowed */
297 1.1 dholland place_addlines(&places.nextline,
298 1.1 dholland countnls(buf, linestart, lineend));
299 1.1 dholland
300 1.1 dholland /* process the line (even if it's empty) */
301 1.1 dholland directive_gotline(&places, buf+linestart, lineend-linestart);
302 1.1 dholland
303 1.1 dholland linestart = nextlinestart;
304 1.1 dholland lineend = findeol(buf, linestart, bufend);
305 1.1 dholland places.current = places.nextline;
306 1.1 dholland }
307 1.1 dholland
308 1.1 dholland if (toplevel) {
309 1.1 dholland directive_goteof(&places.current);
310 1.1 dholland }
311 1.1 dholland dofree(buf, bufmax);
312 1.1 dholland }
313 1.1 dholland
314 1.1 dholland ////////////////////////////////////////////////////////////
315 1.1 dholland // path search
316 1.1 dholland
317 1.1 dholland static
318 1.1 dholland char *
319 1.1 dholland mkfilename(struct place *place, const char *dir, const char *file)
320 1.1 dholland {
321 1.1 dholland size_t dlen, flen, rlen;
322 1.1 dholland char *ret;
323 1.1 dholland bool needslash = false;
324 1.1 dholland
325 1.1 dholland if (dir == NULL) {
326 1.1 dholland dir = place_getparsedir(place);
327 1.1 dholland }
328 1.1 dholland
329 1.1 dholland dlen = strlen(dir);
330 1.1 dholland flen = strlen(file);
331 1.1 dholland if (dlen > 0 && dir[dlen-1] != '/') {
332 1.1 dholland needslash = true;
333 1.1 dholland }
334 1.1 dholland
335 1.1 dholland rlen = dlen + (needslash ? 1 : 0) + flen;
336 1.1 dholland ret = domalloc(rlen + 1);
337 1.1 dholland strcpy(ret, dir);
338 1.1 dholland if (needslash) {
339 1.1 dholland strcat(ret, "/");
340 1.1 dholland }
341 1.1 dholland strcat(ret, file);
342 1.1 dholland return ret;
343 1.1 dholland }
344 1.1 dholland
345 1.1 dholland static
346 1.1 dholland int
347 1.1 dholland file_tryopen(const char *file)
348 1.1 dholland {
349 1.1 dholland int fd;
350 1.1 dholland
351 1.1 dholland /* XXX check for non-regular files */
352 1.1 dholland
353 1.1 dholland fd = open(file, O_RDONLY);
354 1.1 dholland if (fd < 0) {
355 1.1 dholland if (errno != ENOENT && errno != ENOTDIR) {
356 1.1 dholland complain(NULL, "%s: %s", file, strerror(errno));
357 1.1 dholland }
358 1.1 dholland return -1;
359 1.1 dholland }
360 1.1 dholland
361 1.1 dholland return fd;
362 1.1 dholland }
363 1.1 dholland
364 1.1 dholland static
365 1.1 dholland void
366 1.1 dholland file_search(struct place *place, struct incdirarray *path, const char *name)
367 1.1 dholland {
368 1.1 dholland unsigned i, num;
369 1.1 dholland struct incdir *id;
370 1.1 dholland const struct placefile *pf;
371 1.1 dholland char *file;
372 1.1 dholland int fd;
373 1.1 dholland
374 1.1 dholland assert(place != NULL);
375 1.1 dholland
376 1.1 dholland if (name[0] == '/') {
377 1.1 dholland fd = file_tryopen(name);
378 1.1 dholland if (fd >= 0) {
379 1.1 dholland pf = place_addfile(place, name, true);
380 1.1 dholland file_read(pf, fd, name, false);
381 1.1 dholland close(fd);
382 1.1 dholland return;
383 1.1 dholland }
384 1.1 dholland } else {
385 1.1 dholland num = incdirarray_num(path);
386 1.1 dholland for (i=0; i<num; i++) {
387 1.1 dholland id = incdirarray_get(path, i);
388 1.1 dholland file = mkfilename(place, id->name, name);
389 1.1 dholland fd = file_tryopen(file);
390 1.1 dholland if (fd >= 0) {
391 1.1 dholland pf = place_addfile(place, file, id->issystem);
392 1.1 dholland file_read(pf, fd, file, false);
393 1.1 dholland dostrfree(file);
394 1.1 dholland close(fd);
395 1.1 dholland return;
396 1.1 dholland }
397 1.1 dholland dostrfree(file);
398 1.1 dholland }
399 1.1 dholland }
400 1.1 dholland complain(place, "Include file %s not found", name);
401 1.1 dholland complain_fail();
402 1.1 dholland }
403 1.1 dholland
404 1.1 dholland void
405 1.1 dholland file_readquote(struct place *place, const char *name)
406 1.1 dholland {
407 1.1 dholland file_search(place, "epath, name);
408 1.1 dholland }
409 1.1 dholland
410 1.1 dholland void
411 1.1 dholland file_readbracket(struct place *place, const char *name)
412 1.1 dholland {
413 1.1 dholland file_search(place, &bracketpath, name);
414 1.1 dholland }
415 1.1 dholland
416 1.1 dholland void
417 1.1 dholland file_readabsolute(struct place *place, const char *name)
418 1.1 dholland {
419 1.1 dholland const struct placefile *pf;
420 1.1 dholland int fd;
421 1.1 dholland
422 1.1 dholland assert(place != NULL);
423 1.1 dholland
424 1.1 dholland if (name == NULL) {
425 1.1 dholland fd = STDIN_FILENO;
426 1.1 dholland pf = place_addfile(place, "<standard-input>", false);
427 1.1 dholland } else {
428 1.1 dholland fd = file_tryopen(name);
429 1.1 dholland if (fd < 0) {
430 1.1 dholland complain(NULL, "%s: %s", name, strerror(errno));
431 1.1 dholland die();
432 1.1 dholland }
433 1.1 dholland pf = place_addfile(place, name, false);
434 1.1 dholland }
435 1.1 dholland
436 1.1 dholland file_read(pf, fd, name, true);
437 1.1 dholland
438 1.1 dholland if (name != NULL) {
439 1.1 dholland close(fd);
440 1.1 dholland }
441 1.1 dholland }
442