diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c6165632a63..bb179c6733a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2001-04-06 Neil Booth + + * configure.in: Add check for lstat. + * configure, config.in: Regenerate. + * cppinit.c (append_include_chain): Make empty path ".". + * cpplib.c (do_line): Don't simplify #line paths. + * cppfiles.c (remove_component_p): New function. + (find_or_create_entry): Acknowledge stat () errors during + path simplification. + (handle_missing_header): Don't simplify paths. + (_cpp_simplify_pathname): Don't simplify VMS paths. Return + the empty path untouched. Don't leave a trailing '/'. + 2001-04-06 Benjamin Kosnik * cppdefault.c (GPLUSPLUS_BACKWARD_INCLUDE_DIR): Add. diff --git a/gcc/config.in b/gcc/config.in index 7af8d1e818e..bc19ffe2642 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -134,6 +134,9 @@ /* Define if you have the kill function. */ #undef HAVE_KILL +/* Define if you have the lstat function. */ +#undef HAVE_LSTAT + /* Define if you have the munmap function. */ #undef HAVE_MUNMAP diff --git a/gcc/configure b/gcc/configure index 8b0d1b8ef7f..20383fec298 100755 --- a/gcc/configure +++ b/gcc/configure @@ -3102,7 +3102,7 @@ fi for ac_func in strtoul bsearch popen \ strchr strrchr kill getrlimit setrlimit atoll atoq \ sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \ - fputs_unlocked getrusage iconv nl_langinfo + fputs_unlocked getrusage iconv nl_langinfo lstat do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:3109: checking for $ac_func" >&5 diff --git a/gcc/configure.in b/gcc/configure.in index ca356f30cc3..1e5f4088964 100644 --- a/gcc/configure.in +++ b/gcc/configure.in @@ -547,7 +547,7 @@ dnl gcc_AC_C_ENUM_BF_UNSIGNED AC_CHECK_FUNCS(strtoul bsearch popen \ strchr strrchr kill getrlimit setrlimit atoll atoq \ sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \ - fputs_unlocked getrusage iconv nl_langinfo) + fputs_unlocked getrusage iconv nl_langinfo lstat) AC_CHECK_TYPE(ssize_t, int) diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c index bff04ae5326..e242e920f22 100644 --- a/gcc/cppfiles.c +++ b/gcc/cppfiles.c @@ -101,6 +101,7 @@ static int report_missing_guard PARAMS ((splay_tree_node, void *)); static splay_tree_node find_or_create_entry PARAMS ((cpp_reader *, const char *)); static void handle_missing_header PARAMS ((cpp_reader *, const char *, int)); +static int remove_component_p PARAMS ((const char *)); /* Set up the splay tree we use to store information about all the file names seen in this compilation. We also have entries for each @@ -155,7 +156,8 @@ _cpp_never_reread (file) } /* Lookup a filename, which is simplified after making a copy, and - create an entry if none exists. */ + create an entry if none exists. errno is nonzero iff a (reported) + stat() error occurred during simplification. */ static splay_tree_node find_or_create_entry (pfile, fname) cpp_reader *pfile; @@ -208,6 +210,9 @@ open_file (pfile, filename) splay_tree_node nd = find_or_create_entry (pfile, filename); struct include_file *file = (struct include_file *) nd->value; + if (errno) + file->fd = -2; + /* Don't retry opening if we failed previously. */ if (file->fd == -2) return 0; @@ -643,7 +648,6 @@ handle_missing_header (pfile, fname, angle_brackets) p[len++] = '/'; } memcpy (p + len, fname, fname_len + 1); - _cpp_simplify_pathname (p); deps_add_dep (pfile->deps, p); } } @@ -1006,6 +1010,26 @@ remap_filename (pfile, name, loc) return name; } +/* Returns true if it is safe to remove the final component of path, + when it is followed by a ".." component. We use lstat to avoid + symlinks if we have it. If not, we can still catch errors with + stat (). */ +static int +remove_component_p (path) + const char *path; +{ + struct stat s; + int result; + +#ifdef HAVE_LSTAT + result = lstat (path, &s); +#else + result = stat (path, &s); +#endif + + return result == 0 && S_ISDIR (s.st_mode); +} + /* Simplify a path name in place, deleting redundant components. This reduces OS overhead and guarantees that equivalent paths compare the same (modulo symlinks). @@ -1017,124 +1041,122 @@ remap_filename (pfile, name, loc) /../quux /quux //quux //quux (POSIX allows leading // as a namespace escape) - Guarantees no trailing slashes. All transforms reduce the length - of the string. Returns PATH; - */ + Guarantees no trailing slashes. All transforms reduce the length + of the string. Returns PATH. errno is 0 if no error occurred; + nonzero if an error occurred when using stat () or lstat (). */ + char * _cpp_simplify_pathname (path) char *path; { - char *from, *to; - char *base; - int absolute = 0; +#ifndef VMS + char *from, *to; + char *base, *orig_base; + int absolute = 0; + + errno = 0; + /* Don't overflow the empty path by putting a '.' in it below. */ + if (*path == '\0') + return path; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) - /* Convert all backslashes to slashes. */ - for (from = path; *from; from++) - if (*from == '\\') *from = '/'; + /* Convert all backslashes to slashes. */ + for (from = path; *from; from++) + if (*from == '\\') *from = '/'; - /* Skip over leading drive letter if present. */ - if (ISALPHA (path[0]) && path[1] == ':') - from = to = &path[2]; - else - from = to = path; -#else + /* Skip over leading drive letter if present. */ + if (ISALPHA (path[0]) && path[1] == ':') + from = to = &path[2]; + else from = to = path; +#else + from = to = path; #endif - /* Remove redundant initial /s. */ - if (*from == '/') + /* Remove redundant leading /s. */ + if (*from == '/') { - absolute = 1; - to++; + absolute = 1; + to++; + from++; + if (*from == '/') + { + if (*++from == '/') + /* 3 or more initial /s are equivalent to 1 /. */ + while (*++from == '/'); + else + /* On some hosts // differs from /; Posix allows this. */ + to++; + } + } + + base = orig_base = to; + for (;;) + { + int move_base = 0; + + while (*from == '/') from++; - if (*from == '/') - { - if (*++from == '/') - /* 3 or more initial /s are equivalent to 1 /. */ - while (*++from == '/'); - else - /* On some hosts // differs from /; Posix allows this. */ - to++; - } - } - base = to; - - for (;;) - { - while (*from == '/') - from++; - if (from[0] == '.' && from[1] == '/') - from += 2; - else if (from[0] == '.' && from[1] == '\0') - goto done; - else if (from[0] == '.' && from[1] == '.' && from[2] == '/') + if (*from == '\0') + break; + + if (*from == '.') { - if (base == to) + if (from[1] == '\0') + break; + if (from[1] == '/') { - if (absolute) - from += 3; - else - { - *to++ = *from++; - *to++ = *from++; - *to++ = *from++; - base = to; - } + from += 2; + continue; } - else + else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0')) { - to -= 2; - while (to > base && *to != '/') to--; - if (*to == '/') - to++; - from += 3; + /* Don't simplify if there was no previous component. */ + if (absolute && orig_base == to) + { + from += 2; + continue; + } + /* Don't simplify if the previous component was "../", + or if an error has already occurred with (l)stat. */ + if (base != to && errno == 0) + { + /* We don't back up if it's a symlink. */ + *to = '\0'; + if (remove_component_p (path)) + { + while (to > base && *to != '/') + to--; + from += 2; + continue; + } + } + move_base = 1; } } - else if (from[0] == '.' && from[1] == '.' && from[2] == '\0') - { - if (base == to) - { - if (!absolute) - { - *to++ = *from++; - *to++ = *from++; - } - } - else - { - to -= 2; - while (to > base && *to != '/') to--; - if (*to == '/') - to++; - } - goto done; - } - else - /* Copy this component and trailing /, if any. */ - while ((*to++ = *from++) != '/') - { - if (!to[-1]) - { - to--; - goto done; - } - } - + + /* Add the component separator. */ + if (to > orig_base) + *to++ = '/'; + + /* Copy this component until the trailing null or '/'. */ + while (*from != '\0' && *from != '/') + *to++ = *from++; + + if (move_base) + base = to; } - done: - /* Trim trailing slash */ - if (to[0] == '/' && (!absolute || to > path+1)) - to--; + /* Change the empty string to "." so that it is not treated as stdin. + Null terminate. */ + if (to == path) + *to++ = '.'; + *to = '\0'; - /* Change the empty string to "." so that stat() on the result - will always work. */ - if (to == path) - *to++ = '.'; - - *to = '\0'; - - return path; + return path; +#else /* VMS */ + errno = 0; + return path; +#endif /* !VMS */ } diff --git a/gcc/cppinit.c b/gcc/cppinit.c index 13a0e645b92..980cdb1df42 100644 --- a/gcc/cppinit.c +++ b/gcc/cppinit.c @@ -211,10 +211,12 @@ append_include_chain (pfile, dir, path, cxx_aware) struct stat st; unsigned int len; + if (*dir == '\0') + dir = xstrdup ("."); _cpp_simplify_pathname (dir); if (stat (dir, &st)) { - /* Dirs that don't exist are silently ignored. */ + /* Dirs that don't exist are silently ignored. */ if (errno != ENOENT) cpp_notice_from_errno (pfile, dir); else if (CPP_OPTION (pfile, verbose)) diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 5a523e034a1..56ffbb17bc7 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -729,12 +729,7 @@ do_line (pfile) cpp_get_token (pfile, &token); if (token.type == CPP_STRING) { - char *fname; - unsigned int len = token.val.str.len + 1; - - fname = (char *) _cpp_pool_alloc (&pfile->ident_pool, len); - memcpy (fname, token.val.str.text, len); - _cpp_simplify_pathname (fname); + const char *fname = (const char *) token.val.str.text; /* Only accept flags for the # 55 form. */ if (! pfile->state.line_extension)