Mercurial > ~dholland > hg > tradcpp > index.cgi
annotate files.c @ 207:217727e65236
Added tag release-0.5.3 for changeset 9aa91d3fe3a3
author | David A. Holland |
---|---|
date | Mon, 21 Jan 2019 21:21:50 -0500 |
parents | 3a25180d3a5c |
children |
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 <stdio.h> |
31 #include <stdlib.h> | |
13 | 32 #include <string.h> |
6 | 33 #include <unistd.h> |
34 #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
|
35 #include <errno.h> |
6 | 36 |
183
4c3375895c6e
Don't use <stdbool.h> unless __STDC__ is large enough.
David A. Holland
parents:
175
diff
changeset
|
37 #include "bool.h" |
6 | 38 #include "array.h" |
15 | 39 #include "mode.h" |
8 | 40 #include "place.h" |
6 | 41 #include "files.h" |
15 | 42 #include "directive.h" |
6 | 43 |
44 struct incdir { | |
45 const char *name; | |
46 bool issystem; | |
47 }; | |
48 | |
107 | 49 DECLARRAY(incdir, static UNUSED); |
47
2e25e55dba6b
Fix inline usage as per the version in dholland-make2.
David A. Holland
parents:
39
diff
changeset
|
50 DEFARRAY(incdir, static); |
6 | 51 |
52 static struct incdirarray quotepath, bracketpath; | |
53 | |
54 //////////////////////////////////////////////////////////// | |
55 // management | |
56 | |
57 static | |
58 struct incdir * | |
59 incdir_create(const char *name, bool issystem) | |
60 { | |
61 struct incdir *id; | |
62 | |
63 id = domalloc(sizeof(*id)); | |
64 id->name = name; | |
65 id->issystem = issystem; | |
66 return id; | |
67 } | |
68 | |
69 static | |
70 void | |
71 incdir_destroy(struct incdir *id) | |
72 { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
73 dofree(id, sizeof(*id)); |
6 | 74 } |
75 | |
76 void | |
77 files_init(void) | |
78 { | |
79 incdirarray_init("epath); | |
80 incdirarray_init(&bracketpath); | |
81 } | |
82 | |
9 | 83 DESTROYALL_ARRAY(incdir, ); |
6 | 84 |
85 void | |
86 files_cleanup(void) | |
87 { | |
88 incdirarray_destroyall("epath); | |
89 incdirarray_cleanup("epath); | |
90 incdirarray_destroyall(&bracketpath); | |
91 incdirarray_cleanup(&bracketpath); | |
92 } | |
93 | |
94 //////////////////////////////////////////////////////////// | |
95 // path setup | |
96 | |
97 void | |
98 files_addquotepath(const char *dir, bool issystem) | |
99 { | |
100 struct incdir *id; | |
101 | |
102 id = incdir_create(dir, issystem); | |
103 incdirarray_add("epath, id, NULL); | |
104 } | |
105 | |
106 void | |
107 files_addbracketpath(const char *dir, bool issystem) | |
108 { | |
109 struct incdir *id; | |
110 | |
111 id = incdir_create(dir, issystem); | |
112 incdirarray_add(&bracketpath, id, NULL); | |
113 } | |
114 | |
115 //////////////////////////////////////////////////////////// | |
116 // parsing | |
117 | |
75 | 118 /* |
119 * Find the end of the logical line. End of line characters that are | |
120 * commented out do not count. | |
121 */ | |
15 | 122 static |
123 size_t | |
75 | 124 findeol(const char *buf, size_t start, size_t limit) |
15 | 125 { |
126 size_t i; | |
75 | 127 int incomment = 0; |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
75
diff
changeset
|
128 bool inquote = false; |
128
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
113
diff
changeset
|
129 char quote = '\0'; |
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 && |
128
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
113
diff
changeset
|
142 buf[i] == '\\' && buf[i+1] != '\n') { |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
75
diff
changeset
|
143 i++; |
128
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
113
diff
changeset
|
144 } else if (!inquote && (buf[i] == '"' || buf[i] == '\'')) { |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
113
diff
changeset
|
145 inquote = true; |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
113
diff
changeset
|
146 quote = buf[i]; |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
113
diff
changeset
|
147 } else if (inquote && buf[i] == quote) { |
1cda505ddc78
Don't expand macros within character constants.
David A. Holland
parents:
113
diff
changeset
|
148 inquote = false; |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
75
diff
changeset
|
149 } else if (buf[i] == '\n') { |
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
75
diff
changeset
|
150 return i; |
75 | 151 } |
152 } | |
153 return limit; | |
154 } | |
155 | |
156 static | |
157 unsigned | |
158 countnls(const char *buf, size_t start, size_t limit) | |
159 { | |
160 size_t i; | |
161 unsigned count = 0; | |
15 | 162 |
163 for (i=start; i<limit; i++) { | |
164 if (buf[i] == '\n') { | |
75 | 165 count++; |
203
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
166 if (count == 0) { |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
167 /* just return the max and error downstream */ |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
168 return count - 1; |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
169 } |
15 | 170 } |
171 } | |
75 | 172 return count; |
15 | 173 } |
174 | |
175 static | |
6 | 176 void |
28 | 177 file_read(const struct placefile *pf, int fd, const char *name, bool toplevel) |
15 | 178 { |
154
a2c2fe8dbea3
Wrap up the current and next line position when invoking directives.
David A. Holland
parents:
143
diff
changeset
|
179 struct lineplace places; |
a2c2fe8dbea3
Wrap up the current and next line position when invoking directives.
David A. Holland
parents:
143
diff
changeset
|
180 struct place ptmp; |
15 | 181 size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp; |
182 ssize_t result; | |
183 bool ateof = false; | |
184 char *buf; | |
185 | |
154
a2c2fe8dbea3
Wrap up the current and next line position when invoking directives.
David A. Holland
parents:
143
diff
changeset
|
186 place_setfilestart(&places.current, pf); |
a2c2fe8dbea3
Wrap up the current and next line position when invoking directives.
David A. Holland
parents:
143
diff
changeset
|
187 places.nextline = places.current; |
15 | 188 |
199
1d2bad7151f9
Add a -debuglog option to send an execution trace to a file.
David A. Holland
parents:
187
diff
changeset
|
189 if (name) { |
1d2bad7151f9
Add a -debuglog option to send an execution trace to a file.
David A. Holland
parents:
187
diff
changeset
|
190 debuglog(&places.current, "Reading file %s", name); |
1d2bad7151f9
Add a -debuglog option to send an execution trace to a file.
David A. Holland
parents:
187
diff
changeset
|
191 } else { |
1d2bad7151f9
Add a -debuglog option to send an execution trace to a file.
David A. Holland
parents:
187
diff
changeset
|
192 debuglog(&places.current, "Reading standard input"); |
1d2bad7151f9
Add a -debuglog option to send an execution trace to a file.
David A. Holland
parents:
187
diff
changeset
|
193 } |
1d2bad7151f9
Add a -debuglog option to send an execution trace to a file.
David A. Holland
parents:
187
diff
changeset
|
194 |
15 | 195 bufmax = 128; |
196 bufend = 0; | |
197 linestart = 0; | |
198 lineend = 0; | |
199 buf = domalloc(bufmax); | |
200 | |
201 while (1) { | |
202 if (lineend >= bufend) { | |
203 /* do not have a whole line in the buffer; read more */ | |
75 | 204 assert(bufend >= linestart); |
15 | 205 if (linestart > 0 && bufend > linestart) { |
206 /* slide to beginning of buffer */ | |
207 memmove(buf, buf+linestart, bufend-linestart); | |
208 bufend -= linestart; | |
209 lineend -= linestart; | |
210 linestart = 0; | |
211 } | |
212 if (bufend >= bufmax) { | |
213 /* need bigger buffer */ | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
214 buf = dorealloc(buf, bufmax, bufmax*2); |
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
215 bufmax = bufmax*2; |
203
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
216 /* just in case someone's screwing around */ |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
217 if (bufmax > 0xffffffff) { |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
218 complain(&places.current, |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
219 "Input line too long"); |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
220 die(); |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
221 } |
15 | 222 } |
223 | |
224 if (ateof) { | |
225 /* don't read again, in case it's a socket */ | |
226 result = 0; | |
227 } else { | |
228 result = read(fd, buf+bufend, bufmax - bufend); | |
229 } | |
230 | |
231 if (result == -1) { | |
232 /* read error */ | |
143 | 233 complain(NULL, "%s: %s", |
234 name, strerror(errno)); | |
15 | 235 complain_fail(); |
236 } else if (result == 0 && bufend == linestart) { | |
237 /* eof */ | |
238 ateof = true; | |
239 break; | |
240 } else if (result == 0) { | |
241 /* eof in middle of line */ | |
242 ateof = true; | |
154
a2c2fe8dbea3
Wrap up the current and next line position when invoking directives.
David A. Holland
parents:
143
diff
changeset
|
243 ptmp = places.current; |
203
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
244 place_addcolumns(&ptmp, bufend - linestart); |
186
9637bf434f8e
Don't report unclosed comments as "no newline at end of file".
David A. Holland
parents:
183
diff
changeset
|
245 if (buf[bufend - 1] == '\n') { |
9637bf434f8e
Don't report unclosed comments as "no newline at end of file".
David A. Holland
parents:
183
diff
changeset
|
246 complain(&ptmp, "Unclosed comment"); |
187 | 247 complain_fail(); |
186
9637bf434f8e
Don't report unclosed comments as "no newline at end of file".
David A. Holland
parents:
183
diff
changeset
|
248 } else { |
9637bf434f8e
Don't report unclosed comments as "no newline at end of file".
David A. Holland
parents:
183
diff
changeset
|
249 complain(&ptmp, |
9637bf434f8e
Don't report unclosed comments as "no newline at end of file".
David A. Holland
parents:
183
diff
changeset
|
250 "No newline at end of file"); |
9637bf434f8e
Don't report unclosed comments as "no newline at end of file".
David A. Holland
parents:
183
diff
changeset
|
251 } |
15 | 252 if (mode.werror) { |
253 complain_fail(); | |
254 } | |
255 assert(bufend < bufmax); | |
256 lineend = bufend++; | |
257 buf[lineend] = '\n'; | |
258 } else { | |
259 bufend += (size_t)result; | |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
75
diff
changeset
|
260 lineend = findeol(buf, linestart, bufend); |
15 | 261 } |
262 /* loop in case we still don't have a whole line */ | |
263 continue; | |
264 } | |
265 | |
266 /* have a line */ | |
267 assert(buf[lineend] == '\n'); | |
268 buf[lineend] = '\0'; | |
269 nextlinestart = lineend+1; | |
203
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
270 place_addlines(&places.nextline, 1); |
15 | 271 |
272 /* check for CR/NL */ | |
273 if (lineend > 0 && buf[lineend-1] == '\r') { | |
274 buf[lineend-1] = '\0'; | |
275 lineend--; | |
276 } | |
277 | |
278 /* check for continuation line */ | |
279 if (lineend > 0 && buf[lineend-1]=='\\') { | |
280 lineend--; | |
281 tmp = nextlinestart - lineend; | |
282 if (bufend > nextlinestart) { | |
283 memmove(buf+lineend, buf+nextlinestart, | |
284 bufend - nextlinestart); | |
285 } | |
286 bufend -= tmp; | |
287 nextlinestart -= tmp; | |
81
27c9aafcaca1
Don't recognize comments within double-quote strings.
David A. Holland
parents:
75
diff
changeset
|
288 lineend = findeol(buf, linestart, bufend); |
15 | 289 /* might not have a whole line, so loop */ |
290 continue; | |
291 } | |
292 | |
293 /* line now goes from linestart to lineend */ | |
294 assert(buf[lineend] == '\0'); | |
75 | 295 |
296 /* count how many commented-out newlines we swallowed */ | |
203
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
297 place_addlines(&places.nextline, |
3a25180d3a5c
Abort on line numbering or column numbering overflow.
David A. Holland
parents:
199
diff
changeset
|
298 countnls(buf, linestart, lineend)); |
75 | 299 |
175 | 300 /* process the line (even if it's empty) */ |
301 directive_gotline(&places, buf+linestart, lineend-linestart); | |
15 | 302 |
303 linestart = nextlinestart; | |
75 | 304 lineend = findeol(buf, linestart, bufend); |
154
a2c2fe8dbea3
Wrap up the current and next line position when invoking directives.
David A. Holland
parents:
143
diff
changeset
|
305 places.current = places.nextline; |
15 | 306 } |
307 | |
28 | 308 if (toplevel) { |
154
a2c2fe8dbea3
Wrap up the current and next line position when invoking directives.
David A. Holland
parents:
143
diff
changeset
|
309 directive_goteof(&places.current); |
28 | 310 } |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
311 dofree(buf, bufmax); |
15 | 312 } |
6 | 313 |
314 //////////////////////////////////////////////////////////// | |
315 // path search | |
316 | |
317 static | |
13 | 318 char * |
112 | 319 mkfilename(struct place *place, const char *dir, const char *file) |
13 | 320 { |
321 size_t dlen, flen, rlen; | |
322 char *ret; | |
323 bool needslash = false; | |
324 | |
112 | 325 if (dir == NULL) { |
326 dir = place_getparsedir(place); | |
327 } | |
328 | |
13 | 329 dlen = strlen(dir); |
330 flen = strlen(file); | |
331 if (dlen > 0 && dir[dlen-1] != '/') { | |
332 needslash = true; | |
333 } | |
334 | |
335 rlen = dlen + (needslash ? 1 : 0) + flen; | |
336 ret = domalloc(rlen + 1); | |
337 strcpy(ret, dir); | |
338 if (needslash) { | |
339 strcat(ret, "/"); | |
340 } | |
341 strcat(ret, file); | |
342 return ret; | |
343 } | |
344 | |
345 static | |
6 | 346 int |
347 file_tryopen(const char *file) | |
348 { | |
349 int fd; | |
350 | |
15 | 351 /* XXX check for non-regular files */ |
352 | |
6 | 353 fd = open(file, O_RDONLY); |
354 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
|
355 if (errno != ENOENT && errno != ENOTDIR) { |
143 | 356 complain(NULL, "%s: %s", file, strerror(errno)); |
113
1e7144176a42
Print a warning if we get an unexpected error trying to open a file.
David A. Holland
parents:
112
diff
changeset
|
357 } |
6 | 358 return -1; |
359 } | |
15 | 360 |
6 | 361 return fd; |
362 } | |
363 | |
364 static | |
365 void | |
366 file_search(struct place *place, struct incdirarray *path, const char *name) | |
367 { | |
368 unsigned i, num; | |
369 struct incdir *id; | |
13 | 370 const struct placefile *pf; |
6 | 371 char *file; |
372 int fd; | |
373 | |
374 assert(place != NULL); | |
375 | |
104 | 376 if (name[0] == '/') { |
377 fd = file_tryopen(name); | |
6 | 378 if (fd >= 0) { |
104 | 379 pf = place_addfile(place, name, true); |
380 file_read(pf, fd, name, false); | |
6 | 381 close(fd); |
382 return; | |
383 } | |
104 | 384 } else { |
385 num = incdirarray_num(path); | |
386 for (i=0; i<num; i++) { | |
387 id = incdirarray_get(path, i); | |
112 | 388 file = mkfilename(place, id->name, name); |
104 | 389 fd = file_tryopen(file); |
390 if (fd >= 0) { | |
391 pf = place_addfile(place, file, id->issystem); | |
392 file_read(pf, fd, file, false); | |
393 dostrfree(file); | |
394 close(fd); | |
395 return; | |
396 } | |
397 dostrfree(file); | |
398 } | |
6 | 399 } |
400 complain(place, "Include file %s not found", name); | |
401 complain_fail(); | |
402 } | |
403 | |
404 void | |
405 file_readquote(struct place *place, const char *name) | |
406 { | |
407 file_search(place, "epath, name); | |
408 } | |
409 | |
410 void | |
411 file_readbracket(struct place *place, const char *name) | |
412 { | |
413 file_search(place, &bracketpath, name); | |
414 } | |
415 | |
416 void | |
417 file_readabsolute(struct place *place, const char *name) | |
418 { | |
13 | 419 const struct placefile *pf; |
6 | 420 int fd; |
421 | |
422 assert(place != NULL); | |
423 | |
24 | 424 if (name == NULL) { |
425 fd = STDIN_FILENO; | |
426 pf = place_addfile(place, "<standard-input>", false); | |
427 } else { | |
428 fd = file_tryopen(name); | |
429 if (fd < 0) { | |
143 | 430 complain(NULL, "%s: %s", name, strerror(errno)); |
24 | 431 die(); |
432 } | |
433 pf = place_addfile(place, name, false); | |
6 | 434 } |
24 | 435 |
28 | 436 file_read(pf, fd, name, true); |
24 | 437 |
438 if (name != NULL) { | |
439 close(fd); | |
440 } | |
6 | 441 } |