include.c revision ee0db89d
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 225/* 226 * Return full path for the "include" file of the given "type", 227 * which may be found relative to the source file "file". 228 */ 229static const char * 230find_full_inc_path(const char *file, const char *include, int type) 231{ 232 static char path[ BUFSIZ ]; 233 register const char **pp, *p; 234 struct stat st; 235 236 if (inclistnext == inclist) { 237 /* 238 * If the path was surrounded by "" or is an absolute path, 239 * then check the exact path provided. 240 */ 241 if ((type == INCLUDEDOT) || 242 (type == INCLUDENEXTDOT) || 243 (*include == '/')) { 244 if (stat(include, &st) == 0 && !S_ISDIR(st.st_mode)) 245 return include; 246 if (show_where_not) 247 warning1("\tnot in %s\n", include); 248 } 249 250 /* 251 * If the path was surrounded by "" see if this include file is 252 * in the directory of the file being parsed. 253 */ 254 if ((type == INCLUDEDOT) || (type == INCLUDENEXTDOT)) { 255 for (p=file+strlen(file); p>file; p--) 256 if (*p == '/') 257 break; 258 if (p == file) { 259 strcpy(path, include); 260 } else { 261 strncpy(path, file, (p-file) + 1); 262 path[ (p-file) + 1 ] = '\0'; 263 strcpy(path + (p-file) + 1, include); 264 } 265 remove_dotdot(path); 266 if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) 267 return path; 268 if (show_where_not) 269 warning1("\tnot in %s\n", path); 270 } 271 } 272 273 /* 274 * Check the include directories specified. Standard include dirs 275 * should be at the end. 276 */ 277 if ((type == INCLUDE) || (type == INCLUDEDOT)) 278 includedirsnext = includedirs; 279 pp = includedirsnext; 280 281 for (; *pp; pp++) { 282 snprintf(path, sizeof(path), "%s/%s", *pp, include); 283 remove_dotdot(path); 284 if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) { 285 includedirsnext = pp + 1; 286 return path; 287 } 288 if (show_where_not) 289 warning1("\tnot in %s\n", path); 290 } 291 292 return NULL; 293} 294 295struct inclist * 296inc_path(const char *file, const char *include, int type) 297{ 298 const char *fp; 299 struct inclist *ip; 300 char r_include[PATHMAX+1]; 301 302 /* 303 * Check all previously found include files for a path that 304 * has already been expanded. 305 */ 306 if ((type == INCLUDE) || (type == INCLUDEDOT)) 307 inclistnext = inclist; 308 ip = inclistnext; 309 310 fp = find_full_inc_path(file, include, type); 311 if (fp == NULL) 312 return NULL; 313 if (realpath(fp, r_include) == NULL) 314 return NULL; 315 316 for (; ip->i_file; ip++) { 317 if ((strcmp(ip->i_incstring, include) == 0) && 318 !(ip->i_flags & INCLUDED_SYM)) { 319 /* 320 * Same filename but same file ? 321 */ 322 char r_saved_path[PATHMAX+1]; 323 if (realpath(ip->i_file, r_saved_path) == NULL) 324 continue; 325 if (!strcmp(r_include, r_saved_path)) { 326 inclistnext = ip + 1; 327 return ip; 328 } 329 } 330 } 331 332 return newinclude(fp, include); 333} 334