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