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