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