include.c revision 0eb10989
1/* $Xorg: include.c,v 1.4 2001/02/09 02:03:16 xorgcvs Exp $ */
2/*
3
4Copyright (c) 1993, 1994, 1998 The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26*/
27/* $XFree86: xc/config/makedepend/include.c,v 3.6 2001/04/29 23:25:02 tsi Exp $ */
28
29
30#include "def.h"
31
32extern struct	inclist	inclist[ MAXFILES ],
33			*inclistp, *inclistnext;
34extern char	*includedirs[ ],
35		**includedirsnext;
36extern char	*notdotdot[ ];
37extern boolean show_where_not;
38extern boolean warn_multiple;
39
40static boolean
41isdot(char *p)
42{
43	if(p && *p++ == '.' && *p++ == '\0')
44		return(TRUE);
45	return(FALSE);
46}
47
48static boolean
49isdotdot(char *p)
50{
51	if(p && *p++ == '.' && *p++ == '.' && *p++ == '\0')
52		return(TRUE);
53	return(FALSE);
54}
55
56static boolean
57issymbolic(char *dir, char *component)
58{
59#ifdef S_IFLNK
60	struct stat	st;
61	char	buf[ BUFSIZ ], **pp;
62
63	sprintf(buf, "%s%s%s", dir, *dir ? "/" : "", component);
64	for (pp=notdotdot; *pp; pp++)
65		if (strcmp(*pp, buf) == 0)
66			return (TRUE);
67	if (lstat(buf, &st) == 0
68	&& (st.st_mode & S_IFMT) == S_IFLNK) {
69		*pp++ = copy(buf);
70		if (pp >= &notdotdot[ MAXDIRS ])
71			fatalerr("out of .. dirs, increase MAXDIRS\n");
72		return(TRUE);
73	}
74#endif
75	return(FALSE);
76}
77
78/*
79 * Occasionally, pathnames are created that look like .../x/../y
80 * Any of the 'x/..' sequences within the name can be eliminated.
81 * (but only if 'x' is not a symbolic link!!)
82 */
83static void
84remove_dotdot(char *path)
85{
86	register char	*end, *from, *to, **cp;
87	char		*components[ MAXFILES ],
88			newpath[ BUFSIZ ];
89	boolean		component_copied;
90
91	/*
92	 * slice path up into components.
93	 */
94	to = newpath;
95	if (*path == '/')
96		*to++ = '/';
97	*to = '\0';
98	cp = components;
99	for (from=end=path; *end; end++)
100		if (*end == '/') {
101			while (*end == '/')
102				*end++ = '\0';
103			if (*from)
104				*cp++ = from;
105			from = end;
106		}
107	*cp++ = from;
108	*cp = NULL;
109
110	/*
111	 * Recursively remove all 'x/..' component pairs.
112	 */
113	cp = components;
114	while(*cp) {
115		if (!isdot(*cp) && !isdotdot(*cp) && isdotdot(*(cp+1))
116		    && !issymbolic(newpath, *cp))
117		{
118		    char **fp = cp + 2;
119		    char **tp = cp;
120
121		    do
122			*tp++ = *fp; /* move all the pointers down */
123		    while (*fp++);
124		    if (cp != components)
125			cp--;	/* go back and check for nested ".." */
126		} else {
127		    cp++;
128		}
129	}
130	/*
131	 * Concatenate the remaining path elements.
132	 */
133	cp = components;
134	component_copied = FALSE;
135	while(*cp) {
136		if (component_copied)
137			*to++ = '/';
138		component_copied = TRUE;
139		for (from = *cp; *from; )
140			*to++ = *from++;
141		*to = '\0';
142		cp++;
143	}
144	*to++ = '\0';
145
146	/*
147	 * copy the reconstituted path back to our pointer.
148	 */
149	strcpy(path, newpath);
150}
151
152/*
153 * Add an include file to the list of those included by 'file'.
154 */
155struct inclist *
156newinclude(char *newfile, char *incstring)
157{
158	register struct inclist	*ip;
159
160	/*
161	 * First, put this file on the global list of include files.
162	 */
163	ip = inclistp++;
164	if (inclistp == inclist + MAXFILES - 1)
165		fatalerr("out of space: increase MAXFILES\n");
166	ip->i_file = copy(newfile);
167
168	if (incstring == NULL)
169		ip->i_incstring = ip->i_file;
170	else
171		ip->i_incstring = copy(incstring);
172
173	inclistnext = inclistp;
174	return(ip);
175}
176
177void
178included_by(struct inclist *ip, struct inclist *newfile)
179{
180	register int i;
181
182	if (ip == NULL)
183		return;
184	/*
185	 * Put this include file (newfile) on the list of files included
186	 * by 'file'.  If 'file' is NULL, then it is not an include
187	 * file itself (i.e. was probably mentioned on the command line).
188	 * If it is already on the list, don't stick it on again.
189	 */
190	if (ip->i_list == NULL) {
191		ip->i_list = (struct inclist **)
192			malloc(sizeof(struct inclist *) * ++ip->i_listlen);
193		ip->i_merged = (boolean *)
194		    malloc(sizeof(boolean) * ip->i_listlen);
195	} else {
196		for (i=0; i<ip->i_listlen; i++)
197			if (ip->i_list[ i ] == newfile) {
198			    i = strlen(newfile->i_file);
199			    if (!(ip->i_flags & INCLUDED_SYM) &&
200				!(i > 2 &&
201				  newfile->i_file[i-1] == 'c' &&
202				  newfile->i_file[i-2] == '.'))
203			    {
204				/* only bitch if ip has */
205				/* no #include SYMBOL lines  */
206				/* and is not a .c file */
207				if (warn_multiple)
208				{
209					warning("%s includes %s more than once!\n",
210						ip->i_file, newfile->i_file);
211					warning1("Already have\n");
212					for (i=0; i<ip->i_listlen; i++)
213						warning1("\t%s\n", ip->i_list[i]->i_file);
214				}
215			    }
216			    return;
217			}
218		ip->i_list = (struct inclist **) realloc(ip->i_list,
219			sizeof(struct inclist *) * ++ip->i_listlen);
220		ip->i_merged = (boolean *)
221		    realloc(ip->i_merged, sizeof(boolean) * ip->i_listlen);
222	}
223	ip->i_list[ ip->i_listlen-1 ] = newfile;
224	ip->i_merged[ ip->i_listlen-1 ] = FALSE;
225}
226
227void
228inc_clean (void)
229{
230	register struct inclist *ip;
231
232	for (ip = inclist; ip < inclistp; ip++) {
233		ip->i_flags &= ~MARKED;
234	}
235}
236
237struct inclist *
238inc_path(char *file, char *include, int type)
239{
240	static char		path[ BUFSIZ ];
241	register char		**pp, *p;
242	register struct inclist	*ip;
243	struct stat		st;
244
245	/*
246	 * Check all previously found include files for a path that
247	 * has already been expanded.
248	 */
249	if ((type == INCLUDE) || (type == INCLUDEDOT))
250		inclistnext = inclist;
251	ip = inclistnext;
252
253	for (; ip->i_file; ip++) {
254		if ((strcmp(ip->i_incstring, include) == 0) &&
255		    !(ip->i_flags & INCLUDED_SYM)) {
256			inclistnext = ip + 1;
257			return ip;
258		}
259	}
260
261	if (inclistnext == inclist) {
262		/*
263		 * If the path was surrounded by "" or is an absolute path,
264		 * then check the exact path provided.
265		 */
266		if ((type == INCLUDEDOT) ||
267		    (type == INCLUDENEXTDOT) ||
268		    (*include == '/')) {
269			if (stat(include, &st) == 0)
270				return newinclude(include, include);
271			if (show_where_not)
272				warning1("\tnot in %s\n", include);
273		}
274
275		/*
276		 * If the path was surrounded by "" see if this include file is
277		 * in the directory of the file being parsed.
278		 */
279		if ((type == INCLUDEDOT) || (type == INCLUDENEXTDOT)) {
280			for (p=file+strlen(file); p>file; p--)
281				if (*p == '/')
282					break;
283			if (p == file) {
284				strcpy(path, include);
285			} else {
286				strncpy(path, file, (p-file) + 1);
287				path[ (p-file) + 1 ] = '\0';
288				strcpy(path + (p-file) + 1, include);
289			}
290			remove_dotdot(path);
291			if (stat(path, &st) == 0)
292				return newinclude(path, include);
293			if (show_where_not)
294				warning1("\tnot in %s\n", path);
295		}
296	}
297
298	/*
299	 * Check the include directories specified.  Standard include dirs
300	 * should be at the end.
301	 */
302	if ((type == INCLUDE) || (type == INCLUDEDOT))
303		includedirsnext = includedirs;
304	pp = includedirsnext;
305
306	for (; *pp; pp++) {
307		sprintf(path, "%s/%s", *pp, include);
308		remove_dotdot(path);
309		if (stat(path, &st) == 0) {
310			includedirsnext = pp + 1;
311			return newinclude(path, include);
312		}
313		if (show_where_not)
314			warning1("\tnot in %s\n", path);
315	}
316
317	return NULL;
318}
319