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