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("epath); 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("epath); 89 1.1 dholland incdirarray_cleanup("epath); 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("epath, 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, "epath, 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