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