include.c revision 079e7944
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 inclistnext = ip + 1; 245 return ip; 246 } 247 } 248 249 if (inclistnext == inclist) { 250 /* 251 * If the path was surrounded by "" or is an absolute path, 252 * then check the exact path provided. 253 */ 254 if ((type == INCLUDEDOT) || 255 (type == INCLUDENEXTDOT) || 256 (*include == '/')) { 257 if (stat(include, &st) == 0 && !S_ISDIR(st.st_mode)) 258 return newinclude(include, include); 259 if (show_where_not) 260 warning1("\tnot in %s\n", include); 261 } 262 263 /* 264 * If the path was surrounded by "" see if this include file is 265 * in the directory of the file being parsed. 266 */ 267 if ((type == INCLUDEDOT) || (type == INCLUDENEXTDOT)) { 268 for (p=file+strlen(file); p>file; p--) 269 if (*p == '/') 270 break; 271 if (p == file) { 272 strcpy(path, include); 273 } else { 274 strncpy(path, file, (p-file) + 1); 275 path[ (p-file) + 1 ] = '\0'; 276 strcpy(path + (p-file) + 1, include); 277 } 278 remove_dotdot(path); 279 if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) 280 return newinclude(path, include); 281 if (show_where_not) 282 warning1("\tnot in %s\n", path); 283 } 284 } 285 286 /* 287 * Check the include directories specified. Standard include dirs 288 * should be at the end. 289 */ 290 if ((type == INCLUDE) || (type == INCLUDEDOT)) 291 includedirsnext = includedirs; 292 pp = includedirsnext; 293 294 for (; *pp; pp++) { 295 snprintf(path, sizeof(path), "%s/%s", *pp, include); 296 remove_dotdot(path); 297 if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) { 298 includedirsnext = pp + 1; 299 return newinclude(path, include); 300 } 301 if (show_where_not) 302 warning1("\tnot in %s\n", path); 303 } 304 305 return NULL; 306} 307