1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1986-2009 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
19 ***********************************************************************/
25 * include file search support
30 #define SEARCH_NEXT (SEARCH_USER<<1)/* search for next (uncover) */
31 #define SEARCH_SKIP (SEARCH_USER<<2)/* current binding skipped */
32 #define SEARCH_TEST (SEARCH_USER<<3)/* test for binding */
33 #define SEARCH_FOUND (SEARCH_USER<<4)/* current binding found */
46 * multiple include test
47 * fp is a canonicalized ppfile pointer
51 * INC_CLEAR can be included again
52 * INC_TEST test if include required
53 * <symbol> ifndef guard symbol
55 * test!=INC_CLEAR returns 1 if file can be included again
59 * (1) different hard links to the same file are treated as
62 * (2) symbolic links in combination with .. may cause two
63 * different files to be treated as the same file:
65 * "../h/<file>" == "/usr/include/sys/../h/<file>" -> "/usr/include/h/<file>"
66 * "h/<file>" -> "/usr/include/h/<file>"
70 ppmultiple(register struct ppfile
* fp
, register struct ppsymbol
* test
)
72 register struct ppsymbol
* status
;
75 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
));
76 if (status
== INC_IGNORE
)
78 message((-2, "%s: ignored [%s]", fp
->name
, pp
.ignore
));
83 if (status
!= INC_CLEAR
)
85 if (status
== INC_TEST
|| status
->macro
)
87 if ((pp
.mode
& (ALLMULTIPLE
|LOADING
)) == LOADING
)
88 fp
->guard
= INC_IGNORE
;
89 if ((pp
.state
& WARN
) && (pp
.mode
& (HOSTED
|MARKHOSTED
|RELAX
|PEDANTIC
)) == PEDANTIC
)
90 error(1, "%s: ignored -- already included", fp
->name
);
92 message((-3, "%s: ignored -- already included", fp
->name
));
97 if ((pp
.mode
& (ALLMULTIPLE
|LOADING
)) == LOADING
)
107 * search for file using directories in dp
111 search(register struct ppfile
* fp
, register struct ppdirs
* dp
, int type
, int flags
)
113 register char* prefix
;
114 register struct ppdirs
* up
;
115 register struct ppfile
* xp
;
123 if (!(pp
.option
& PREFIX
))
125 else if ((prefix
= strrchr(fp
->name
, '/')) && prefix
> fp
->name
)
128 t
= ppsetfile(fp
->name
)->name
;
132 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",
134 (flags
& SEARCH_INCLUDE
) ? "include" : "exists",
135 (flags
& SEARCH_VENDOR
) ? " vendor" : "",
136 (flags
& SEARCH_HOSTED
) ? " hosted" : "",
137 (flags
& SEARCH_NEXT
) ? " next" : "",
138 (flags
& SEARCH_SKIP
) ? " skip" : "",
139 (flags
& SEARCH_TEST
) ? " test" : "",
140 type
== T_HEADER
? "<*>" : "\"*\"", prefix
,
141 (fp
->flags
& INC_SELF
) ? "SELF|" : "",
142 (fp
->flags
& INC_EXISTS
) ? "EXISTS|" : "",
143 (fp
->flags
& INC_BOUND(INC_PREFIX
)) ? "PREFIX|" : "",
144 (fp
->flags
& INC_BOUND(INC_LOCAL
)) ? "LOCAL|" : "",
145 (fp
->flags
& INC_BOUND(INC_VENDOR
)) ? "VENDOR|" : "",
146 (fp
->flags
& INC_BOUND(INC_STANDARD
)) ? "STANDARD|" : "",
147 dp
? (dp
->index
== INC_PREFIX
? "pre" : dp
->index
== INC_LOCAL
? "lcl" : dp
->index
== INC_VENDOR
? "vnd" : "std") : NiL
,
149 !(fp
->flags
& INC_MEMBER(INC_PREFIX
)) && (xp
= fp
->bound
[INC_PREFIX
]) ? xp
->name
: NiL
,
150 !(fp
->flags
& INC_MEMBER(INC_LOCAL
)) && (xp
= fp
->bound
[INC_LOCAL
]) ? xp
->name
: NiL
,
151 !(fp
->flags
& INC_MEMBER(INC_VENDOR
)) && (xp
= fp
->bound
[INC_VENDOR
]) ? xp
->name
: NiL
,
152 !(fp
->flags
& INC_MEMBER(INC_STANDARD
)) && (xp
= fp
->bound
[INC_STANDARD
]) ? xp
->name
: NiL
,
155 if (flags
& SEARCH_HOSTED
)
157 else if (flags
& SEARCH_VENDOR
)
161 for (index
= -1; dp
; dp
= dp
->next
)
164 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
));
166 if (!(dp
->type
& (TYPE_ARCHIVE
|TYPE_DIRECTORY
)))
170 if (stat(dp
->name
, &st
))
172 message((-3, "search: omit %s", dp
->name
));
176 if (S_ISREG(st
.st_mode
))
188 * check for vdb header archive
191 if (!(sp
= sfopen(NiL
, dp
->name
, "r")))
193 error(ERROR_SYSTEM
|1, "%s: ignored -- cannot open", dp
->name
);
197 variant
= sfsprintf(pp
.tmpbuf
, MAXTOKEN
, "%c%s%c%s:archive", VDB_DELIMITER
, VDB_MAGIC
, VDB_DELIMITER
, pp
.pass
);
198 if (!(s
= sfgetr(sp
, '\n', 1)) || !strneq(s
, pp
.tmpbuf
, variant
))
201 error(1, "%s: ignored -- not a directory or archive", dp
->name
);
210 dp
->type
|= TYPE_ARCHIVE
;
213 while (*s
== ' ') s
++;
215 for (t
= 0; *s
&& *s
!= ' '; s
++)
225 switch ((int)hashref(pp
.strtab
, e
))
229 dp
->type
|= TYPE_CHECKPOINT
;
232 error(1, "preprocessor not compiled with checkpoint enabled");
238 error(1, "%s: %s: archive option value ignored", e
);
239 if (e
= strrchr(dp
->name
, '/'))
246 error(1, "%s: archive option value expected", e
);
248 dp
->name
= strdup(t
);
251 error(1, "%s: unknown archive option", e
);
255 if (sfseek(sp
, -(VDB_LENGTH
+ 1), SEEK_END
) <= 0 || !(s
= sfgetr(sp
, '\n', 1)))
259 error(1, "%s: ignored -- cannot load archive", dp
->name
);
263 if (variant
= *s
!= 0)
265 else if (!(s
= sfgetr(sp
, '\n', 1)))
267 if (sfvalue(sp
) != (VDB_LENGTH
+ variant
))
269 if (!strneq(s
, VDB_DIRECTORY
, sizeof(VDB_DIRECTORY
) - 1))
271 delimiter
= s
[VDB_OFFSET
- 1];
272 off
= strtol(s
+ VDB_OFFSET
, NiL
, 10) - sizeof(VDB_DIRECTORY
);
273 siz
= strtol(s
+ VDB_SIZE
, NiL
, 10);
274 if (sfseek(sp
, off
, SEEK_SET
) != off
)
276 if (!(s
= sfreserve(sp
, siz
+ 1, 0)))
279 if (!strneq(s
, VDB_DIRECTORY
, sizeof(VDB_DIRECTORY
)) - 1)
281 if (!(s
= strchr(s
, '\n')))
284 while (e
= strchr(s
, '\n'))
286 delimiter
= variant
? *s
++ : delimiter
;
287 if (!(t
= strchr(s
, delimiter
)))
290 if (!streq(s
, VDB_DIRECTORY
))
293 ap
= newof(0, struct ppmember
, 1, 0);
295 ap
->offset
= strtol(t
+ 1, &t
, 10);
296 ap
->size
= strtol(t
+ 1, NiL
, 10);
298 xp
->flags
|= INC_MEMBER(dp
->index
);
299 xp
->bound
[dp
->index
] = (struct ppfile
*)ap
;
300 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
);
304 if (sfseek(sp
, 0L, SEEK_SET
))
306 if (!(pp
.test
& 0x4000) &&
308 (pp
.pool
.input
|| !(dp
->type
& TYPE_CHECKPOINT
))
310 !(dp
->type
& TYPE_CHECKPOINT
)
312 && (dp
->info
.buffer
= sfreserve(sp
, off
, 0)))
313 dp
->type
|= TYPE_BUFFER
;
319 sfset(sp
, SF_SHARE
, 1);
324 dp
->type
|= TYPE_DIRECTORY
;
327 if (streq(fp
->name
, "."))
329 if (prefix
&& *fp
->name
!= '/' && dp
->index
!= INC_PREFIX
)
331 if (dp
->type
& TYPE_DIRECTORY
)
334 for (up
= dp
->info
.subdir
; up
; up
= up
->next
)
335 if (up
->name
== prefix
)
339 up
= newof(0, struct ppdirs
, 1, 0);
342 up
->next
= dp
->info
.subdir
;
343 dp
->info
.subdir
= up
;
347 sfsprintf(t
= pp
.path
, PATH_MAX
- 1, "%s/%s", dp
->name
, prefix
);
348 if (eaccess(t
, X_OK
))
350 message((-3, "search: omit %s", t
));
353 up
->type
|= TYPE_HOSTED
;
355 else if (!(up
->type
& TYPE_HOSTED
))
359 if (!(flags
& SEARCH_NEXT
) && index
!= dp
->index
&& (!(need
& TYPE_HOSTED
) || dp
->index
== INC_STANDARD
) && (!(need
& TYPE_VENDOR
) || dp
->index
== INC_VENDOR
))
361 if (index
>= 0 && !(fp
->flags
& INC_MEMBER(index
)))
362 fp
->flags
|= INC_BOUND(index
);
364 if (fp
->flags
& INC_BOUND(index
))
366 xp
= fp
->bound
[index
];
367 if (index
== INC_PREFIX
)
369 if (*fp
->name
== '/' || !*dp
->name
)
370 strcpy(pp
.path
, fp
->name
);
372 sfsprintf(pp
.path
, PATH_MAX
- 1, "%s/%s", dp
->name
, fp
->name
);
373 pathcanon(pp
.path
, 0);
374 if (!xp
|| !streq(xp
->name
, pp
.path
))
376 fp
->bound
[index
] = xp
= ppsetfile(pp
.path
);
377 if (dp
->type
& TYPE_HOSTED
)
378 xp
->flags
|= INC_HOSTED
;
379 if ((flags
& SEARCH_INCLUDE
) || (xp
->flags
& INC_EXISTS
))
381 if (!(flags
& SEARCH_INCLUDE
))
383 if (!ppmultiple(xp
, INC_TEST
))
385 if (flags
& SEARCH_TEST
)
386 pp
.include
= xp
->name
;
395 while (dp
->next
&& dp
->next
->index
== index
)
397 message((-3, "search: omit %s/%s", dp
->name
, fp
->name
));
402 strcpy(pp
.path
, xp
->name
);
403 if (!(flags
& SEARCH_INCLUDE
))
405 if (!ppmultiple(xp
, INC_TEST
))
407 if (flags
& SEARCH_TEST
)
408 pp
.include
= xp
->name
;
415 if (!(fp
->flags
& INC_BOUND(index
)) || (flags
& SEARCH_NEXT
))
417 if (*fp
->name
== '/' || !*dp
->name
)
418 strcpy(pp
.path
, fp
->name
);
420 sfsprintf(pp
.path
, PATH_MAX
- 1, "%s/%s", dp
->name
, fp
->name
);
421 pathcanon(pp
.path
, 0);
422 if (!(flags
& SEARCH_SKIP
))
427 if (streq(error_info
.file
, pp
.path
))
432 for (in
= pp
.in
; in
; in
= in
->prev
)
433 if (in
->type
== IN_FILE
&& in
->file
&& streq(in
->file
, pp
.path
))
441 flags
|= SEARCH_FOUND
;
444 if (!(flags
& SEARCH_FOUND
))
448 if ((xp
|| (xp
= ppgetfile(pp
.path
))) && (xp
->flags
& INC_SELF
))
450 if (xp
->flags
& INC_EXISTS
)
452 if (!(flags
& SEARCH_INCLUDE
))
454 if (!(flags
& SEARCH_NEXT
) && mp
!= xp
&& (mp
= xp
) && !ppmultiple(xp
, INC_TEST
))
456 if (flags
& SEARCH_TEST
)
457 pp
.include
= xp
->name
;
461 else if (*fp
->name
== '/')
466 message((-3, "search: file=%s path=%s", fp
->name
, pp
.path
));
468 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
);
469 if ((fp
->flags
& INC_MEMBER(index
)) && ((struct ppmember
*)fp
->bound
[index
])->archive
== dp
)
472 pp
.member
= (struct ppmember
*)fp
->bound
[index
];
473 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
);
475 else if (!(dp
->type
& TYPE_DIRECTORY
))
481 fd
= (flags
& SEARCH_INCLUDE
) ? open(pp
.path
, O_RDONLY
) : eaccess(pp
.path
, R_OK
);
486 if ((pp
.option
& (PLUSPLUS
|NOPROTO
)) == PLUSPLUS
&& !(pp
.test
& TEST_noproto
))
494 markhosted
= xp
->flags
& INC_HOSTED
;
495 else if (!(markhosted
= (dp
->type
& TYPE_HOSTED
)) && dp
->index
== INC_PREFIX
&& (pp
.mode
& (FILEDEPS
|HEADERDEPS
|INIT
)) == FILEDEPS
)
498 while ((up
= up
->next
) && !streq(up
->name
, dp
->name
));
499 if (up
&& (up
->type
& TYPE_HOSTED
))
503 pp
.mode
|= MARKHOSTED
;
505 pp
.mode
&= ~MARKHOSTED
;
506 xp
= ppsetfile(pp
.path
);
508 xp
->flags
|= INC_HOSTED
;
509 message((-2, "search: %s -> %s%s%s", fp
->name
, pp
.path
, (pp
.mode
& MARKC
) ? " [C]" : "", (pp
.mode
& MARKHOSTED
) ? " [hosted]" : ""));
514 fp
->flags
|= INC_BOUND(index
);
515 fp
->bound
[index
] = xp
;
516 if ((index
== INC_STANDARD
|| index
== INC_VENDOR
) && type
!= T_HEADER
&& !(fp
->flags
& INC_BOUND(INC_LOCAL
)))
518 fp
->flags
|= INC_BOUND(INC_LOCAL
);
519 fp
->bound
[INC_LOCAL
] = xp
;
524 xp
->flags
|= INC_SELF
|INC_EXISTS
;
525 if (flags
& SEARCH_INCLUDE
)
527 if ((pp
.prefix
= prefix
) || (pp
.prefix
= pp
.in
->prefix
))
528 message((-2, "search: %s: prefix=%s", xp
->name
, pp
.prefix
));
529 if (!(pp
.mode
& ALLMULTIPLE
))
531 if (xp
->guard
== INC_CLEAR
|| xp
== mp
)
532 xp
->guard
= INC_TEST
;
535 if ((pp
.state
& WARN
) && (pp
.mode
& (HOSTED
|MARKHOSTED
|RELAX
|PEDANTIC
)) == PEDANTIC
)
536 error(1, "%s: ignored -- already included", xp
->name
);
538 message((-3, "%s: ignored -- already included", xp
->name
));
539 xp
->guard
= fp
->guard
= INC_IGNORE
;
545 if (flags
& SEARCH_TEST
)
546 pp
.include
= xp
->name
;
550 pp
.include
= xp
->name
;
551 if ((pp
.mode
& (FILEDEPS
|INIT
)) == FILEDEPS
&& ((pp
.mode
& HEADERDEPS
) || !(pp
.mode
& MARKHOSTED
)) && !(xp
->flags
& INC_LISTED
))
553 xp
->flags
|= INC_LISTED
;
554 if ((pp
.column
+ strlen(xp
->name
)) >= COLUMN_MAX
)
556 sfprintf(pp
.filedeps
.sp
, " \\\n");
557 pp
.column
= COLUMN_TAB
;
562 pp
.column
+= sfprintf(pp
.filedeps
.sp
, "%c%s", index
, xp
->name
);
568 xp
->flags
|= INC_SELF
;
570 error(3, "%s: too many open files", fp
->name
);
571 else if (errno
!= ENOENT
&& errno
!= ENOTDIR
)
572 error(ERROR_SYSTEM
|1, "%s: cannot open file for reading", pp
.path
);
573 if (*fp
->name
== '/')
576 strcpy(pp
.path
, fp
->name
);
577 message((-2, "search: %s%s not found", (flags
& SEARCH_NEXT
) ? "next " : "", fp
->name
));
582 * search for an include file
583 * if (flags&SEARCH_INCLUDE) then
584 * if file found then open read file descriptor returned
585 * with pp.path set to the full path and
586 * pp.prefix set to the directory prefix
587 * otherwise 0 returned if file found but ignored
588 * otherwise -1 returned
590 * if file found then 0 returned
591 * otherwise -1 returned
595 ppsearch(char* file
, int type
, int flags
)
597 register struct ppfile
* fp
;
599 register struct ppdirs
* dp
;
606 char name
[MAXTOKEN
+ 1];
611 if (s
= strchr(file
, '\\'))
613 do *s
++ = '/'; while (s
= strchr(s
, '\\'));
621 for (cp
= pp
.chop
; cp
; cp
= cp
->next
)
622 if (strneq(file
, cp
->value
, cp
->op
))
624 if (cp
->value
[cp
->op
+ 1])
626 sfsprintf(name
, sizeof(name
) - 1, "%s%s", cp
->value
+ cp
->op
+ 1, file
+ cp
->op
);
627 message((-2, "search: %s -> %s", file
, name
));
630 else if (strchr(file
+ cp
->op
, '/'))
632 message((-2, "search: %s -> %s", file
, file
+ cp
->op
));
637 fp
= ppsetfile(file
);
638 while ((fp
->flags
& INC_MAPALL
) || (fp
->flags
& INC_MAPHOSTED
) && (pp
.mode
& HOSTED
) || (fp
->flags
& INC_MAPNOHOSTED
) && !(pp
.mode
& HOSTED
))
640 if (!(xp
= fp
->bound
[type
== T_HEADER
? INC_STANDARD
: INC_LOCAL
]) || xp
== fp
)
642 message((-1, "map: %s -> %s", fp
->name
, xp
->name
));
645 if ((fp
->flags
& INC_MAPNOLOCAL
) && (pp
.mode
& HOSTED
))
646 flags
|= SEARCH_HOSTED
;
648 flags
|= SEARCH_VENDOR
;
650 if (type
== T_HEADER
&& strneq(fp
->name
, "...", 3) && (!fp
->name
[3] || fp
->name
[3] == '/'))
652 if (fp
->name
[3] == '/')
657 n
= strlen(error_info
.file
);
658 m
= strlen(fp
->name
+ 4);
659 if (n
< m
|| !streq(fp
->name
+ 4, error_info
.file
+ n
- m
))
661 if ((fd
= ppsearch(fp
->name
+ 4, type
, flags
|SEARCH_TEST
)) < 0)
666 error_info
.file
= pp
.include
;
667 fd
= ppsearch(fp
->name
+ 4, type
, flags
|SEARCH_NEXT
);
671 file
= error_info
.file
+ n
- m
;
673 else if (file
= strrchr(error_info
.file
, '/'))
676 file
= error_info
.file
;
677 flags
|= SEARCH_NEXT
;
681 sfsprintf(name
, sizeof(name
) - 1, "%s/%s", pp
.in
->prefix
, file
);
682 fp
= ppsetfile(name
);
683 if ((fd
= ppsearch(fp
->name
, type
, flags
)) >= 0)
687 fp
= ppsetfile(file
);
688 return ppsearch(fp
->name
, type
, flags
);
690 else if ((flags
& SEARCH_INCLUDE
) && fp
->guard
== INC_IGNORE
)
692 strcpy(pp
.path
, fp
->name
);
693 message((-2, "%s: ignored", fp
->name
));
696 else if (!(flags
& SEARCH_NEXT
))
697 flags
|= SEARCH_SKIP
;
699 if (type
== T_HEADER
)
700 dp
= pp
.stddirs
->next
;
704 if (dp
== pp
.firstdir
)
707 * look in directory of including file first
710 if (error_info
.file
&& (s
= strrchr(error_info
.file
, '/')))
713 dp
->name
= ppsetfile(error_info
.file
)->name
;
719 else if (pp
.in
->prefix
&& pp
.lcldirs
!= pp
.firstdir
)
722 * look in prefix directory of including file first
725 if (*fp
->name
!= '/')
727 if ((s
= strchr(fp
->name
, '/')) && (fp
->name
[0]
728 != '.' || fp
->name
[1] != '.' || fp
->name
[2] != '/'))
731 if (!streq(fp
->name
, pp
.in
->prefix
))
740 sfsprintf(name
, sizeof(name
) - 1, "%s/%s", pp
.in
->prefix
, fp
->name
);
742 xp
= ppsetfile(name
);
743 if ((fd
= search(xp
, dp
, type
, flags
)) >= 0)
748 if ((fd
= search(fp
, dp
, type
, flags
)) < 0)
750 if ((pp
.option
& PLUSPLUS
) && file
!= pp
.tmpbuf
)
752 s
= file
+ strlen(file
);
753 while (s
> file
&& *--s
!= '/' && *s
!= '\\' && *s
!= '.');
756 sfsprintf(pp
.tmpbuf
, MAXTOKEN
, "%s.h", file
);
763 * hackery for msdos files viewed through unix
769 if (ppisid(file
[0]) && file
[1] == ':' && file
[2] == '/')
782 if ((flags
& (SEARCH_INCLUDE
|SEARCH_NEXT
)) == SEARCH_INCLUDE
)
784 if (!chop
&& pp
.chop
)
790 if (!(pp
.mode
& GENDEPS
))
792 if (!(pp
.option
& ALLPOSSIBLE
) || pp
.in
->prev
->prev
)
793 error(2, "%s: cannot find include file", file
);
795 else if (!(pp
.mode
& INIT
))
797 xp
= ppsetfile(file
);
798 if (!(xp
->flags
& INC_LISTED
))
800 xp
->flags
|= INC_LISTED
;
801 if ((pp
.column
+ strlen(file
)) >= COLUMN_MAX
)
803 sfprintf(pp
.filedeps
.sp
, " \\\n");
804 pp
.column
= COLUMN_TAB
;
809 pp
.column
+= sfprintf(pp
.filedeps
.sp
, "%c%s", index
, file
);