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