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