|
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 } |