1 1.1 thorpej %{ 2 1.37 joe /* $NetBSD: scan.l,v 1.37 2025/01/07 14:21:11 joe Exp $ */ 3 1.1 thorpej 4 1.1 thorpej /* 5 1.1 thorpej * Copyright (c) 1992, 1993 6 1.1 thorpej * The Regents of the University of California. All rights reserved. 7 1.1 thorpej * 8 1.1 thorpej * This software was developed by the Computer Systems Engineering group 9 1.1 thorpej * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10 1.1 thorpej * contributed to Berkeley. 11 1.1 thorpej * 12 1.1 thorpej * All advertising materials mentioning features or use of this software 13 1.1 thorpej * must display the following acknowledgement: 14 1.1 thorpej * This product includes software developed by the University of 15 1.1 thorpej * California, Lawrence Berkeley Laboratories. 16 1.1 thorpej * 17 1.1 thorpej * Redistribution and use in source and binary forms, with or without 18 1.1 thorpej * modification, are permitted provided that the following conditions 19 1.1 thorpej * are met: 20 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 21 1.1 thorpej * notice, this list of conditions and the following disclaimer. 22 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 23 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 24 1.1 thorpej * documentation and/or other materials provided with the distribution. 25 1.1 thorpej * 3. Neither the name of the University nor the names of its contributors 26 1.1 thorpej * may be used to endorse or promote products derived from this software 27 1.1 thorpej * without specific prior written permission. 28 1.1 thorpej * 29 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 1.1 thorpej * SUCH DAMAGE. 40 1.1 thorpej * 41 1.1 thorpej * from: @(#)scan.l 8.1 (Berkeley) 6/6/93 42 1.1 thorpej */ 43 1.1 thorpej 44 1.19 christos #include <sys/cdefs.h> 45 1.37 joe __RCSID("$NetBSD: scan.l,v 1.37 2025/01/07 14:21:11 joe Exp $"); 46 1.19 christos 47 1.1 thorpej #include <sys/param.h> 48 1.1 thorpej #include <errno.h> 49 1.1 thorpej #include <libgen.h> 50 1.1 thorpej #include <stdio.h> 51 1.1 thorpej #include <stdlib.h> 52 1.1 thorpej #include <string.h> 53 1.1 thorpej #include <unistd.h> 54 1.2 martin #include <stddef.h> 55 1.2 martin #include <ctype.h> 56 1.5 christos #include <util.h> 57 1.5 christos #undef ECHO 58 1.1 thorpej #include "defs.h" 59 1.1 thorpej #include "gram.h" 60 1.1 thorpej 61 1.1 thorpej int yyline; 62 1.1 thorpej const char *yyfile; 63 1.1 thorpej const char *lastfile; 64 1.2 martin char curinclpath[PATH_MAX]; 65 1.28 christos uint64_t ifdefstate; 66 1.28 christos int ifdefshift = -1; 67 1.28 christos 68 1.28 christos /* 69 1.28 christos * The state is represented by 3 bits. 70 1.28 christos */ 71 1.31 christos #define IDS_ENABLED 1ll 72 1.31 christos #define IDS_MATCH 2ll 73 1.31 christos #define IDS_ELIF 4ll 74 1.31 christos #define IDS_ELSE 8ll 75 1.31 christos 76 1.31 christos #define IDS_BITS 0xf 77 1.31 christos #define IDS_SHIFT 4 78 1.31 christos 79 1.31 christos #define IDS_ISMATCH(st) (((st) & IDS_MATCH) != 0) 80 1.31 christos #define IDS_ISENABLED(st) (((st) & IDS_ENABLED) != 0) 81 1.31 christos #define IDS_PARENT_DISABLED \ 82 1.31 christos (ifdefshift > 0 && !IDS_ISENABLED(ifdefstate >> IDS_SHIFT)) 83 1.31 christos #define IDS_MAX_DEPTH 16 /* 64 / 4 */ 84 1.30 christos 85 1.31 christos #ifdef IDS_DEBUG 86 1.30 christos # define IDS_PRINT(s, st, x) \ 87 1.30 christos do { \ 88 1.30 christos for (int i = 0; i < ifdefshift + 1; i++) \ 89 1.30 christos fprintf(stderr, " "); \ 90 1.30 christos printf("%s%s [%d,%d,%d] %#" PRIx64 "\n", x, # s, \ 91 1.30 christos IDS_PARENT_DISABLED, IDS_ISMATCH(st), getcurifdef(), \ 92 1.30 christos ifdefstate); \ 93 1.34 rillig } while (0) 94 1.30 christos #else 95 1.31 christos # define IDS_PRINT(s, st, x) ((void)0) 96 1.30 christos #endif 97 1.30 christos 98 1.31 christos #define IDS_ENTER(s, st) \ 99 1.30 christos IDS_PRINT(s, st, ">") 100 1.31 christos #define IDS_EXIT(s, st) \ 101 1.30 christos IDS_PRINT(s, st, "<") 102 1.30 christos 103 1.1 thorpej /* 104 1.1 thorpej * Data for returning to previous files from include files. 105 1.1 thorpej */ 106 1.1 thorpej struct incl { 107 1.1 thorpej struct incl *in_prev; /* previous includes in effect, if any */ 108 1.1 thorpej YY_BUFFER_STATE in_buf; /* previous lex state */ 109 1.27 christos struct where in_where; 110 1.1 thorpej int in_ateof; /* token to insert at EOF */ 111 1.1 thorpej int in_interesting; /* previous value for "interesting" */ 112 1.28 christos uint64_t in_ifdefstate; /* conditional level */ 113 1.28 christos int in_ifdefshift; /* conditional level */ 114 1.1 thorpej }; 115 1.1 thorpej static struct incl *incl; 116 1.1 thorpej static int endinclude(void); 117 1.2 martin static int getincludepath(void); 118 1.9 cube static int getcurifdef(void); 119 1.1 thorpej 120 1.32 joerg SLIST_HEAD(, prefix) curdirs; /* curdir stack */ 121 1.1 thorpej 122 1.1 thorpej %} 123 1.1 thorpej 124 1.22 christos %option noyywrap nounput noinput 125 1.13 christos 126 1.1 thorpej PATH [A-Za-z_0-9]*[./][-A-Za-z_0-9./]* 127 1.37 joe QCHARS \"(\\.|[^\\"])*\" 128 1.1 thorpej WORD [A-Za-z_][-A-Za-z_0-9]* 129 1.22 christos FILENAME ({PATH}|{QCHARS}) 130 1.8 cube RESTOFLINE [ \t]*(#[^\n]*)?\n 131 1.29 christos WS ^[ \t]* 132 1.1 thorpej 133 1.9 cube %x IGNORED 134 1.9 cube 135 1.1 thorpej %% 136 1.1 thorpej /* Local variables for yylex() */ 137 1.1 thorpej int tok; 138 1.1 thorpej 139 1.1 thorpej and return AND; 140 1.1 thorpej at return AT; 141 1.1 thorpej attach return ATTACH; 142 1.1 thorpej block return BLOCK; 143 1.1 thorpej build return BUILD; 144 1.1 thorpej char return CHAR; 145 1.1 thorpej compile-with return COMPILE_WITH; 146 1.1 thorpej config return CONFIG; 147 1.1 thorpej deffs return DEFFS; 148 1.1 thorpej define return DEFINE; 149 1.1 thorpej defflag return DEFFLAG; 150 1.1 thorpej defopt return DEFOPT; 151 1.1 thorpej defparam return DEFPARAM; 152 1.1 thorpej defpseudo return DEFPSEUDO; 153 1.10 drochner defpseudodev return DEFPSEUDODEV; 154 1.1 thorpej devclass return DEVCLASS; 155 1.1 thorpej device return DEVICE; 156 1.1 thorpej device-major return DEVICE_MAJOR; 157 1.1 thorpej dumps return DUMPS; 158 1.1 thorpej file return XFILE; 159 1.1 thorpej file-system return FILE_SYSTEM; 160 1.1 thorpej flags return FLAGS; 161 1.1 thorpej ident return IDENT; 162 1.14 pooka ioconf return IOCONF; 163 1.16 pooka linkzero return LINKZERO; 164 1.1 thorpej machine return XMACHINE; 165 1.1 thorpej major return MAJOR; 166 1.1 thorpej makeoptions return MAKEOPTIONS; 167 1.35 thorpej mkflagvar return MKFLAGVAR; 168 1.1 thorpej maxpartitions return MAXPARTITIONS; 169 1.1 thorpej maxusers return MAXUSERS; 170 1.1 thorpej minor return MINOR; 171 1.1 thorpej needs-count return NEEDS_COUNT; 172 1.1 thorpej needs-flag return NEEDS_FLAG; 173 1.1 thorpej no return NO; 174 1.26 christos -no return CNO; 175 1.1 thorpej object return XOBJECT; 176 1.4 cube obsolete return OBSOLETE; 177 1.1 thorpej on return ON; 178 1.1 thorpej options return OPTIONS; 179 1.1 thorpej prefix return PREFIX; 180 1.24 uebayasi buildprefix return BUILDPREFIX; 181 1.1 thorpej pseudo-device return PSEUDO_DEVICE; 182 1.15 pooka pseudo-root return PSEUDO_ROOT; 183 1.1 thorpej root return ROOT; 184 1.21 uebayasi select return SELECT; 185 1.16 pooka single return SINGLE; 186 1.1 thorpej source return SOURCE; 187 1.1 thorpej type return TYPE; 188 1.16 pooka vector return VECTOR; 189 1.3 cube version return VERSION; 190 1.1 thorpej with return WITH; 191 1.1 thorpej 192 1.1 thorpej \+= return PLUSEQ; 193 1.6 cube := return COLONEQ; 194 1.1 thorpej 195 1.29 christos <*>{WS}ifdef[ \t]+{WORD}{RESTOFLINE} { 196 1.28 christos ifdefstate <<= IDS_SHIFT; 197 1.28 christos if (++ifdefshift >= IDS_MAX_DEPTH) { 198 1.9 cube yyerror("too many levels of conditional"); 199 1.9 cube } 200 1.30 christos IDS_ENTER(ifdef, 0); 201 1.28 christos if (IDS_PARENT_DISABLED || !getcurifdef()) { 202 1.31 christos ifdefstate &= (uint64_t)~IDS_ENABLED; 203 1.28 christos BEGIN(IGNORED); 204 1.28 christos } else { 205 1.31 christos ifdefstate |= IDS_MATCH|IDS_ENABLED; 206 1.9 cube BEGIN(INITIAL); 207 1.9 cube } 208 1.30 christos IDS_EXIT(ifdef, 0); 209 1.9 cube yyline++; 210 1.9 cube } 211 1.9 cube 212 1.29 christos <*>{WS}ifndef[ \t]+{WORD}{RESTOFLINE} { 213 1.28 christos ifdefstate <<= IDS_SHIFT; 214 1.28 christos if (++ifdefshift >= IDS_MAX_DEPTH) { 215 1.9 cube yyerror("too many levels of conditional"); 216 1.9 cube } 217 1.30 christos IDS_ENTER(ifndef, 0); 218 1.28 christos if (IDS_PARENT_DISABLED || getcurifdef()) { 219 1.31 christos ifdefstate &= (uint64_t)~IDS_ENABLED; 220 1.28 christos BEGIN(IGNORED); 221 1.28 christos } else { 222 1.31 christos ifdefstate |= IDS_MATCH|IDS_ENABLED; 223 1.9 cube BEGIN(INITIAL); 224 1.9 cube } 225 1.30 christos IDS_EXIT(ifndef, 0); 226 1.9 cube yyline++; 227 1.9 cube } 228 1.9 cube 229 1.9 cube 230 1.29 christos <*>{WS}elifdef[ \t]+{WORD}{RESTOFLINE} { 231 1.28 christos int st = ifdefstate & IDS_BITS; 232 1.30 christos IDS_ENTER(elifdef, st); 233 1.28 christos if (ifdefshift == -1 || (st & IDS_ELSE) != 0) { 234 1.9 cube yyerror("mismatched elifdef"); 235 1.9 cube } 236 1.28 christos if (IDS_PARENT_DISABLED || IDS_ISMATCH(st) || !getcurifdef()) { 237 1.31 christos ifdefstate &= (uint64_t)~IDS_ENABLED; 238 1.9 cube BEGIN(IGNORED); 239 1.9 cube } else { 240 1.31 christos ifdefstate |= IDS_MATCH|IDS_ENABLED; 241 1.9 cube BEGIN(INITIAL); 242 1.9 cube } 243 1.28 christos ifdefstate |= IDS_ELIF; 244 1.30 christos IDS_EXIT(elifdef, st); 245 1.9 cube yyline++; 246 1.9 cube } 247 1.9 cube 248 1.29 christos <*>{WS}elifndef[ \t]+{WORD}{RESTOFLINE} { 249 1.28 christos int st = ifdefstate & IDS_BITS; 250 1.30 christos IDS_ENTER(elifndef, st); 251 1.28 christos if (ifdefshift == -1 || (st & IDS_ELSE) != 0) { 252 1.9 cube yyerror("mismatched elifndef"); 253 1.9 cube } 254 1.28 christos if (IDS_PARENT_DISABLED || IDS_ISMATCH(st) || getcurifdef()) { 255 1.31 christos ifdefstate &= (uint64_t)~IDS_ENABLED; 256 1.9 cube BEGIN(IGNORED); 257 1.9 cube } else { 258 1.31 christos ifdefstate |= IDS_MATCH|IDS_ENABLED; 259 1.9 cube BEGIN(INITIAL); 260 1.9 cube } 261 1.28 christos ifdefstate |= IDS_ELIF; 262 1.30 christos IDS_EXIT(elifndef, st); 263 1.9 cube yyline++; 264 1.9 cube } 265 1.9 cube 266 1.29 christos <*>{WS}else{RESTOFLINE} { 267 1.28 christos int st = ifdefstate & IDS_BITS; 268 1.30 christos IDS_ENTER(else, st); 269 1.28 christos if (ifdefshift == -1 || (st & IDS_ELSE) != 0) { 270 1.9 cube yyerror("mismatched else"); 271 1.9 cube } 272 1.28 christos if (IDS_PARENT_DISABLED || IDS_ISMATCH(st)) { 273 1.31 christos ifdefstate &= (uint64_t)~IDS_ENABLED; 274 1.28 christos BEGIN(IGNORED); 275 1.28 christos } else { 276 1.31 christos ifdefstate |= IDS_MATCH|IDS_ENABLED; 277 1.9 cube BEGIN(INITIAL); 278 1.9 cube } 279 1.28 christos ifdefstate |= IDS_ELSE; 280 1.30 christos IDS_ENTER(else, st); 281 1.9 cube yyline++; 282 1.9 cube } 283 1.9 cube 284 1.29 christos <*>{WS}endif{RESTOFLINE} { 285 1.30 christos IDS_ENTER(endif, 0); 286 1.28 christos if (ifdefshift == -1) { 287 1.9 cube yyerror("mismatched endif"); 288 1.9 cube } 289 1.9 cube if (!IDS_PARENT_DISABLED) { 290 1.9 cube BEGIN(INITIAL); 291 1.9 cube } 292 1.30 christos IDS_EXIT(endif, 0); 293 1.28 christos ifdefshift--; 294 1.28 christos ifdefstate >>= IDS_SHIFT; 295 1.9 cube yyline++; 296 1.9 cube } 297 1.9 cube 298 1.9 cube <IGNORED>\n { 299 1.9 cube yyline++; 300 1.9 cube } 301 1.9 cube 302 1.9 cube <IGNORED>. /* ignore */ 303 1.9 cube 304 1.8 cube include[ \t]+{FILENAME}{RESTOFLINE} { 305 1.8 cube yyline++; 306 1.2 martin if (getincludepath()) { 307 1.2 martin include(curinclpath, 0, 0, 1); 308 1.2 martin } else { 309 1.2 martin yyerror("bad include path-name"); 310 1.2 martin } 311 1.2 martin } 312 1.2 martin 313 1.8 cube cinclude[ \t]+{FILENAME}{RESTOFLINE} { 314 1.8 cube yyline++; 315 1.2 martin if (getincludepath()) { 316 1.2 martin include(curinclpath, 0, 1, 1); 317 1.2 martin } else { 318 1.2 martin yyerror("bad cinclude path-name"); 319 1.2 martin } 320 1.2 martin } 321 1.2 martin 322 1.8 cube package[ \t]+{FILENAME}{RESTOFLINE} { 323 1.8 cube yyline++; 324 1.2 martin if (!oktopackage) { 325 1.2 martin yyerror("package not allowed here"); 326 1.2 martin } else if (getincludepath()) { 327 1.2 martin package(curinclpath); 328 1.2 martin } else { 329 1.2 martin yyerror("bad package path-name"); 330 1.2 martin } 331 1.2 martin } 332 1.2 martin 333 1.1 thorpej {PATH} { 334 1.1 thorpej yylval.str = intern(yytext); 335 1.1 thorpej return PATHNAME; 336 1.1 thorpej } 337 1.1 thorpej 338 1.1 thorpej {WORD} { 339 1.1 thorpej yylval.str = intern(yytext); 340 1.1 thorpej return WORD; 341 1.1 thorpej } 342 1.1 thorpej 343 1.1 thorpej \"\" { 344 1.1 thorpej yylval.str = intern(""); 345 1.5 christos return EMPTYSTRING; 346 1.1 thorpej } 347 1.2 martin 348 1.22 christos {QCHARS} { 349 1.22 christos size_t l = strlen(yytext); 350 1.22 christos if (l > 1 && yytext[l - 1] == '"') 351 1.22 christos yytext[l - 1] = '\0'; 352 1.22 christos 353 1.1 thorpej yylval.str = intern(yytext + 1); 354 1.1 thorpej return QSTRING; 355 1.1 thorpej } 356 1.1 thorpej 0[0-7]* { 357 1.1 thorpej yylval.num.fmt = 8; 358 1.1 thorpej yylval.num.val = strtoll(yytext, NULL, 8); 359 1.1 thorpej return NUMBER; 360 1.1 thorpej } 361 1.1 thorpej 0[xX][0-9a-fA-F]+ { 362 1.1 thorpej yylval.num.fmt = 16; 363 1.20 christos yylval.num.val = (long long)strtoull(yytext + 2, NULL, 16); 364 1.1 thorpej return NUMBER; 365 1.1 thorpej } 366 1.1 thorpej [1-9][0-9]* { 367 1.1 thorpej yylval.num.fmt = 10; 368 1.1 thorpej yylval.num.val = strtoll(yytext, NULL, 10); 369 1.1 thorpej return NUMBER; 370 1.1 thorpej } 371 1.1 thorpej \n[ \t] { 372 1.1 thorpej /* 373 1.1 thorpej * Note: newline followed by whitespace is always a 374 1.1 thorpej * continuation of the previous line, so do NOT 375 1.1 thorpej * return a token in this case. 376 1.1 thorpej */ 377 1.1 thorpej yyline++; 378 1.1 thorpej } 379 1.1 thorpej \n { 380 1.1 thorpej yyline++; 381 1.1 thorpej return '\n'; 382 1.1 thorpej } 383 1.1 thorpej \00 { 384 1.1 thorpej /* Detect NUL characters in the config file and 385 1.1 thorpej * error out. 386 1.1 thorpej */ 387 1.23 christos cfgerror("NUL character detected at line %i", yyline); 388 1.1 thorpej } 389 1.1 thorpej #.* { /* ignored (comment) */; } 390 1.1 thorpej [ \t]+ { /* ignored (white space) */; } 391 1.1 thorpej . { return yytext[0]; } 392 1.9 cube <*><<EOF>> { 393 1.28 christos if (ifdefshift > (incl == NULL ? -1 : incl->in_ifdefshift)) { 394 1.9 cube yyerror("reached EOF while looking for endif"); 395 1.9 cube } 396 1.1 thorpej if (incl == NULL) 397 1.1 thorpej return YY_NULL; 398 1.1 thorpej tok = endinclude(); 399 1.1 thorpej if (tok) 400 1.1 thorpej return tok; 401 1.1 thorpej /* otherwise continue scanning */ 402 1.1 thorpej } 403 1.1 thorpej 404 1.1 thorpej %% 405 1.1 thorpej 406 1.1 thorpej int interesting = 1; 407 1.1 thorpej 408 1.1 thorpej static int 409 1.1 thorpej curdir_push(const char *fname) 410 1.1 thorpej { 411 1.1 thorpej struct prefix *pf; 412 1.1 thorpej char *p, *d, *f; 413 1.1 thorpej 414 1.1 thorpej /* Set up the initial "current directory" for include directives. */ 415 1.1 thorpej d = dirname(f = estrdup(fname)); 416 1.1 thorpej if (*d == '/') 417 1.1 thorpej p = estrdup(d); 418 1.1 thorpej else { 419 1.1 thorpej char *cwd, buf[PATH_MAX]; 420 1.1 thorpej 421 1.11 dholland if ((cwd = getcwd(buf, sizeof(buf))) == NULL) { 422 1.11 dholland free(f); 423 1.1 thorpej return (-1); 424 1.11 dholland } 425 1.22 christos easprintf(&p, "%s/%s", cwd, d); 426 1.1 thorpej } 427 1.1 thorpej free(f); 428 1.1 thorpej pf = ecalloc(1, sizeof(*pf)); 429 1.1 thorpej pf->pf_prefix = p; 430 1.1 thorpej SLIST_INSERT_HEAD(&curdirs, pf, pf_next); 431 1.1 thorpej 432 1.1 thorpej return (0); 433 1.1 thorpej } 434 1.1 thorpej 435 1.1 thorpej static void 436 1.1 thorpej curdir_pop(void) 437 1.1 thorpej { 438 1.1 thorpej struct prefix *pf; 439 1.1 thorpej 440 1.1 thorpej pf = SLIST_FIRST(&curdirs); 441 1.1 thorpej SLIST_REMOVE_HEAD(&curdirs, pf_next); 442 1.1 thorpej if (SLIST_EMPTY(&curdirs)) 443 1.1 thorpej panic("curdirs is empty"); 444 1.1 thorpej /* LINTED cast away const (pf_prefix is malloc'd for curdirs) */ 445 1.12 lukem free((void *)__UNCONST(pf->pf_prefix)); 446 1.1 thorpej free(pf); 447 1.1 thorpej } 448 1.1 thorpej 449 1.1 thorpej /* 450 1.1 thorpej * Open the "main" file (conffile). 451 1.1 thorpej */ 452 1.1 thorpej int 453 1.1 thorpej firstfile(const char *fname) 454 1.1 thorpej { 455 1.1 thorpej 456 1.1 thorpej #if defined(__NetBSD__) 457 1.1 thorpej if ((yyin = fopen(fname, "rf")) == NULL) 458 1.1 thorpej #else 459 1.1 thorpej if ((yyin = fopen(fname, "r")) == NULL) 460 1.1 thorpej #endif 461 1.1 thorpej return (-1); 462 1.1 thorpej 463 1.1 thorpej if (curdir_push(fname) == -1) 464 1.1 thorpej return (-1); 465 1.1 thorpej 466 1.1 thorpej yyfile = conffile = fname; 467 1.1 thorpej yyline = 1; 468 1.1 thorpej return (0); 469 1.1 thorpej } 470 1.1 thorpej 471 1.1 thorpej /* 472 1.1 thorpej * Add a "package" to the configuration. This is essentially 473 1.1 thorpej * syntactic sugar around the sequence: 474 1.1 thorpej * 475 1.1 thorpej * prefix ../some/directory 476 1.1 thorpej * include "files.package" 477 1.1 thorpej * prefix 478 1.1 thorpej */ 479 1.1 thorpej void 480 1.1 thorpej package(const char *fname) 481 1.1 thorpej { 482 1.1 thorpej char *fname1 = estrdup(fname); 483 1.1 thorpej char *fname2 = estrdup(fname); 484 1.1 thorpej char *dir = dirname(fname1); 485 1.1 thorpej char *file = basename(fname2); 486 1.1 thorpej 487 1.1 thorpej /* 488 1.1 thorpej * Push the prefix on to the prefix stack and process the include 489 1.1 thorpej * file. When we reach the end of the include file, inserting 490 1.1 thorpej * the PREFIX token into the input stream will pop the prefix off 491 1.1 thorpej * of the prefix stack. 492 1.1 thorpej */ 493 1.1 thorpej prefix_push(dir); 494 1.1 thorpej (void) include(file, PREFIX, 0, 1); 495 1.1 thorpej 496 1.1 thorpej free(fname1); 497 1.1 thorpej free(fname2); 498 1.1 thorpej } 499 1.1 thorpej 500 1.25 uebayasi int includedepth; 501 1.25 uebayasi 502 1.1 thorpej /* 503 1.1 thorpej * Open the named file for inclusion at the current point. Returns 0 on 504 1.1 thorpej * success (file opened and previous state pushed), nonzero on failure 505 1.1 thorpej * (fopen failed, complaint made). The `ateof' parameter controls the 506 1.1 thorpej * token to be inserted at the end of the include file (i.e. ENDFILE). 507 1.1 thorpej * If ateof == 0 then nothing is inserted. 508 1.1 thorpej */ 509 1.1 thorpej int 510 1.1 thorpej include(const char *fname, int ateof, int conditional, int direct) 511 1.1 thorpej { 512 1.1 thorpej FILE *fp; 513 1.1 thorpej struct incl *in; 514 1.1 thorpej char *s; 515 1.1 thorpej static int havedirs; 516 1.1 thorpej extern int vflag; 517 1.1 thorpej 518 1.1 thorpej if (havedirs == 0) { 519 1.1 thorpej havedirs = 1; 520 1.1 thorpej setupdirs(); 521 1.1 thorpej } 522 1.1 thorpej 523 1.1 thorpej if (fname[0] == '/') 524 1.1 thorpej s = estrdup(fname); 525 1.1 thorpej else if (fname[0] == '.' && fname[1] == '/') { 526 1.1 thorpej struct prefix *pf = SLIST_FIRST(&curdirs); 527 1.22 christos easprintf(&s, "%s/%s", pf->pf_prefix, fname + 2); 528 1.1 thorpej } else 529 1.1 thorpej s = sourcepath(fname); 530 1.1 thorpej if ((fp = fopen(s, "r")) == NULL) { 531 1.1 thorpej if (conditional == 0) 532 1.23 christos cfgerror("cannot open %s for reading: %s", s, 533 1.1 thorpej strerror(errno)); 534 1.1 thorpej else if (vflag) 535 1.7 christos cfgwarn("cannot open conditional include file %s: %s", 536 1.1 thorpej s, strerror(errno)); 537 1.1 thorpej free(s); 538 1.1 thorpej return (-1); 539 1.1 thorpej } 540 1.1 thorpej if (curdir_push(s) == -1) { 541 1.23 christos cfgerror("cannot record current working directory for %s", s); 542 1.1 thorpej fclose(fp); 543 1.1 thorpej free(s); 544 1.1 thorpej return (-1); 545 1.1 thorpej } 546 1.1 thorpej in = ecalloc(1, sizeof *in); 547 1.1 thorpej in->in_prev = incl; 548 1.1 thorpej in->in_buf = YY_CURRENT_BUFFER; 549 1.27 christos in->in_where.w_srcfile = yyfile; 550 1.27 christos in->in_where.w_srcline = (u_short)yyline; 551 1.1 thorpej in->in_ateof = ateof; 552 1.1 thorpej in->in_interesting = interesting; 553 1.9 cube in->in_ifdefstate = ifdefstate; 554 1.28 christos in->in_ifdefshift = ifdefshift; 555 1.1 thorpej interesting = direct & interesting; 556 1.1 thorpej if (interesting) 557 1.1 thorpej logconfig_include(fp, fname); 558 1.1 thorpej incl = in; 559 1.33 uwe CFGDBG(1, "include `%s'", fname); 560 1.1 thorpej yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); 561 1.1 thorpej yyfile = intern(s); 562 1.1 thorpej yyline = 1; 563 1.1 thorpej free(s); 564 1.25 uebayasi includedepth++; 565 1.1 thorpej return (0); 566 1.1 thorpej } 567 1.1 thorpej 568 1.1 thorpej /* 569 1.2 martin * Extract the pathname from a include/cinclude/package into curinclpath 570 1.2 martin */ 571 1.2 martin static int 572 1.17 matt getincludepath(void) 573 1.2 martin { 574 1.2 martin const char *p = yytext; 575 1.8 cube ptrdiff_t len; 576 1.8 cube const char *e; 577 1.2 martin 578 1.36 uwe while (*p && isascii((unsigned char)*p) && !isspace((unsigned char)*p)) 579 1.2 martin p++; 580 1.36 uwe while (*p && isascii((unsigned char)*p) && isspace((unsigned char)*p)) 581 1.2 martin p++; 582 1.2 martin if (!*p) 583 1.2 martin return 0; 584 1.2 martin if (*p == '"') { 585 1.8 cube p++; 586 1.8 cube e = strchr(p, '"'); 587 1.2 martin if (!e) return 0; 588 1.2 martin } else { 589 1.8 cube e = p; 590 1.36 uwe while (*e && isascii((unsigned char)*e) 591 1.36 uwe && !isspace((unsigned char)*e)) 592 1.8 cube e++; 593 1.2 martin } 594 1.2 martin 595 1.8 cube len = e-p; 596 1.12 lukem if (len > (ptrdiff_t)sizeof(curinclpath)-1) 597 1.8 cube len = sizeof(curinclpath)-1; 598 1.8 cube strncpy(curinclpath, p, sizeof(curinclpath)); 599 1.8 cube curinclpath[len] = '\0'; 600 1.8 cube 601 1.2 martin return 1; 602 1.2 martin } 603 1.2 martin 604 1.2 martin /* 605 1.1 thorpej * Terminate the most recent inclusion. 606 1.1 thorpej */ 607 1.1 thorpej static int 608 1.1 thorpej endinclude(void) 609 1.1 thorpej { 610 1.1 thorpej struct incl *in; 611 1.1 thorpej int ateof; 612 1.1 thorpej 613 1.1 thorpej curdir_pop(); 614 1.1 thorpej if ((in = incl) == NULL) 615 1.1 thorpej panic("endinclude"); 616 1.1 thorpej incl = in->in_prev; 617 1.1 thorpej lastfile = yyfile; 618 1.1 thorpej yy_delete_buffer(YY_CURRENT_BUFFER); 619 1.1 thorpej (void)fclose(yyin); 620 1.1 thorpej yy_switch_to_buffer(in->in_buf); 621 1.27 christos yyfile = in->in_where.w_srcfile; 622 1.27 christos yyline = in->in_where.w_srcline; 623 1.1 thorpej ateof = in->in_ateof; 624 1.1 thorpej interesting = in->in_interesting; 625 1.28 christos ifdefstate = in->in_ifdefstate; 626 1.28 christos ifdefshift = in->in_ifdefshift; 627 1.1 thorpej free(in); 628 1.1 thorpej 629 1.25 uebayasi includedepth--; 630 1.25 uebayasi 631 1.1 thorpej return (ateof); 632 1.1 thorpej } 633 1.1 thorpej 634 1.1 thorpej /* 635 1.1 thorpej * Return the current line number. If yacc has looked ahead and caused 636 1.1 thorpej * us to consume a newline, we have to subtract one. yychar is yacc's 637 1.1 thorpej * token lookahead, so we can tell. 638 1.1 thorpej */ 639 1.19 christos u_short 640 1.1 thorpej currentline(void) 641 1.1 thorpej { 642 1.1 thorpej extern int yychar; 643 1.1 thorpej 644 1.19 christos return (u_short)(yyline - (yychar == '\n')); 645 1.1 thorpej } 646 1.9 cube 647 1.9 cube static int 648 1.9 cube getcurifdef(void) 649 1.9 cube { 650 1.9 cube char *p = yytext, *q; 651 1.9 cube 652 1.36 uwe while (*p && isascii((unsigned char)*p) && !isspace((unsigned char)*p)) 653 1.9 cube p++; 654 1.36 uwe while (*p && isascii((unsigned char)*p) && isspace((unsigned char)*p)) 655 1.9 cube p++; 656 1.9 cube q = p; 657 1.36 uwe while (*q && isascii((unsigned char)*q) && !isspace((unsigned char)*q)) 658 1.9 cube q++; 659 1.9 cube *q = '\0'; 660 1.9 cube 661 1.9 cube return ht_lookup(attrtab, intern(p)) != NULL; 662 1.9 cube } 663