1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4*7c2fbfb3SApril Chin * Copyright (c) 1986-2008 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6da2e3ebdSchin * Common Public License, Version 1.0 * 7*7c2fbfb3SApril Chin * by AT&T Intellectual Property * 8da2e3ebdSchin * * 9da2e3ebdSchin * A copy of the License is available at * 10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt * 11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12da2e3ebdSchin * * 13da2e3ebdSchin * Information and Software Systems Research * 14da2e3ebdSchin * AT&T Research * 15da2e3ebdSchin * Florham Park NJ * 16da2e3ebdSchin * * 17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> * 18da2e3ebdSchin * * 19da2e3ebdSchin ***********************************************************************/ 20da2e3ebdSchin #pragma prototyped 21da2e3ebdSchin /* 22da2e3ebdSchin * Glenn Fowler 23da2e3ebdSchin * AT&T Research 24da2e3ebdSchin * 25da2e3ebdSchin * include file search support 26da2e3ebdSchin */ 27da2e3ebdSchin 28da2e3ebdSchin #include "pplib.h" 29da2e3ebdSchin 30da2e3ebdSchin #define SEARCH_NEXT (SEARCH_USER<<1)/* search for next (uncover) */ 31da2e3ebdSchin #define SEARCH_SKIP (SEARCH_USER<<2)/* current binding skipped */ 32da2e3ebdSchin #define SEARCH_TEST (SEARCH_USER<<3)/* test for binding */ 33da2e3ebdSchin #define SEARCH_FOUND (SEARCH_USER<<4)/* current binding found */ 34da2e3ebdSchin 35da2e3ebdSchin #define COLUMN_TAB 7 36da2e3ebdSchin #define COLUMN_MAX 72 37da2e3ebdSchin 38da2e3ebdSchin #if ARCHIVE 39da2e3ebdSchin 40da2e3ebdSchin #include <vdb.h> 41da2e3ebdSchin #include <ls.h> 42da2e3ebdSchin 43da2e3ebdSchin #endif 44da2e3ebdSchin 45da2e3ebdSchin /* 46da2e3ebdSchin * multiple include test 47da2e3ebdSchin * fp is a canonicalized ppfile pointer 48da2e3ebdSchin * 49da2e3ebdSchin * test 50da2e3ebdSchin * 51da2e3ebdSchin * INC_CLEAR can be included again 52da2e3ebdSchin * INC_TEST test if include required 53da2e3ebdSchin * <symbol> ifndef guard symbol 54da2e3ebdSchin * 55da2e3ebdSchin * test!=INC_CLEAR returns 1 if file can be included again 56da2e3ebdSchin * 57da2e3ebdSchin * NOTE: 58da2e3ebdSchin * 59da2e3ebdSchin * (1) different hard links to the same file are treated as 60da2e3ebdSchin * different files 61da2e3ebdSchin * 62da2e3ebdSchin * (2) symbolic links in combination with .. may cause two 63da2e3ebdSchin * different files to be treated as the same file: 64da2e3ebdSchin * 65da2e3ebdSchin * "../h/<file>" == "/usr/include/sys/../h/<file>" -> "/usr/include/h/<file>" 66da2e3ebdSchin * "h/<file>" -> "/usr/include/h/<file>" 67da2e3ebdSchin */ 68da2e3ebdSchin 69da2e3ebdSchin int 70da2e3ebdSchin ppmultiple(register struct ppfile* fp, register struct ppsymbol* test) 71da2e3ebdSchin { 72da2e3ebdSchin register struct ppsymbol* status; 73da2e3ebdSchin 74da2e3ebdSchin status = fp->guard; 75da2e3ebdSchin message((-3, "search: %s: status=%s%s test=%s", fp->name, status == INC_CLEAR ? "[CLEAR]" : status == INC_TEST ? "[ONCE]" : status == INC_IGNORE ? "[IGNORE]" : status->name, (pp.mode & HOSTED) ? "[HOSTED]" : "", test == INC_CLEAR ? "[CLEAR]" : test == INC_TEST ? "[TEST]" : test->name)); 76da2e3ebdSchin if (status == INC_IGNORE) 77da2e3ebdSchin { 78da2e3ebdSchin message((-2, "%s: ignored [%s]", fp->name, pp.ignore)); 79da2e3ebdSchin return 0; 80da2e3ebdSchin } 81da2e3ebdSchin if (test == INC_TEST) 82da2e3ebdSchin { 83da2e3ebdSchin if (status != INC_CLEAR) 84da2e3ebdSchin { 85da2e3ebdSchin if (status != INC_TEST && status->macro || !(pp.mode & ALLMULTIPLE) && !(pp.state & STRICT)) 86da2e3ebdSchin { 87da2e3ebdSchin if ((pp.mode & (ALLMULTIPLE|LOADING)) == LOADING) 88da2e3ebdSchin fp->guard = INC_IGNORE; 89*7c2fbfb3SApril Chin if ((pp.state & WARN) && (pp.mode & (HOSTED|MARKHOSTED|RELAX|PEDANTIC)) == PEDANTIC) 90da2e3ebdSchin error(1, "%s: ignored -- already included", fp->name); 91da2e3ebdSchin else 92da2e3ebdSchin message((-3, "%s: ignored -- already included", fp->name)); 93da2e3ebdSchin return 0; 94da2e3ebdSchin } 95da2e3ebdSchin return 1; 96da2e3ebdSchin } 97da2e3ebdSchin if ((pp.mode & (ALLMULTIPLE|LOADING)) == LOADING) 98da2e3ebdSchin test = INC_IGNORE; 99da2e3ebdSchin } 100da2e3ebdSchin fp->guard = test; 101da2e3ebdSchin return 1; 102da2e3ebdSchin } 103da2e3ebdSchin 104da2e3ebdSchin /* 105da2e3ebdSchin * search for file using directories in dp 106da2e3ebdSchin */ 107da2e3ebdSchin 108da2e3ebdSchin static int 109da2e3ebdSchin search(register struct ppfile* fp, register struct ppdirs* dp, int type, int flags) 110da2e3ebdSchin { 111da2e3ebdSchin register char* prefix; 112da2e3ebdSchin register struct ppdirs* up; 113da2e3ebdSchin register struct ppfile* xp; 114da2e3ebdSchin struct ppfile* mp; 115da2e3ebdSchin int fd; 116da2e3ebdSchin int index; 117da2e3ebdSchin int need; 118da2e3ebdSchin int markhosted; 119da2e3ebdSchin char* t; 120da2e3ebdSchin 121da2e3ebdSchin if (!(pp.option & PREFIX)) 122da2e3ebdSchin prefix = 0; 123da2e3ebdSchin else if ((prefix = strrchr(fp->name, '/')) && prefix > fp->name) 124da2e3ebdSchin { 125da2e3ebdSchin *prefix = 0; 126da2e3ebdSchin t = ppsetfile(fp->name)->name; 127da2e3ebdSchin *prefix = '/'; 128da2e3ebdSchin prefix = t; 129da2e3ebdSchin } 130da2e3ebdSchin message((-3, "search: %s %s%s%s%s%s%s type=%s prefix=%s flags=|%s%s%s%s%s%s start=%s=\"%s\" pre=%s lcl=%s vnd=%s std=%s cur=%s", 131da2e3ebdSchin fp->name, 132da2e3ebdSchin (flags & SEARCH_INCLUDE) ? "include" : "exists", 133da2e3ebdSchin (flags & SEARCH_VENDOR) ? " vendor" : "", 134da2e3ebdSchin (flags & SEARCH_HOSTED) ? " hosted" : "", 135da2e3ebdSchin (flags & SEARCH_NEXT) ? " next" : "", 136da2e3ebdSchin (flags & SEARCH_SKIP) ? " skip" : "", 137da2e3ebdSchin (flags & SEARCH_TEST) ? " test" : "", 138da2e3ebdSchin type == T_HEADER ? "<*>" : "\"*\"", prefix, 139da2e3ebdSchin (fp->flags & INC_SELF) ? "SELF|" : "", 140da2e3ebdSchin (fp->flags & INC_EXISTS) ? "EXISTS|" : "", 141da2e3ebdSchin (fp->flags & INC_BOUND(INC_PREFIX)) ? "PREFIX|" : "", 142da2e3ebdSchin (fp->flags & INC_BOUND(INC_LOCAL)) ? "LOCAL|" : "", 143da2e3ebdSchin (fp->flags & INC_BOUND(INC_VENDOR)) ? "VENDOR|" : "", 144da2e3ebdSchin (fp->flags & INC_BOUND(INC_STANDARD)) ? "STANDARD|" : "", 145da2e3ebdSchin dp ? (dp->index == INC_PREFIX ? "pre" : dp->index == INC_LOCAL ? "lcl" : dp->index == INC_VENDOR ? "vnd" : "std") : NiL, 146da2e3ebdSchin dp ? dp->name : NiL, 147da2e3ebdSchin !(fp->flags & INC_MEMBER(INC_PREFIX)) && (xp = fp->bound[INC_PREFIX]) ? xp->name : NiL, 148da2e3ebdSchin !(fp->flags & INC_MEMBER(INC_LOCAL)) && (xp = fp->bound[INC_LOCAL]) ? xp->name : NiL, 149da2e3ebdSchin !(fp->flags & INC_MEMBER(INC_VENDOR)) && (xp = fp->bound[INC_VENDOR]) ? xp->name : NiL, 150da2e3ebdSchin !(fp->flags & INC_MEMBER(INC_STANDARD)) && (xp = fp->bound[INC_STANDARD]) ? xp->name : NiL, 151da2e3ebdSchin error_info.file 152da2e3ebdSchin )); 153da2e3ebdSchin if (flags & SEARCH_HOSTED) 154da2e3ebdSchin need = TYPE_HOSTED; 155da2e3ebdSchin else if (flags & SEARCH_VENDOR) 156da2e3ebdSchin need = TYPE_VENDOR; 157da2e3ebdSchin else 158da2e3ebdSchin need = TYPE_INCLUDE; 159da2e3ebdSchin for (index = -1; dp; dp = dp->next) 160da2e3ebdSchin if (dp->type & need) 161da2e3ebdSchin { 162da2e3ebdSchin message((-3, "search: fp=%s need=%02x index=%d dp=%s type=%02x index=%d", fp->name, need, index, dp->name, dp->type, dp->index)); 163da2e3ebdSchin #if ARCHIVE 164da2e3ebdSchin if (!(dp->type & (TYPE_ARCHIVE|TYPE_DIRECTORY))) 165da2e3ebdSchin { 166da2e3ebdSchin struct stat st; 167da2e3ebdSchin 168da2e3ebdSchin if (stat(dp->name, &st)) 169da2e3ebdSchin { 170da2e3ebdSchin message((-3, "search: omit %s", dp->name)); 171da2e3ebdSchin dp->type = 0; 172da2e3ebdSchin continue; 173da2e3ebdSchin } 174da2e3ebdSchin if (S_ISREG(st.st_mode)) 175da2e3ebdSchin { 176da2e3ebdSchin register char* s; 177da2e3ebdSchin char* e; 178da2e3ebdSchin int delimiter; 179da2e3ebdSchin int variant; 180da2e3ebdSchin unsigned long siz; 181da2e3ebdSchin unsigned long off; 182da2e3ebdSchin struct ppmember* ap; 183da2e3ebdSchin Sfio_t* sp; 184da2e3ebdSchin 185da2e3ebdSchin /* 186da2e3ebdSchin * check for vdb header archive 187da2e3ebdSchin */ 188da2e3ebdSchin 189da2e3ebdSchin if (!(sp = sfopen(NiL, dp->name, "r"))) 190da2e3ebdSchin { 191da2e3ebdSchin error(ERROR_SYSTEM|1, "%s: ignored -- cannot open", dp->name); 192da2e3ebdSchin dp->type = 0; 193da2e3ebdSchin continue; 194da2e3ebdSchin } 195da2e3ebdSchin variant = sfsprintf(pp.tmpbuf, MAXTOKEN, "%c%s%c%s:archive", VDB_DELIMITER, VDB_MAGIC, VDB_DELIMITER, pp.pass); 196da2e3ebdSchin if (!(s = sfgetr(sp, '\n', 1)) || !strneq(s, pp.tmpbuf, variant)) 197da2e3ebdSchin { 198da2e3ebdSchin sfclose(sp); 199da2e3ebdSchin error(1, "%s: ignored -- not a directory or archive", dp->name); 200da2e3ebdSchin dp->type = 0; 201da2e3ebdSchin continue; 202da2e3ebdSchin } 203da2e3ebdSchin 204da2e3ebdSchin /* 205da2e3ebdSchin * parse the options 206da2e3ebdSchin */ 207da2e3ebdSchin 208da2e3ebdSchin dp->type |= TYPE_ARCHIVE; 209da2e3ebdSchin for (s += variant;;) 210da2e3ebdSchin { 211da2e3ebdSchin while (*s == ' ') s++; 212da2e3ebdSchin e = s; 213da2e3ebdSchin for (t = 0; *s && *s != ' '; s++) 214da2e3ebdSchin if (*s == '=') 215da2e3ebdSchin { 216da2e3ebdSchin *s = 0; 217da2e3ebdSchin t = s + 1; 218da2e3ebdSchin } 219da2e3ebdSchin if (*s) 220da2e3ebdSchin *s++ = 0; 221da2e3ebdSchin if (!*e) 222da2e3ebdSchin break; 223da2e3ebdSchin switch ((int)hashref(pp.strtab, e)) 224da2e3ebdSchin { 225da2e3ebdSchin case X_CHECKPOINT: 226da2e3ebdSchin #if CHECKPOINT 227da2e3ebdSchin dp->type |= TYPE_CHECKPOINT; 228da2e3ebdSchin break; 229da2e3ebdSchin #else 230da2e3ebdSchin error(1, "preprocessor not compiled with checkpoint enabled"); 231da2e3ebdSchin goto notvdb; 232da2e3ebdSchin #endif 233da2e3ebdSchin case X_HIDE: 234da2e3ebdSchin 235da2e3ebdSchin if (t) 236da2e3ebdSchin error(1, "%s: %s: archive option value ignored", e); 237da2e3ebdSchin if (e = strrchr(dp->name, '/')) 238da2e3ebdSchin *e = 0; 239da2e3ebdSchin else 240da2e3ebdSchin dp->name = "."; 241da2e3ebdSchin break; 242da2e3ebdSchin case X_MAP: 243da2e3ebdSchin if (!t) 244da2e3ebdSchin error(1, "%s: archive option value expected", e); 245da2e3ebdSchin else 246da2e3ebdSchin dp->name = strdup(t); 247da2e3ebdSchin break; 248da2e3ebdSchin default: 249da2e3ebdSchin error(1, "%s: unknown archive option", e); 250da2e3ebdSchin break; 251da2e3ebdSchin } 252da2e3ebdSchin } 253da2e3ebdSchin if (sfseek(sp, -(VDB_LENGTH + 1), SEEK_END) <= 0 || !(s = sfgetr(sp, '\n', 1))) 254da2e3ebdSchin { 255da2e3ebdSchin notvdb: 256da2e3ebdSchin sfclose(sp); 257da2e3ebdSchin error(1, "%s: ignored -- cannot load archive", dp->name); 258da2e3ebdSchin dp->type = 0; 259da2e3ebdSchin continue; 260da2e3ebdSchin } 261da2e3ebdSchin if (variant = *s != 0) 262da2e3ebdSchin s++; 263da2e3ebdSchin else if (!(s = sfgetr(sp, '\n', 1))) 264da2e3ebdSchin goto notvdb; 265da2e3ebdSchin if (sfvalue(sp) != (VDB_LENGTH + variant)) 266da2e3ebdSchin goto notvdb; 267da2e3ebdSchin if (!strneq(s, VDB_DIRECTORY, sizeof(VDB_DIRECTORY) - 1)) 268da2e3ebdSchin goto notvdb; 269da2e3ebdSchin delimiter = s[VDB_OFFSET - 1]; 270da2e3ebdSchin off = strtol(s + VDB_OFFSET, NiL, 10) - sizeof(VDB_DIRECTORY); 271da2e3ebdSchin siz = strtol(s + VDB_SIZE, NiL, 10); 272da2e3ebdSchin if (sfseek(sp, off, SEEK_SET) != off) 273da2e3ebdSchin goto notvdb; 274da2e3ebdSchin if (!(s = sfreserve(sp, siz + 1, 0))) 275da2e3ebdSchin goto notvdb; 276da2e3ebdSchin s[siz] = 0; 277da2e3ebdSchin if (!strneq(s, VDB_DIRECTORY, sizeof(VDB_DIRECTORY)) - 1) 278da2e3ebdSchin goto notvdb; 279da2e3ebdSchin if (!(s = strchr(s, '\n'))) 280da2e3ebdSchin goto notvdb; 281da2e3ebdSchin s++; 282da2e3ebdSchin while (e = strchr(s, '\n')) 283da2e3ebdSchin { 284da2e3ebdSchin delimiter = variant ? *s++ : delimiter; 285da2e3ebdSchin if (!(t = strchr(s, delimiter))) 286da2e3ebdSchin break; 287da2e3ebdSchin *t = 0; 288da2e3ebdSchin if (!streq(s, VDB_DIRECTORY)) 289da2e3ebdSchin { 290da2e3ebdSchin pathcanon(s, 0); 291da2e3ebdSchin ap = newof(0, struct ppmember, 1, 0); 292da2e3ebdSchin ap->archive = dp; 293da2e3ebdSchin ap->offset = strtol(t + 1, &t, 10); 294da2e3ebdSchin ap->size = strtol(t + 1, NiL, 10); 295da2e3ebdSchin xp = ppsetfile(s); 296da2e3ebdSchin xp->flags |= INC_MEMBER(dp->index); 297da2e3ebdSchin xp->bound[dp->index] = (struct ppfile*)ap; 298da2e3ebdSchin if (pp.test & 0x0020) error(1, "VDB#%d %s %s index=%d data=<%lu,%lu>", __LINE__, dp->name, xp->name, index, ap->offset, ap->size); 299da2e3ebdSchin } 300da2e3ebdSchin s = e + 1; 301da2e3ebdSchin } 302da2e3ebdSchin if (sfseek(sp, 0L, SEEK_SET)) 303da2e3ebdSchin goto notvdb; 304da2e3ebdSchin if (!(pp.test & 0x4000) && 305da2e3ebdSchin #if POOL 306da2e3ebdSchin (pp.pool.input || !(dp->type & TYPE_CHECKPOINT)) 307da2e3ebdSchin #else 308da2e3ebdSchin !(dp->type & TYPE_CHECKPOINT) 309da2e3ebdSchin #endif 310da2e3ebdSchin && (dp->info.buffer = sfreserve(sp, off, 0))) 311da2e3ebdSchin dp->type |= TYPE_BUFFER; 312da2e3ebdSchin else 313da2e3ebdSchin { 314da2e3ebdSchin dp->info.sp = sp; 315da2e3ebdSchin #if POOL 316da2e3ebdSchin if (pp.pool.input) 317da2e3ebdSchin sfset(sp, SF_SHARE, 1); 318da2e3ebdSchin #endif 319da2e3ebdSchin } 320da2e3ebdSchin } 321da2e3ebdSchin else 322da2e3ebdSchin dp->type |= TYPE_DIRECTORY; 323da2e3ebdSchin } 324da2e3ebdSchin #endif 325da2e3ebdSchin if (streq(fp->name, ".")) 326da2e3ebdSchin continue; 327da2e3ebdSchin if (prefix && *fp->name != '/' && dp->index != INC_PREFIX) 328da2e3ebdSchin #if ARCHIVE 329da2e3ebdSchin if (dp->type & TYPE_DIRECTORY) 330da2e3ebdSchin #endif 331da2e3ebdSchin { 332da2e3ebdSchin for (up = dp->info.subdir; up; up = up->next) 333da2e3ebdSchin if (up->name == prefix) 334da2e3ebdSchin break; 335da2e3ebdSchin if (!up) 336da2e3ebdSchin { 337da2e3ebdSchin up = newof(0, struct ppdirs, 1, 0); 338da2e3ebdSchin up->name = prefix; 339da2e3ebdSchin up->type = dp->type; 340da2e3ebdSchin up->next = dp->info.subdir; 341da2e3ebdSchin dp->info.subdir = up; 342da2e3ebdSchin if (!*dp->name) 343da2e3ebdSchin t = prefix; 344da2e3ebdSchin else 345da2e3ebdSchin sfsprintf(t = pp.path, PATH_MAX - 1, "%s/%s", dp->name, prefix); 346da2e3ebdSchin if (eaccess(t, X_OK)) 347da2e3ebdSchin { 348da2e3ebdSchin message((-3, "search: omit %s", t)); 349da2e3ebdSchin continue; 350da2e3ebdSchin } 351da2e3ebdSchin up->type |= TYPE_HOSTED; 352da2e3ebdSchin } 353da2e3ebdSchin else if (!(up->type & TYPE_HOSTED)) 354da2e3ebdSchin continue; 355da2e3ebdSchin } 356da2e3ebdSchin mp = xp = 0; 357da2e3ebdSchin if (!(flags & SEARCH_NEXT) && index != dp->index && (!(need & TYPE_HOSTED) || dp->index == INC_STANDARD) && (!(need & TYPE_VENDOR) || dp->index == INC_VENDOR)) 358da2e3ebdSchin { 359da2e3ebdSchin if (index >= 0 && !(fp->flags & INC_MEMBER(index))) 360da2e3ebdSchin fp->flags |= INC_BOUND(index); 361da2e3ebdSchin index = dp->index; 362da2e3ebdSchin if (fp->flags & INC_BOUND(index)) 363da2e3ebdSchin { 364da2e3ebdSchin xp = fp->bound[index]; 365da2e3ebdSchin if (index == INC_PREFIX) 366da2e3ebdSchin { 367da2e3ebdSchin if (*fp->name == '/' || !*dp->name) 368da2e3ebdSchin strcpy(pp.path, fp->name); 369da2e3ebdSchin else 370da2e3ebdSchin sfsprintf(pp.path, PATH_MAX - 1, "%s/%s", dp->name, fp->name); 371da2e3ebdSchin pathcanon(pp.path, 0); 372da2e3ebdSchin if (!xp || !streq(xp->name, pp.path)) 373da2e3ebdSchin { 374da2e3ebdSchin fp->bound[index] = xp = ppsetfile(pp.path); 375da2e3ebdSchin if (dp->type & TYPE_HOSTED) 376da2e3ebdSchin xp->flags |= INC_HOSTED; 377da2e3ebdSchin if ((flags & SEARCH_INCLUDE) || (xp->flags & INC_EXISTS)) 378da2e3ebdSchin { 379da2e3ebdSchin if (!(flags & SEARCH_INCLUDE)) 380da2e3ebdSchin return 0; 381da2e3ebdSchin if (!ppmultiple(xp, INC_TEST)) 382da2e3ebdSchin { 383da2e3ebdSchin if (flags & SEARCH_TEST) 384da2e3ebdSchin pp.include = xp->name; 385da2e3ebdSchin return 0; 386da2e3ebdSchin } 387da2e3ebdSchin mp = xp; 388da2e3ebdSchin } 389da2e3ebdSchin } 390da2e3ebdSchin } 391da2e3ebdSchin else if (!xp) 392da2e3ebdSchin { 393da2e3ebdSchin while (dp->next && dp->next->index == index) 394da2e3ebdSchin dp = dp->next; 395da2e3ebdSchin message((-3, "search: omit %s/%s", dp->name, fp->name)); 396da2e3ebdSchin continue; 397da2e3ebdSchin } 398da2e3ebdSchin else 399da2e3ebdSchin { 400da2e3ebdSchin strcpy(pp.path, xp->name); 401da2e3ebdSchin if (!(flags & SEARCH_INCLUDE)) 402da2e3ebdSchin return 0; 403da2e3ebdSchin if (!ppmultiple(xp, INC_TEST)) 404da2e3ebdSchin { 405da2e3ebdSchin if (flags & SEARCH_TEST) 406da2e3ebdSchin pp.include = xp->name; 407da2e3ebdSchin return 0; 408da2e3ebdSchin } 409da2e3ebdSchin mp = xp; 410da2e3ebdSchin } 411da2e3ebdSchin } 412da2e3ebdSchin } 413da2e3ebdSchin if (!(fp->flags & INC_BOUND(index)) || (flags & SEARCH_NEXT)) 414da2e3ebdSchin { 415da2e3ebdSchin if (*fp->name == '/' || !*dp->name) 416da2e3ebdSchin strcpy(pp.path, fp->name); 417da2e3ebdSchin else 418da2e3ebdSchin sfsprintf(pp.path, PATH_MAX - 1, "%s/%s", dp->name, fp->name); 419da2e3ebdSchin pathcanon(pp.path, 0); 420da2e3ebdSchin if (!(flags & SEARCH_SKIP)) 421da2e3ebdSchin { 422da2e3ebdSchin int found; 423da2e3ebdSchin struct ppinstk* in; 424da2e3ebdSchin 425da2e3ebdSchin if (streq(error_info.file, pp.path)) 426da2e3ebdSchin found = 1; 427da2e3ebdSchin else 428da2e3ebdSchin { 429da2e3ebdSchin found = 0; 430da2e3ebdSchin for (in = pp.in; in; in = in->prev) 431da2e3ebdSchin if (in->type == IN_FILE && in->file && streq(in->file, pp.path)) 432da2e3ebdSchin { 433da2e3ebdSchin found = 1; 434da2e3ebdSchin break; 435da2e3ebdSchin } 436da2e3ebdSchin } 437da2e3ebdSchin if (found) 438da2e3ebdSchin { 439da2e3ebdSchin flags |= SEARCH_FOUND; 440da2e3ebdSchin continue; 441da2e3ebdSchin } 442da2e3ebdSchin if (!(flags & SEARCH_FOUND)) 443da2e3ebdSchin continue; 444da2e3ebdSchin } 445da2e3ebdSchin } 446da2e3ebdSchin if ((xp || (xp = ppgetfile(pp.path))) && (xp->flags & INC_SELF)) 447da2e3ebdSchin { 448da2e3ebdSchin if (xp->flags & INC_EXISTS) 449da2e3ebdSchin { 450da2e3ebdSchin if (!(flags & SEARCH_INCLUDE)) 451da2e3ebdSchin return 0; 452da2e3ebdSchin if (!(flags & SEARCH_NEXT) && mp != xp && (mp = xp) && !ppmultiple(xp, INC_TEST)) 453da2e3ebdSchin { 454da2e3ebdSchin if (flags & SEARCH_TEST) 455da2e3ebdSchin pp.include = xp->name; 456da2e3ebdSchin return 0; 457da2e3ebdSchin } 458da2e3ebdSchin } 459da2e3ebdSchin else if (*fp->name == '/') 460da2e3ebdSchin break; 461da2e3ebdSchin else 462da2e3ebdSchin continue; 463da2e3ebdSchin } 464da2e3ebdSchin message((-3, "search: file=%s path=%s", fp->name, pp.path)); 465da2e3ebdSchin #if ARCHIVE 466da2e3ebdSchin if (pp.test & 0x0040) error(1, "SEARCH#%d dir=%s%s%s%s%s file=%s%s path=%s index=%d", __LINE__, dp->name, (dp->type & TYPE_ARCHIVE) ? " ARCHIVE" : "", (dp->type & TYPE_BUFFER) ? " BUFFER" : "", (dp->type & TYPE_CHECKPOINT) ? " CHECKPOINT" : "", (dp->type & TYPE_DIRECTORY) ? " DIRECTORY" : "", fp->name, (fp->flags & INC_MEMBER(index)) ? " MEMBER" : "", pp.path, index); 467da2e3ebdSchin if ((fp->flags & INC_MEMBER(index)) && ((struct ppmember*)fp->bound[index])->archive == dp) 468da2e3ebdSchin { 469da2e3ebdSchin fd = 0; 470da2e3ebdSchin pp.member = (struct ppmember*)fp->bound[index]; 471da2e3ebdSchin if (pp.test & 0x0010) error(1, "SEARCH#%d file=%s path=%s index=%d data=<%lu,%lu>", __LINE__, fp->name, pp.path, index, pp.member->offset, pp.member->size); 472da2e3ebdSchin } 473da2e3ebdSchin else if (!(dp->type & TYPE_DIRECTORY)) 474da2e3ebdSchin continue; 475da2e3ebdSchin else 476da2e3ebdSchin #endif 477da2e3ebdSchin { 478da2e3ebdSchin pp.member = 0; 479da2e3ebdSchin fd = (flags & SEARCH_INCLUDE) ? open(pp.path, O_RDONLY) : eaccess(pp.path, R_OK); 480da2e3ebdSchin } 481da2e3ebdSchin if (fd >= 0) 482da2e3ebdSchin { 483da2e3ebdSchin pp.found = dp; 484da2e3ebdSchin if ((pp.option & (PLUSPLUS|NOPROTO)) == PLUSPLUS && !(pp.test & TEST_noproto)) 485da2e3ebdSchin { 486da2e3ebdSchin if (dp->c) 487da2e3ebdSchin pp.mode |= MARKC; 488da2e3ebdSchin else 489da2e3ebdSchin pp.mode &= ~MARKC; 490da2e3ebdSchin } 491da2e3ebdSchin if (xp) 492da2e3ebdSchin markhosted = xp->flags & INC_HOSTED; 493da2e3ebdSchin else if (!(markhosted = (dp->type & TYPE_HOSTED)) && dp->index == INC_PREFIX && (pp.mode & (FILEDEPS|HEADERDEPS|INIT)) == FILEDEPS) 494da2e3ebdSchin { 495da2e3ebdSchin up = dp; 496da2e3ebdSchin while ((up = up->next) && !streq(up->name, dp->name)); 497da2e3ebdSchin if (up && (up->type & TYPE_HOSTED)) 498da2e3ebdSchin markhosted = 1; 499da2e3ebdSchin } 500da2e3ebdSchin if (markhosted) 501da2e3ebdSchin pp.mode |= MARKHOSTED; 502da2e3ebdSchin else 503da2e3ebdSchin pp.mode &= ~MARKHOSTED; 504da2e3ebdSchin xp = ppsetfile(pp.path); 505da2e3ebdSchin if (markhosted) 506da2e3ebdSchin xp->flags |= INC_HOSTED; 507da2e3ebdSchin message((-2, "search: %s -> %s%s%s", fp->name, pp.path, (pp.mode & MARKC) ? " [C]" : "", (pp.mode & MARKHOSTED) ? " [hosted]" : "")); 508da2e3ebdSchin #if ARCHIVE 509da2e3ebdSchin if (!pp.member) 510da2e3ebdSchin { 511da2e3ebdSchin #endif 512da2e3ebdSchin fp->flags |= INC_BOUND(index); 513da2e3ebdSchin fp->bound[index] = xp; 514da2e3ebdSchin if ((index == INC_STANDARD || index == INC_VENDOR) && type != T_HEADER && !(fp->flags & INC_BOUND(INC_LOCAL))) 515da2e3ebdSchin { 516da2e3ebdSchin fp->flags |= INC_BOUND(INC_LOCAL); 517da2e3ebdSchin fp->bound[INC_LOCAL] = xp; 518da2e3ebdSchin } 519da2e3ebdSchin #if ARCHIVE 520da2e3ebdSchin } 521da2e3ebdSchin #endif 522da2e3ebdSchin xp->flags |= INC_SELF|INC_EXISTS; 523da2e3ebdSchin if (flags & SEARCH_INCLUDE) 524da2e3ebdSchin { 525da2e3ebdSchin if ((pp.prefix = prefix) || (pp.prefix = pp.in->prefix)) 526da2e3ebdSchin message((-2, "search: %s: prefix=%s", xp->name, pp.prefix)); 527da2e3ebdSchin if (!(pp.mode & ALLMULTIPLE)) 528da2e3ebdSchin { 529da2e3ebdSchin if (xp->guard == INC_CLEAR || xp == mp) 530da2e3ebdSchin xp->guard = INC_TEST; 531da2e3ebdSchin else 532da2e3ebdSchin { 533*7c2fbfb3SApril Chin if ((pp.state & WARN) && (pp.mode & (HOSTED|MARKHOSTED|RELAX|PEDANTIC)) == PEDANTIC) 534da2e3ebdSchin error(1, "%s: ignored -- already included", xp->name); 535da2e3ebdSchin else 536da2e3ebdSchin message((-3, "%s: ignored -- already included", xp->name)); 537da2e3ebdSchin xp->guard = fp->guard = INC_IGNORE; 538da2e3ebdSchin #if ARCHIVE 539da2e3ebdSchin if (!pp.member) 540da2e3ebdSchin #endif 541da2e3ebdSchin if (fd > 0) 542da2e3ebdSchin close(fd); 543da2e3ebdSchin if (flags & SEARCH_TEST) 544da2e3ebdSchin pp.include = xp->name; 545da2e3ebdSchin return 0; 546da2e3ebdSchin } 547da2e3ebdSchin } 548da2e3ebdSchin pp.include = xp->name; 549da2e3ebdSchin if ((pp.mode & (FILEDEPS|INIT)) == FILEDEPS && ((pp.mode & HEADERDEPS) || !(pp.mode & MARKHOSTED)) && !(xp->flags & INC_LISTED)) 550da2e3ebdSchin { 551da2e3ebdSchin xp->flags |= INC_LISTED; 552da2e3ebdSchin if ((pp.column + strlen(xp->name)) >= COLUMN_MAX) 553da2e3ebdSchin { 554da2e3ebdSchin sfprintf(pp.filedeps.sp, " \\\n"); 555da2e3ebdSchin pp.column = COLUMN_TAB; 556da2e3ebdSchin index = '\t'; 557da2e3ebdSchin } 558da2e3ebdSchin else 559da2e3ebdSchin index = ' '; 560da2e3ebdSchin pp.column += sfprintf(pp.filedeps.sp, "%c%s", index, xp->name); 561da2e3ebdSchin } 562da2e3ebdSchin } 563da2e3ebdSchin return fd; 564da2e3ebdSchin } 565da2e3ebdSchin if (xp) 566da2e3ebdSchin xp->flags |= INC_SELF; 567da2e3ebdSchin if (errno == EMFILE) 568da2e3ebdSchin error(3, "%s: too many open files", fp->name); 569da2e3ebdSchin else if (errno != ENOENT && errno != ENOTDIR) 570da2e3ebdSchin error(ERROR_SYSTEM|1, "%s: cannot open file for reading", pp.path); 571da2e3ebdSchin if (*fp->name == '/') 572da2e3ebdSchin break; 573da2e3ebdSchin } 574da2e3ebdSchin strcpy(pp.path, fp->name); 575da2e3ebdSchin message((-2, "search: %s%s not found", (flags & SEARCH_NEXT) ? "next " : "", fp->name)); 576da2e3ebdSchin return -1; 577da2e3ebdSchin } 578da2e3ebdSchin 579da2e3ebdSchin /* 580da2e3ebdSchin * search for an include file 581da2e3ebdSchin * if (flags&SEARCH_INCLUDE) then 582da2e3ebdSchin * if file found then open read file descriptor returned 583da2e3ebdSchin * with pp.path set to the full path and 584da2e3ebdSchin * pp.prefix set to the directory prefix 585da2e3ebdSchin * otherwise 0 returned if file found but ignored 586da2e3ebdSchin * otherwise -1 returned 587da2e3ebdSchin * otherwise 588da2e3ebdSchin * if file found then 0 returned 589da2e3ebdSchin * otherwise -1 returned 590da2e3ebdSchin */ 591da2e3ebdSchin 592da2e3ebdSchin int 593da2e3ebdSchin ppsearch(char* file, int type, int flags) 594da2e3ebdSchin { 595da2e3ebdSchin register struct ppfile* fp; 596da2e3ebdSchin register char* s; 597da2e3ebdSchin register struct ppdirs* dp; 598da2e3ebdSchin struct oplist* cp; 599da2e3ebdSchin struct ppfile* xp; 600da2e3ebdSchin int dospath; 601*7c2fbfb3SApril Chin int chop; 602da2e3ebdSchin int fd; 603da2e3ebdSchin int index; 604da2e3ebdSchin char name[MAXTOKEN + 1]; 605da2e3ebdSchin 606da2e3ebdSchin pp.include = 0; 607da2e3ebdSchin fd = -1; 608da2e3ebdSchin dospath = 0; 609*7c2fbfb3SApril Chin chop = 0; 610da2e3ebdSchin again: 611da2e3ebdSchin pathcanon(file, 0); 612*7c2fbfb3SApril Chin if (chop) 613da2e3ebdSchin for (cp = pp.chop; cp; cp = cp->next) 614da2e3ebdSchin if (strneq(file, cp->value, cp->op)) 615da2e3ebdSchin { 616da2e3ebdSchin if (cp->value[cp->op + 1]) 617da2e3ebdSchin { 618da2e3ebdSchin sfsprintf(name, sizeof(name) - 1, "%s%s", cp->value + cp->op + 1, file + cp->op); 619*7c2fbfb3SApril Chin message((-2, "search: %s -> %s", file, name)); 620da2e3ebdSchin file = name; 621da2e3ebdSchin } 622da2e3ebdSchin else if (strchr(file + cp->op, '/')) 623da2e3ebdSchin { 624*7c2fbfb3SApril Chin message((-2, "search: %s -> %s", file, file + cp->op)); 625da2e3ebdSchin file += cp->op; 626da2e3ebdSchin } 627da2e3ebdSchin break; 628da2e3ebdSchin } 629da2e3ebdSchin fp = ppsetfile(file); 630da2e3ebdSchin while ((fp->flags & INC_MAPALL) || (fp->flags & INC_MAPHOSTED) && (pp.mode & HOSTED) || (fp->flags & INC_MAPNOHOSTED) && !(pp.mode & HOSTED)) 631da2e3ebdSchin { 632da2e3ebdSchin if (!(xp = fp->bound[type == T_HEADER ? INC_STANDARD : INC_LOCAL]) || xp == fp) 633da2e3ebdSchin break; 634da2e3ebdSchin message((-1, "map: %s -> %s", fp->name, xp->name)); 635da2e3ebdSchin fp = xp; 636da2e3ebdSchin } 637da2e3ebdSchin if ((fp->flags & INC_MAPNOLOCAL) && (pp.mode & HOSTED)) 638da2e3ebdSchin flags |= SEARCH_HOSTED; 639da2e3ebdSchin else if (pp.vendor) 640da2e3ebdSchin flags |= SEARCH_VENDOR; 641da2e3ebdSchin pp.original = fp; 642da2e3ebdSchin if (type == T_HEADER && strneq(fp->name, "...", 3) && (!fp->name[3] || fp->name[3] == '/')) 643da2e3ebdSchin { 644da2e3ebdSchin if (fp->name[3] == '/') 645da2e3ebdSchin { 646da2e3ebdSchin int n; 647da2e3ebdSchin int m; 648da2e3ebdSchin 649da2e3ebdSchin n = strlen(error_info.file); 650da2e3ebdSchin m = strlen(fp->name + 4); 651da2e3ebdSchin if (n < m || !streq(fp->name + 4, error_info.file + n - m)) 652da2e3ebdSchin { 653da2e3ebdSchin if ((fd = ppsearch(fp->name + 4, type, flags|SEARCH_TEST)) < 0) 654da2e3ebdSchin return -1; 655da2e3ebdSchin if (fd > 0) 656da2e3ebdSchin close(fd); 657da2e3ebdSchin s = error_info.file; 658da2e3ebdSchin error_info.file = pp.include; 659da2e3ebdSchin fd = ppsearch(fp->name + 4, type, flags|SEARCH_NEXT); 660da2e3ebdSchin error_info.file = s; 661da2e3ebdSchin return fd; 662da2e3ebdSchin } 663da2e3ebdSchin file = error_info.file + n - m; 664da2e3ebdSchin } 665da2e3ebdSchin else if (file = strrchr(error_info.file, '/')) 666da2e3ebdSchin file++; 667da2e3ebdSchin else 668da2e3ebdSchin file = error_info.file; 669da2e3ebdSchin flags |= SEARCH_NEXT; 670da2e3ebdSchin #if _HUH_2002_05_28 671da2e3ebdSchin if (pp.in->prefix) 672da2e3ebdSchin { 673da2e3ebdSchin sfsprintf(name, sizeof(name) - 1, "%s/%s", pp.in->prefix, file); 674da2e3ebdSchin fp = ppsetfile(name); 675da2e3ebdSchin if ((fd = ppsearch(fp->name, type, flags)) >= 0) 676da2e3ebdSchin return fd; 677da2e3ebdSchin } 678da2e3ebdSchin #endif 679da2e3ebdSchin fp = ppsetfile(file); 680da2e3ebdSchin return ppsearch(fp->name, type, flags); 681da2e3ebdSchin } 682da2e3ebdSchin else if ((flags & SEARCH_INCLUDE) && fp->guard == INC_IGNORE) 683da2e3ebdSchin { 684da2e3ebdSchin strcpy(pp.path, fp->name); 685da2e3ebdSchin message((-2, "%s: ignored", fp->name)); 686da2e3ebdSchin return 0; 687da2e3ebdSchin } 688da2e3ebdSchin else if (!(flags & SEARCH_NEXT)) 689da2e3ebdSchin flags |= SEARCH_SKIP; 690da2e3ebdSchin pp.prefix = 0; 691da2e3ebdSchin if (type == T_HEADER) 692da2e3ebdSchin dp = pp.stddirs->next; 693da2e3ebdSchin else 694da2e3ebdSchin { 695da2e3ebdSchin dp = pp.lcldirs; 696da2e3ebdSchin if (dp == pp.firstdir) 697da2e3ebdSchin { 698da2e3ebdSchin /* 699da2e3ebdSchin * look in directory of including file first 700da2e3ebdSchin */ 701da2e3ebdSchin 702da2e3ebdSchin if (error_info.file && (s = strrchr(error_info.file, '/'))) 703da2e3ebdSchin { 704da2e3ebdSchin *s = 0; 705da2e3ebdSchin dp->name = ppsetfile(error_info.file)->name; 706da2e3ebdSchin *s = '/'; 707da2e3ebdSchin } 708da2e3ebdSchin else 709da2e3ebdSchin dp->name = ""; 710da2e3ebdSchin } 711da2e3ebdSchin else if (pp.in->prefix && pp.lcldirs != pp.firstdir) 712da2e3ebdSchin { 713da2e3ebdSchin /* 714da2e3ebdSchin * look in prefix directory of including file first 715da2e3ebdSchin */ 716da2e3ebdSchin 717da2e3ebdSchin if (*fp->name != '/') 718da2e3ebdSchin { 719da2e3ebdSchin if ((s = strchr(fp->name, '/')) && (fp->name[0] 720da2e3ebdSchin != '.' || fp->name[1] != '.' || fp->name[2] != '/')) 721da2e3ebdSchin { 722da2e3ebdSchin *s = 0; 723da2e3ebdSchin if (!streq(fp->name, pp.in->prefix)) 724da2e3ebdSchin fd = 0; 725da2e3ebdSchin *s = '/'; 726da2e3ebdSchin } 727da2e3ebdSchin else 728da2e3ebdSchin fd = 0; 729da2e3ebdSchin } 730da2e3ebdSchin if (fd >= 0) 731da2e3ebdSchin { 732da2e3ebdSchin sfsprintf(name, sizeof(name) - 1, "%s/%s", pp.in->prefix, fp->name); 733da2e3ebdSchin pathcanon(name, 0); 734da2e3ebdSchin xp = ppsetfile(name); 735da2e3ebdSchin if ((fd = search(xp, dp, type, flags)) >= 0) 736da2e3ebdSchin return fd; 737da2e3ebdSchin } 738da2e3ebdSchin } 739da2e3ebdSchin } 740da2e3ebdSchin if ((fd = search(fp, dp, type, flags)) < 0) 741da2e3ebdSchin { 742da2e3ebdSchin if ((pp.option & PLUSPLUS) && file != pp.tmpbuf) 743da2e3ebdSchin { 744da2e3ebdSchin s = file + strlen(file); 745da2e3ebdSchin while (s > file && *--s != '/' && *s != '\\' && *s != '.'); 746da2e3ebdSchin if (*s != '.') 747da2e3ebdSchin { 748da2e3ebdSchin sfsprintf(pp.tmpbuf, MAXTOKEN, "%s.h", file); 749da2e3ebdSchin file = pp.tmpbuf; 750da2e3ebdSchin goto again; 751da2e3ebdSchin } 752da2e3ebdSchin } 753da2e3ebdSchin 754da2e3ebdSchin /* 755da2e3ebdSchin * hackery for msdos files viewed through unix 756da2e3ebdSchin */ 757da2e3ebdSchin 758da2e3ebdSchin switch (dospath) 759da2e3ebdSchin { 760da2e3ebdSchin case 0: 761da2e3ebdSchin if (s = strchr(file, '\\')) 762da2e3ebdSchin { 763da2e3ebdSchin do *s++ = '/'; while (s = strchr(s, '\\')); 764da2e3ebdSchin pathcanon(file, 0); 765da2e3ebdSchin dospath = 1; 766da2e3ebdSchin goto again; 767da2e3ebdSchin } 768da2e3ebdSchin /*FALLTHROUGH*/ 769da2e3ebdSchin case 1: 770da2e3ebdSchin if (ppisid(file[0]) && file[1] == ':' && file[2] == '/') 771da2e3ebdSchin { 772da2e3ebdSchin file[1] = file[0]; 773da2e3ebdSchin file[0] = '/'; 774da2e3ebdSchin pathcanon(file, 0); 775da2e3ebdSchin dospath = 2; 776da2e3ebdSchin goto again; 777da2e3ebdSchin } 778da2e3ebdSchin break; 779da2e3ebdSchin case 2: 780da2e3ebdSchin file += 2; 781da2e3ebdSchin goto again; 782da2e3ebdSchin } 783da2e3ebdSchin if ((flags & (SEARCH_INCLUDE|SEARCH_NEXT)) == SEARCH_INCLUDE) 784da2e3ebdSchin { 785*7c2fbfb3SApril Chin if (!chop && pp.chop) 786*7c2fbfb3SApril Chin { 787*7c2fbfb3SApril Chin chop = 1; 788*7c2fbfb3SApril Chin type = T_STRING; 789*7c2fbfb3SApril Chin goto again; 790*7c2fbfb3SApril Chin } 791da2e3ebdSchin if (!(pp.mode & GENDEPS)) 792da2e3ebdSchin { 793da2e3ebdSchin if (!(pp.option & ALLPOSSIBLE) || pp.in->prev->prev) 794da2e3ebdSchin error(2, "%s: cannot find include file", file); 795da2e3ebdSchin } 796da2e3ebdSchin else if (!(pp.mode & INIT)) 797da2e3ebdSchin { 798da2e3ebdSchin xp = ppsetfile(file); 799da2e3ebdSchin if (!(xp->flags & INC_LISTED)) 800da2e3ebdSchin { 801da2e3ebdSchin xp->flags |= INC_LISTED; 802da2e3ebdSchin if ((pp.column + strlen(file)) >= COLUMN_MAX) 803da2e3ebdSchin { 804da2e3ebdSchin sfprintf(pp.filedeps.sp, " \\\n"); 805da2e3ebdSchin pp.column = COLUMN_TAB; 806da2e3ebdSchin index = '\t'; 807da2e3ebdSchin } 808da2e3ebdSchin else 809da2e3ebdSchin index = ' '; 810da2e3ebdSchin pp.column += sfprintf(pp.filedeps.sp, "%c%s", index, file); 811da2e3ebdSchin } 812da2e3ebdSchin } 813da2e3ebdSchin } 814da2e3ebdSchin } 815da2e3ebdSchin return fd; 816da2e3ebdSchin } 817