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