Mercurial > ~dholland > hg > tradcpp > index.cgi
annotate files.c @ 40:291fefe664f2
Oops, fix previous.
author | David A. Holland |
---|---|
date | Sat, 30 Mar 2013 21:48:57 -0400 |
parents | 337110e7240a |
children | 2e25e55dba6b |
rev | line source |
---|---|
30 | 1 /*- |
2 * Copyright (c) 2010 The NetBSD Foundation, Inc. | |
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> | |
36 #include <err.h> | |
37 | |
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 | |
49 DECLARRAY(incdir); | |
50 DEFARRAY(incdir, ); | |
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 | |
15 | 118 static |
119 size_t | |
120 findnl(const char *buf, size_t start, size_t limit) | |
121 { | |
122 size_t i; | |
123 | |
124 for (i=start; i<limit; i++) { | |
125 if (buf[i] == '\n') { | |
126 return i; | |
127 } | |
128 } | |
129 return limit; | |
130 } | |
131 | |
132 static | |
6 | 133 void |
28 | 134 file_read(const struct placefile *pf, int fd, const char *name, bool toplevel) |
15 | 135 { |
136 struct place linestartplace, nextlinestartplace, ptmp; | |
137 size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp; | |
138 ssize_t result; | |
139 bool ateof = false; | |
140 char *buf; | |
141 | |
142 place_setfilestart(&linestartplace, pf); | |
143 nextlinestartplace = linestartplace; | |
144 | |
145 bufmax = 128; | |
146 bufend = 0; | |
147 linestart = 0; | |
148 lineend = 0; | |
149 buf = domalloc(bufmax); | |
150 | |
151 while (1) { | |
152 if (lineend >= bufend) { | |
153 /* do not have a whole line in the buffer; read more */ | |
154 if (linestart > 0 && bufend > linestart) { | |
155 /* slide to beginning of buffer */ | |
156 memmove(buf, buf+linestart, bufend-linestart); | |
157 bufend -= linestart; | |
158 lineend -= linestart; | |
159 linestart = 0; | |
160 } | |
161 if (bufend >= bufmax) { | |
162 /* need bigger buffer */ | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
163 buf = dorealloc(buf, bufmax, bufmax*2); |
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
164 bufmax = bufmax*2; |
15 | 165 } |
166 | |
167 if (ateof) { | |
168 /* don't read again, in case it's a socket */ | |
169 result = 0; | |
170 } else { | |
171 result = read(fd, buf+bufend, bufmax - bufend); | |
172 } | |
173 | |
174 if (result == -1) { | |
175 /* read error */ | |
176 warn("%s", name); | |
177 complain_fail(); | |
178 } else if (result == 0 && bufend == linestart) { | |
179 /* eof */ | |
180 ateof = true; | |
181 break; | |
182 } else if (result == 0) { | |
183 /* eof in middle of line */ | |
184 ateof = true; | |
185 ptmp = linestartplace; | |
186 ptmp.column += bufend - linestart; | |
187 complain(&ptmp, "No newline at end of file"); | |
188 if (mode.werror) { | |
189 complain_fail(); | |
190 } | |
191 assert(bufend < bufmax); | |
192 lineend = bufend++; | |
193 buf[lineend] = '\n'; | |
194 } else { | |
195 tmp = bufend; | |
196 bufend += (size_t)result; | |
197 lineend = findnl(buf, tmp, bufend); | |
198 } | |
199 /* loop in case we still don't have a whole line */ | |
200 continue; | |
201 } | |
202 | |
203 /* have a line */ | |
204 assert(buf[lineend] == '\n'); | |
205 buf[lineend] = '\0'; | |
206 nextlinestart = lineend+1; | |
207 nextlinestartplace.line++; | |
208 | |
209 /* check for CR/NL */ | |
210 if (lineend > 0 && buf[lineend-1] == '\r') { | |
211 buf[lineend-1] = '\0'; | |
212 lineend--; | |
213 } | |
214 | |
215 /* check for continuation line */ | |
216 if (lineend > 0 && buf[lineend-1]=='\\') { | |
217 lineend--; | |
218 tmp = nextlinestart - lineend; | |
219 if (bufend > nextlinestart) { | |
220 memmove(buf+lineend, buf+nextlinestart, | |
221 bufend - nextlinestart); | |
222 } | |
223 bufend -= tmp; | |
224 nextlinestart -= tmp; | |
225 lineend = findnl(buf, lineend, bufend); | |
226 /* might not have a whole line, so loop */ | |
227 continue; | |
228 } | |
229 | |
230 /* line now goes from linestart to lineend */ | |
231 assert(buf[lineend] == '\0'); | |
232 if (lineend > linestart) { | |
233 directive_gotline(&linestartplace, | |
234 buf+linestart, lineend-linestart); | |
235 } | |
236 | |
237 linestart = nextlinestart; | |
238 lineend = findnl(buf, linestart, bufend); | |
239 linestartplace = nextlinestartplace; | |
240 } | |
241 | |
28 | 242 if (toplevel) { |
243 directive_goteof(&linestartplace); | |
244 } | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
245 dofree(buf, bufmax); |
15 | 246 } |
6 | 247 |
248 //////////////////////////////////////////////////////////// | |
249 // path search | |
250 | |
251 static | |
13 | 252 char * |
253 mkfilename(const char *dir, const char *file) | |
254 { | |
255 size_t dlen, flen, rlen; | |
256 char *ret; | |
257 bool needslash = false; | |
258 | |
259 dlen = strlen(dir); | |
260 flen = strlen(file); | |
261 if (dlen > 0 && dir[dlen-1] != '/') { | |
262 needslash = true; | |
263 } | |
264 | |
265 rlen = dlen + (needslash ? 1 : 0) + flen; | |
266 ret = domalloc(rlen + 1); | |
267 strcpy(ret, dir); | |
268 if (needslash) { | |
269 strcat(ret, "/"); | |
270 } | |
271 strcat(ret, file); | |
272 return ret; | |
273 } | |
274 | |
275 static | |
6 | 276 int |
277 file_tryopen(const char *file) | |
278 { | |
279 int fd; | |
280 | |
15 | 281 /* XXX check for non-regular files */ |
282 | |
6 | 283 fd = open(file, O_RDONLY); |
284 if (fd < 0) { | |
285 return -1; | |
286 } | |
15 | 287 |
6 | 288 return fd; |
289 } | |
290 | |
291 static | |
292 void | |
293 file_search(struct place *place, struct incdirarray *path, const char *name) | |
294 { | |
295 unsigned i, num; | |
296 struct incdir *id; | |
13 | 297 const struct placefile *pf; |
6 | 298 char *file; |
299 int fd; | |
300 | |
301 assert(place != NULL); | |
302 | |
303 num = incdirarray_num(path); | |
304 for (i=0; i<num; i++) { | |
305 id = incdirarray_get(path, i); | |
13 | 306 file = mkfilename(id->name, name); |
6 | 307 fd = file_tryopen(file); |
308 if (fd >= 0) { | |
13 | 309 pf = place_addfile(place, file, id->issystem); |
28 | 310 file_read(pf, fd, file, false); |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
311 dostrfree(file); |
6 | 312 close(fd); |
313 return; | |
314 } | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
315 dostrfree(file); |
6 | 316 } |
317 complain(place, "Include file %s not found", name); | |
318 complain_fail(); | |
319 } | |
320 | |
321 void | |
322 file_readquote(struct place *place, const char *name) | |
323 { | |
324 file_search(place, "epath, name); | |
325 } | |
326 | |
327 void | |
328 file_readbracket(struct place *place, const char *name) | |
329 { | |
330 file_search(place, &bracketpath, name); | |
331 } | |
332 | |
333 void | |
334 file_readabsolute(struct place *place, const char *name) | |
335 { | |
13 | 336 const struct placefile *pf; |
6 | 337 int fd; |
338 | |
339 assert(place != NULL); | |
340 | |
24 | 341 if (name == NULL) { |
342 fd = STDIN_FILENO; | |
343 pf = place_addfile(place, "<standard-input>", false); | |
344 } else { | |
345 fd = file_tryopen(name); | |
346 if (fd < 0) { | |
347 warn("%s", name); | |
348 die(); | |
349 } | |
350 pf = place_addfile(place, name, false); | |
6 | 351 } |
24 | 352 |
28 | 353 file_read(pf, fd, name, true); |
24 | 354 |
355 if (name != NULL) { | |
356 close(fd); | |
357 } | |
6 | 358 } |