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