include.c revision e4c0bf4d
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 30extern struct inclist inclist[ MAXFILES ], 31 *inclistp, *inclistnext; 32extern const char *includedirs[ ], 33 **includedirsnext; 34extern char *notdotdot[ ]; 35extern boolean show_where_not; 36extern boolean warn_multiple; 37 38static boolean 39isdot(const char *p) 40{ 41 if(p && *p++ == '.' && *p++ == '\0') 42 return(TRUE); 43 return(FALSE); 44} 45 46static boolean 47isdotdot(const char *p) 48{ 49 if(p && *p++ == '.' && *p++ == '.' && *p++ == '\0') 50 return(TRUE); 51 return(FALSE); 52} 53 54static boolean 55issymbolic(const char *dir, const char *component) 56{ 57#ifdef S_IFLNK 58 struct stat st; 59 char buf[ BUFSIZ ], **pp; 60 61 sprintf(buf, "%s%s%s", dir, *dir ? "/" : "", component); 62 for (pp=notdotdot; *pp; pp++) 63 if (strcmp(*pp, buf) == 0) 64 return (TRUE); 65 if (lstat(buf, &st) == 0 66 && (st.st_mode & S_IFMT) == S_IFLNK) { 67 *pp++ = copy(buf); 68 if (pp >= ¬dotdot[ MAXDIRS ]) 69 fatalerr("out of .. dirs, increase MAXDIRS\n"); 70 return(TRUE); 71 } 72#endif 73 return(FALSE); 74} 75 76/* 77 * Occasionally, pathnames are created that look like .../x/../y 78 * Any of the 'x/..' sequences within the name can be eliminated. 79 * (but only if 'x' is not a symbolic link!!) 80 */ 81static void 82remove_dotdot(char *path) 83{ 84 register char *end, *from, *to, **cp; 85 char *components[ MAXFILES ], 86 newpath[ BUFSIZ ]; 87 boolean component_copied; 88 89 /* 90 * slice path up into components. 91 */ 92 to = newpath; 93 if (*path == '/') 94 *to++ = '/'; 95 *to = '\0'; 96 cp = components; 97 for (from=end=path; *end; end++) 98 if (*end == '/') { 99 while (*end == '/') 100 *end++ = '\0'; 101 if (*from) 102 *cp++ = from; 103 from = end; 104 } 105 *cp++ = from; 106 *cp = NULL; 107 108 /* 109 * Recursively remove all 'x/..' component pairs. 110 */ 111 cp = components; 112 while(*cp) { 113 if (!isdot(*cp) && !isdotdot(*cp) && isdotdot(*(cp+1)) 114 && !issymbolic(newpath, *cp)) 115 { 116 char **fp = cp + 2; 117 char **tp = cp; 118 119 do 120 *tp++ = *fp; /* move all the pointers down */ 121 while (*fp++); 122 if (cp != components) 123 cp--; /* go back and check for nested ".." */ 124 } else { 125 cp++; 126 } 127 } 128 /* 129 * Concatenate the remaining path elements. 130 */ 131 cp = components; 132 component_copied = FALSE; 133 while(*cp) { 134 if (component_copied) 135 *to++ = '/'; 136 component_copied = TRUE; 137 for (from = *cp; *from; ) 138 *to++ = *from++; 139 *to = '\0'; 140 cp++; 141 } 142 *to++ = '\0'; 143 144 /* 145 * copy the reconstituted path back to our pointer. 146 */ 147 strcpy(path, newpath); 148} 149 150/* 151 * Add an include file to the list of those included by 'file'. 152 */ 153struct inclist * 154newinclude(const char *newfile, const char *incstring) 155{ 156 register struct inclist *ip; 157 158 /* 159 * First, put this file on the global list of include files. 160 */ 161 ip = inclistp++; 162 if (inclistp == inclist + MAXFILES - 1) 163 fatalerr("out of space: increase MAXFILES\n"); 164 ip->i_file = copy(newfile); 165 166 if (incstring == NULL) 167 ip->i_incstring = ip->i_file; 168 else 169 ip->i_incstring = copy(incstring); 170 171 inclistnext = inclistp; 172 return(ip); 173} 174 175void 176included_by(struct inclist *ip, struct inclist *newfile) 177{ 178 register int i; 179 180 if (ip == NULL) 181 return; 182 /* 183 * Put this include file (newfile) on the list of files included 184 * by 'file'. If 'file' is NULL, then it is not an include 185 * file itself (i.e. was probably mentioned on the command line). 186 * If it is already on the list, don't stick it on again. 187 */ 188 if (ip->i_list == NULL) { 189 ip->i_list = (struct inclist **) 190 malloc(sizeof(struct inclist *) * ++ip->i_listlen); 191 ip->i_merged = (boolean *) 192 malloc(sizeof(boolean) * ip->i_listlen); 193 } else { 194 for (i=0; i<ip->i_listlen; i++) 195 if (ip->i_list[ i ] == newfile) { 196 i = strlen(newfile->i_file); 197 if (!(ip->i_flags & INCLUDED_SYM) && 198 !(i > 2 && 199 newfile->i_file[i-1] == 'c' && 200 newfile->i_file[i-2] == '.')) 201 { 202 /* only bitch if ip has */ 203 /* no #include SYMBOL lines */ 204 /* and is not a .c file */ 205 if (warn_multiple) 206 { 207 warning("%s includes %s more than once!\n", 208 ip->i_file, newfile->i_file); 209 warning1("Already have\n"); 210 for (i=0; i<ip->i_listlen; i++) 211 warning1("\t%s\n", ip->i_list[i]->i_file); 212 } 213 } 214 return; 215 } 216 ip->i_list = (struct inclist **) realloc(ip->i_list, 217 sizeof(struct inclist *) * ++ip->i_listlen); 218 ip->i_merged = (boolean *) 219 realloc(ip->i_merged, sizeof(boolean) * ip->i_listlen); 220 } 221 ip->i_list[ ip->i_listlen-1 ] = newfile; 222 ip->i_merged[ ip->i_listlen-1 ] = FALSE; 223} 224 225void 226inc_clean (void) 227{ 228 register struct inclist *ip; 229 230 for (ip = inclist; ip < inclistp; ip++) { 231 ip->i_flags &= ~MARKED; 232 } 233} 234 235struct inclist * 236inc_path(const char *file, const char *include, int type) 237{ 238 static char path[ BUFSIZ ]; 239 register const char **pp, *p; 240 register struct inclist *ip; 241 struct stat st; 242 243 /* 244 * Check all previously found include files for a path that 245 * has already been expanded. 246 */ 247 if ((type == INCLUDE) || (type == INCLUDEDOT)) 248 inclistnext = inclist; 249 ip = inclistnext; 250 251 for (; ip->i_file; ip++) { 252 if ((strcmp(ip->i_incstring, include) == 0) && 253 !(ip->i_flags & INCLUDED_SYM)) { 254 inclistnext = ip + 1; 255 return ip; 256 } 257 } 258 259 if (inclistnext == inclist) { 260 /* 261 * If the path was surrounded by "" or is an absolute path, 262 * then check the exact path provided. 263 */ 264 if ((type == INCLUDEDOT) || 265 (type == INCLUDENEXTDOT) || 266 (*include == '/')) { 267 if (stat(include, &st) == 0 && !S_ISDIR(st.st_mode)) 268 return newinclude(include, include); 269 if (show_where_not) 270 warning1("\tnot in %s\n", include); 271 } 272 273 /* 274 * If the path was surrounded by "" see if this include file is 275 * in the directory of the file being parsed. 276 */ 277 if ((type == INCLUDEDOT) || (type == INCLUDENEXTDOT)) { 278 for (p=file+strlen(file); p>file; p--) 279 if (*p == '/') 280 break; 281 if (p == file) { 282 strcpy(path, include); 283 } else { 284 strncpy(path, file, (p-file) + 1); 285 path[ (p-file) + 1 ] = '\0'; 286 strcpy(path + (p-file) + 1, include); 287 } 288 remove_dotdot(path); 289 if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) 290 return newinclude(path, include); 291 if (show_where_not) 292 warning1("\tnot in %s\n", path); 293 } 294 } 295 296 /* 297 * Check the include directories specified. Standard include dirs 298 * should be at the end. 299 */ 300 if ((type == INCLUDE) || (type == INCLUDEDOT)) 301 includedirsnext = includedirs; 302 pp = includedirsnext; 303 304 for (; *pp; pp++) { 305 sprintf(path, "%s/%s", *pp, include); 306 remove_dotdot(path); 307 if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) { 308 includedirsnext = pp + 1; 309 return newinclude(path, include); 310 } 311 if (show_where_not) 312 warning1("\tnot in %s\n", path); 313 } 314 315 return NULL; 316} 317