michael@0: /* $Xorg: include.c,v 1.4 2001/02/09 02:03:16 xorgcvs Exp $ */ michael@0: /* michael@0: michael@0: Copyright (c) 1993, 1994, 1998 The Open Group michael@0: michael@0: Permission to use, copy, modify, distribute, and sell this software and its michael@0: documentation for any purpose is hereby granted without fee, provided that michael@0: the above copyright notice appear in all copies and that both that michael@0: copyright notice and this permission notice appear in supporting michael@0: documentation. michael@0: michael@0: The above copyright notice and this permission notice shall be included in michael@0: all copies or substantial portions of the Software. michael@0: michael@0: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR michael@0: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, michael@0: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE michael@0: OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN michael@0: AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN michael@0: CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. michael@0: michael@0: Except as contained in this notice, the name of The Open Group shall not be michael@0: used in advertising or otherwise to promote the sale, use or other dealings michael@0: in this Software without prior written authorization from The Open Group. michael@0: michael@0: */ michael@0: /* $XFree86: xc/config/makedepend/include.c,v 3.7 2001/12/14 19:53:20 dawes Exp $ */ michael@0: michael@0: michael@0: #include "def.h" michael@0: michael@0: #ifdef _MSC_VER michael@0: #include michael@0: static int michael@0: does_file_exist(char *file) michael@0: { michael@0: WIN32_FILE_ATTRIBUTE_DATA data; michael@0: BOOL b = GetFileAttributesExA(file, GetFileExInfoStandard, &data); michael@0: if (!b) michael@0: return 0; michael@0: return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0; michael@0: } michael@0: #else michael@0: static int michael@0: does_file_exist(char *file) michael@0: { michael@0: struct stat sb; michael@0: return stat(file, &sb) == 0 && !S_ISDIR(sb.st_mode); michael@0: } michael@0: #endif michael@0: michael@0: extern struct inclist inclist[ MAXFILES ], michael@0: *inclistp, *inclistnext; michael@0: extern char *includedirs[ ], michael@0: **includedirsnext; michael@0: extern char *notdotdot[ ]; michael@0: extern boolean show_where_not; michael@0: extern boolean warn_multiple; michael@0: michael@0: static boolean michael@0: isdot(char *p) michael@0: { michael@0: if(p && *p++ == '.' && *p++ == '\0') michael@0: return(TRUE); michael@0: return(FALSE); michael@0: } michael@0: michael@0: static boolean michael@0: isdotdot(char *p) michael@0: { michael@0: if(p && *p++ == '.' && *p++ == '.' && *p++ == '\0') michael@0: return(TRUE); michael@0: return(FALSE); michael@0: } michael@0: michael@0: static boolean michael@0: issymbolic(char *dir, char *component) michael@0: { michael@0: #ifdef S_IFLNK michael@0: struct stat st; michael@0: char buf[ BUFSIZ ], **pp; michael@0: michael@0: sprintf(buf, "%s%s%s", dir, *dir ? "/" : "", component); michael@0: for (pp=notdotdot; *pp; pp++) michael@0: if (strcmp(*pp, buf) == 0) michael@0: return (TRUE); michael@0: if (lstat(buf, &st) == 0 michael@0: && (st.st_mode & S_IFMT) == S_IFLNK) { michael@0: *pp++ = copy(buf); michael@0: if (pp >= ¬dotdot[ MAXDIRS ]) michael@0: fatalerr("out of .. dirs, increase MAXDIRS\n"); michael@0: return(TRUE); michael@0: } michael@0: #endif michael@0: return(FALSE); michael@0: } michael@0: michael@0: /* michael@0: * Occasionally, pathnames are created that look like .../x/../y michael@0: * Any of the 'x/..' sequences within the name can be eliminated. michael@0: * (but only if 'x' is not a symbolic link!!) michael@0: */ michael@0: static void michael@0: remove_dotdot(char *path) michael@0: { michael@0: register char *end, *from, *to, **cp; michael@0: char *components[ MAXFILES ], michael@0: newpath[ BUFSIZ ]; michael@0: boolean component_copied; michael@0: michael@0: /* michael@0: * slice path up into components. michael@0: */ michael@0: to = newpath; michael@0: if (*path == '/') michael@0: *to++ = '/'; michael@0: *to = '\0'; michael@0: cp = components; michael@0: for (from=end=path; *end; end++) michael@0: if (*end == '/') { michael@0: while (*end == '/') michael@0: *end++ = '\0'; michael@0: if (*from) michael@0: *cp++ = from; michael@0: from = end; michael@0: } michael@0: *cp++ = from; michael@0: *cp = NULL; michael@0: michael@0: /* michael@0: * Recursively remove all 'x/..' component pairs. michael@0: */ michael@0: cp = components; michael@0: while(*cp) { michael@0: if (!isdot(*cp) && !isdotdot(*cp) && isdotdot(*(cp+1)) michael@0: && !issymbolic(newpath, *cp)) michael@0: { michael@0: char **fp = cp + 2; michael@0: char **tp = cp; michael@0: michael@0: do michael@0: *tp++ = *fp; /* move all the pointers down */ michael@0: while (*fp++); michael@0: if (cp != components) michael@0: cp--; /* go back and check for nested ".." */ michael@0: } else { michael@0: cp++; michael@0: } michael@0: } michael@0: /* michael@0: * Concatenate the remaining path elements. michael@0: */ michael@0: cp = components; michael@0: component_copied = FALSE; michael@0: while(*cp) { michael@0: if (component_copied) michael@0: *to++ = '/'; michael@0: component_copied = TRUE; michael@0: for (from = *cp; *from; ) michael@0: *to++ = *from++; michael@0: *to = '\0'; michael@0: cp++; michael@0: } michael@0: *to++ = '\0'; michael@0: michael@0: /* michael@0: * copy the reconstituted path back to our pointer. michael@0: */ michael@0: strcpy(path, newpath); michael@0: } michael@0: michael@0: /* michael@0: * Add an include file to the list of those included by 'file'. michael@0: */ michael@0: struct inclist * michael@0: newinclude(char *newfile, char *incstring) michael@0: { michael@0: register struct inclist *ip; michael@0: michael@0: /* michael@0: * First, put this file on the global list of include files. michael@0: */ michael@0: ip = inclistp++; michael@0: if (inclistp == inclist + MAXFILES - 1) michael@0: fatalerr("out of space: increase MAXFILES\n"); michael@0: ip->i_file = copy(newfile); michael@0: michael@0: if (incstring == NULL) michael@0: ip->i_incstring = ip->i_file; michael@0: else michael@0: ip->i_incstring = copy(incstring); michael@0: michael@0: inclistnext = inclistp; michael@0: return(ip); michael@0: } michael@0: michael@0: void michael@0: included_by(struct inclist *ip, struct inclist *newfile) michael@0: { michael@0: register int i; michael@0: michael@0: if (ip == NULL) michael@0: return; michael@0: /* michael@0: * Put this include file (newfile) on the list of files included michael@0: * by 'file'. If 'file' is NULL, then it is not an include michael@0: * file itself (i.e. was probably mentioned on the command line). michael@0: * If it is already on the list, don't stick it on again. michael@0: */ michael@0: if (ip->i_list == NULL) { michael@0: ip->i_list = (struct inclist **) michael@0: malloc(sizeof(struct inclist *) * ++ip->i_listlen); michael@0: ip->i_merged = (boolean *) michael@0: malloc(sizeof(boolean) * ip->i_listlen); michael@0: } else { michael@0: for (i=0; ii_listlen; i++) michael@0: if (ip->i_list[ i ] == newfile) { michael@0: i = strlen(newfile->i_file); michael@0: if (!(ip->i_flags & INCLUDED_SYM) && michael@0: !(i > 2 && michael@0: newfile->i_file[i-1] == 'c' && michael@0: newfile->i_file[i-2] == '.')) michael@0: { michael@0: /* only bitch if ip has */ michael@0: /* no #include SYMBOL lines */ michael@0: /* and is not a .c file */ michael@0: if (warn_multiple) michael@0: { michael@0: warning("%s includes %s more than once!\n", michael@0: ip->i_file, newfile->i_file); michael@0: warning1("Already have\n"); michael@0: for (i=0; ii_listlen; i++) michael@0: warning1("\t%s\n", ip->i_list[i]->i_file); michael@0: } michael@0: } michael@0: return; michael@0: } michael@0: ip->i_list = (struct inclist **) realloc(ip->i_list, michael@0: sizeof(struct inclist *) * ++ip->i_listlen); michael@0: ip->i_merged = (boolean *) michael@0: realloc(ip->i_merged, sizeof(boolean) * ip->i_listlen); michael@0: } michael@0: ip->i_list[ ip->i_listlen-1 ] = newfile; michael@0: ip->i_merged[ ip->i_listlen-1 ] = FALSE; michael@0: } michael@0: michael@0: void michael@0: inc_clean (void) michael@0: { michael@0: register struct inclist *ip; michael@0: michael@0: for (ip = inclist; ip < inclistp; ip++) { michael@0: ip->i_flags &= ~MARKED; michael@0: } michael@0: } michael@0: michael@0: struct inclist * michael@0: inc_path(char *file, char *include, int type) michael@0: { michael@0: static char path[ BUFSIZ ]; michael@0: register char **pp, *p; michael@0: register struct inclist *ip; michael@0: michael@0: /* michael@0: * Check all previously found include files for a path that michael@0: * has already been expanded. michael@0: */ michael@0: if ((type == INCLUDE) || (type == INCLUDEDOT)) michael@0: inclistnext = inclist; michael@0: ip = inclistnext; michael@0: michael@0: for (; ip->i_file; ip++) { michael@0: if ((strcmp(ip->i_incstring, include) == 0) && michael@0: !(ip->i_flags & INCLUDED_SYM)) { michael@0: inclistnext = ip + 1; michael@0: return ip; michael@0: } michael@0: } michael@0: michael@0: if (inclistnext == inclist) { michael@0: /* michael@0: * If the path was surrounded by "" or is an absolute path, michael@0: * then check the exact path provided. michael@0: */ michael@0: if ((type == INCLUDEDOT) || michael@0: (type == INCLUDENEXTDOT) || michael@0: (*include == '/')) { michael@0: if (does_file_exist(include)) michael@0: return newinclude(include, include); michael@0: if (show_where_not) michael@0: warning1("\tnot in %s\n", include); michael@0: } michael@0: michael@0: /* michael@0: * If the path was surrounded by "" see if this include file is michael@0: * in the directory of the file being parsed. michael@0: */ michael@0: if ((type == INCLUDEDOT) || (type == INCLUDENEXTDOT)) { michael@0: for (p=file+strlen(file); p>file; p--) michael@0: if (*p == '/') michael@0: break; michael@0: if (p == file) { michael@0: strcpy(path, include); michael@0: } else { michael@0: strncpy(path, file, (p-file) + 1); michael@0: path[ (p-file) + 1 ] = '\0'; michael@0: strcpy(path + (p-file) + 1, include); michael@0: } michael@0: remove_dotdot(path); michael@0: if (does_file_exist(path)) michael@0: return newinclude(path, include); michael@0: if (show_where_not) michael@0: warning1("\tnot in %s\n", path); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Check the include directories specified. Standard include dirs michael@0: * should be at the end. michael@0: */ michael@0: if ((type == INCLUDE) || (type == INCLUDEDOT)) michael@0: includedirsnext = includedirs; michael@0: pp = includedirsnext; michael@0: michael@0: for (; *pp; pp++) { michael@0: sprintf(path, "%s/%s", *pp, include); michael@0: remove_dotdot(path); michael@0: if (does_file_exist(path)) { michael@0: includedirsnext = pp + 1; michael@0: return newinclude(path, include); michael@0: } michael@0: if (show_where_not) michael@0: warning1("\tnot in %s\n", path); michael@0: } michael@0: michael@0: return NULL; michael@0: }