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