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