2 * Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
42 #include "directive.h"
49 DECLARRAY(incdir, static UNUSED);
50 DEFARRAY(incdir, static);
52 static struct incdirarray quotepath, bracketpath;
54 ////////////////////////////////////////////////////////////
59 incdir_create(const char *name, bool issystem)
63 id = domalloc(sizeof(*id));
65 id->issystem = issystem;
71 incdir_destroy(struct incdir *id)
73 dofree(id, sizeof(*id));
79 incdirarray_init("epath);
80 incdirarray_init(&bracketpath);
83 DESTROYALL_ARRAY(incdir, );
88 incdirarray_destroyall("epath);
89 incdirarray_cleanup("epath);
90 incdirarray_destroyall(&bracketpath);
91 incdirarray_cleanup(&bracketpath);
94 ////////////////////////////////////////////////////////////
98 files_addquotepath(const char *dir, bool issystem)
102 id = incdir_create(dir, issystem);
103 incdirarray_add("epath, id, NULL);
107 files_addbracketpath(const char *dir, bool issystem)
111 id = incdir_create(dir, issystem);
112 incdirarray_add(&bracketpath, id, NULL);
115 ////////////////////////////////////////////////////////////
119 * Find the end of the logical line. End of line characters that are
120 * commented out do not count.
124 findeol(const char *buf, size_t start, size_t limit)
128 bool inquote = false;
131 for (i=start; i<limit; i++) {
133 if (i+1 < limit && buf[i] == '*' && buf[i+1] == '/') {
137 } else if (!inquote && i+1 < limit &&
138 buf[i] == '/' && buf[i+1] == '*') {
141 } else if (i+1 < limit &&
142 buf[i] == '\\' && buf[i+1] != '\n') {
144 } else if (!inquote && (buf[i] == '"' || buf[i] == '\'')) {
147 } else if (inquote && buf[i] == quote) {
149 } else if (buf[i] == '\n') {
158 countnls(const char *buf, size_t start, size_t limit)
163 for (i=start; i<limit; i++) {
164 if (buf[i] == '\n') {
173 file_read(const struct placefile *pf, int fd, const char *name, bool toplevel)
175 struct place linestartplace, nextlinestartplace, ptmp;
176 size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp;
181 place_setfilestart(&linestartplace, pf);
182 nextlinestartplace = linestartplace;
188 buf = domalloc(bufmax);
191 if (lineend >= bufend) {
192 /* do not have a whole line in the buffer; read more */
193 assert(bufend >= linestart);
194 if (linestart > 0 && bufend > linestart) {
195 /* slide to beginning of buffer */
196 memmove(buf, buf+linestart, bufend-linestart);
198 lineend -= linestart;
201 if (bufend >= bufmax) {
202 /* need bigger buffer */
203 buf = dorealloc(buf, bufmax, bufmax*2);
208 /* don't read again, in case it's a socket */
211 result = read(fd, buf+bufend, bufmax - bufend);
216 complain(NULL, "%s: %s",
217 name, strerror(errno));
219 } else if (result == 0 && bufend == linestart) {
223 } else if (result == 0) {
224 /* eof in middle of line */
226 ptmp = linestartplace;
227 ptmp.column += bufend - linestart;
228 complain(&ptmp, "No newline at end of file");
232 assert(bufend < bufmax);
236 bufend += (size_t)result;
237 lineend = findeol(buf, linestart, bufend);
239 /* loop in case we still don't have a whole line */
244 assert(buf[lineend] == '\n');
246 nextlinestart = lineend+1;
247 nextlinestartplace.line++;
249 /* check for CR/NL */
250 if (lineend > 0 && buf[lineend-1] == '\r') {
251 buf[lineend-1] = '\0';
255 /* check for continuation line */
256 if (lineend > 0 && buf[lineend-1]=='\\') {
258 tmp = nextlinestart - lineend;
259 if (bufend > nextlinestart) {
260 memmove(buf+lineend, buf+nextlinestart,
261 bufend - nextlinestart);
264 nextlinestart -= tmp;
265 lineend = findeol(buf, linestart, bufend);
266 /* might not have a whole line, so loop */
270 /* line now goes from linestart to lineend */
271 assert(buf[lineend] == '\0');
273 /* count how many commented-out newlines we swallowed */
274 nextlinestartplace.line += countnls(buf, linestart, lineend);
276 /* if the line isn't empty, process it */
277 if (lineend > linestart) {
278 directive_gotline(&linestartplace,
279 buf+linestart, lineend-linestart);
282 linestart = nextlinestart;
283 lineend = findeol(buf, linestart, bufend);
284 linestartplace = nextlinestartplace;
288 directive_goteof(&linestartplace);
293 ////////////////////////////////////////////////////////////
298 mkfilename(struct place *place, const char *dir, const char *file)
300 size_t dlen, flen, rlen;
302 bool needslash = false;
305 dir = place_getparsedir(place);
310 if (dlen > 0 && dir[dlen-1] != '/') {
314 rlen = dlen + (needslash ? 1 : 0) + flen;
315 ret = domalloc(rlen + 1);
326 file_tryopen(const char *file)
330 /* XXX check for non-regular files */
332 fd = open(file, O_RDONLY);
334 if (errno != ENOENT && errno != ENOTDIR) {
335 complain(NULL, "%s: %s", file, strerror(errno));
345 file_search(struct place *place, struct incdirarray *path, const char *name)
349 const struct placefile *pf;
353 assert(place != NULL);
355 if (name[0] == '/') {
356 fd = file_tryopen(name);
358 pf = place_addfile(place, name, true);
359 file_read(pf, fd, name, false);
364 num = incdirarray_num(path);
365 for (i=0; i<num; i++) {
366 id = incdirarray_get(path, i);
367 file = mkfilename(place, id->name, name);
368 fd = file_tryopen(file);
370 pf = place_addfile(place, file, id->issystem);
371 file_read(pf, fd, file, false);
379 complain(place, "Include file %s not found", name);
384 file_readquote(struct place *place, const char *name)
386 file_search(place, "epath, name);
390 file_readbracket(struct place *place, const char *name)
392 file_search(place, &bracketpath, name);
396 file_readabsolute(struct place *place, const char *name)
398 const struct placefile *pf;
401 assert(place != NULL);
405 pf = place_addfile(place, "<standard-input>", false);
407 fd = file_tryopen(name);
409 complain(NULL, "%s: %s", name, strerror(errno));
412 pf = place_addfile(place, name, false);
415 file_read(pf, fd, name, true);