OSDN Git Service

Correct test results for avoid-bool-define fix
[pf3gnuchains/gcc-fork.git] / gcc / cppfiles.c
index 1f7d899..137882b 100644 (file)
@@ -67,6 +67,7 @@ struct include_file
   const unsigned char *buffer; /* pointer to cached file contents */
   struct stat st;              /* copy of stat(2) data for file */
   int fd;                      /* fd open on file (short term storage only) */
+  int err_no;                  /* errno obtained if opening a file failed */
   unsigned short include_count;        /* number of times file has been read */
   unsigned short refcnt;       /* number of stacked buffers using this file */
   unsigned char mapped;                /* file buffer is mmapped */
@@ -93,7 +94,7 @@ static struct include_file *
        find_include_file PARAMS ((cpp_reader *, const cpp_token *,
                                   enum include_type));
 static struct include_file *open_file PARAMS ((cpp_reader *, const char *));
-static void read_include_file  PARAMS ((cpp_reader *, struct include_file *));
+static int read_include_file   PARAMS ((cpp_reader *, struct include_file *));
 static void stack_include_file PARAMS ((cpp_reader *, struct include_file *));
 static void purge_cache        PARAMS ((struct include_file *));
 static void destroy_node       PARAMS ((splay_tree_value));
@@ -101,6 +102,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 +157,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;
@@ -173,6 +176,7 @@ find_or_create_entry (pfile, fname)
     {
       file = xcnew (struct include_file);
       file->name = name;
+      file->err_no = errno;
       node = splay_tree_insert (pfile->all_include_files,
                                (splay_tree_key) file->name,
                                (splay_tree_value) file);
@@ -208,9 +212,12 @@ open_file (pfile, filename)
   splay_tree_node nd = find_or_create_entry (pfile, filename);
   struct include_file *file = (struct include_file *) nd->value;
 
-  /* Don't retry opening if we failed previously.  */
-  if (file->fd == -2)
-    return 0;
+  if (file->err_no)
+    {
+      /* Ugh.  handle_missing_header () needs errno to be set.  */
+      errno = file->err_no;
+      return 0;
+    }
 
   /* Don't reopen an idempotent file. */
   if (DO_NOT_REREAD (file))
@@ -241,24 +248,30 @@ open_file (pfile, filename)
 
   if (file->fd != -1 && fstat (file->fd, &file->st) == 0)
     {
-      /* Mark a regular, zero-length file never-reread now.  */
-      if (S_ISREG (file->st.st_mode) && file->st.st_size == 0)
-        {
-         _cpp_never_reread (file);
-         close (file->fd);
-         file->fd = -1;
-       }
+      /* If it's a directory, we return null and continue the search
+        as the file we're looking for may appear elsewhere in the
+        search path.  */
+      if (S_ISDIR (file->st.st_mode))
+       errno = ENOENT;
+      else
+       {
+         /* Mark a regular, zero-length file never-reread now.  */
+         if (S_ISREG (file->st.st_mode) && file->st.st_size == 0)
+           {
+             _cpp_never_reread (file);
+             close (file->fd);
+             file->fd = -1;
+           }
 
-      return file;
+         return file;
+       }
     }
 
   /* Don't issue an error message if the file doesn't exist.  */
+  file->err_no = errno;
   if (errno != ENOENT && errno != ENOTDIR)
     cpp_error_from_errno (pfile, file->name);
 
-  /* Create a negative node for this path, and return null.  */
-  file->fd = -2;
-
   return 0;
 }
 
@@ -284,13 +297,19 @@ stack_include_file (pfile, inc)
   if (CPP_OPTION (pfile, print_deps) > deps_sysp && !inc->include_count)
     deps_add_dep (pfile->deps, inc->name);
 
+  /* Not in cache?  */
+  if (! DO_NOT_REREAD (inc) && ! inc->buffer)
+    {
+      /* If an error occurs, do not try to read this file again.  */
+      if (read_include_file (pfile, inc))
+       _cpp_never_reread (inc);
+      close (inc->fd);
+      inc->fd = -1;
+    }
+
   if (! DO_NOT_REREAD (inc))
     {
-      /* Not in cache?  */
-      if (! inc->buffer)
-       read_include_file (pfile, inc);
       len = inc->st.st_size;
-
       if (pfile->buffer)
        {
          /* We don't want MI guard advice for the main file.  */
@@ -328,17 +347,17 @@ stack_include_file (pfile, inc)
    If fd points to a plain file, we might be able to mmap it; we can
    definitely allocate the buffer all at once.  If fd is a pipe or
    terminal, we can't do either.  If fd is something weird, like a
-   block device or a directory, we don't want to read it at all.
+   block device, we don't want to read it at all.
 
    Unfortunately, different systems use different st.st_mode values
    for pipes: some have S_ISFIFO, some S_ISSOCK, some are buggy and
    zero the entire struct stat except a couple fields.  Hence we don't
-   even try to figure out what something is, except for plain files,
-   directories, and block devices.
+   even try to figure out what something is, except for plain files
+   and block devices.
 
    FIXME: Flush file cache and try again if we run out of memory.  */
 
-static void
+static int
 read_include_file (pfile, inc)
      cpp_reader *pfile;
      struct include_file *inc;
@@ -402,11 +421,6 @@ read_include_file (pfile, inc)
       cpp_error (pfile, "%s is a block device", inc->name);
       goto fail;
     }
-  else if (S_ISDIR (inc->st.st_mode))
-    {
-      cpp_error (pfile, "%s is a directory", inc->name);
-      goto fail;
-    }
   else
     {
       /* 8 kilobytes is a sensible starting size.  It ought to be
@@ -430,19 +444,13 @@ read_include_file (pfile, inc)
       inc->st.st_size = offset;
     }
 
-  close (inc->fd);
   inc->buffer = buf;
-  inc->fd = -1;
-  return;
+  return 0;
 
  perror_fail:
   cpp_error_from_errno (pfile, inc->name);
  fail:
-  /* Do not try to read this file again.  */
-  close (inc->fd);
-  inc->fd = -1;
-  _cpp_never_reread (inc);
-  return;
+  return 1;
 }
 
 static void
@@ -617,6 +625,7 @@ handle_missing_header (pfile, fname, angle_brackets)
   /* We will try making the RHS pfile->buffer->sysp after 3.0.  */
   int print_dep = CPP_PRINT_DEPS(pfile) > (angle_brackets
                                           || pfile->system_include_depth);
+
   if (CPP_OPTION (pfile, print_deps_missing_files) && print_dep)
     {
       if (!angle_brackets || IS_ABSOLUTE_PATHNAME (fname))
@@ -639,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);
        }
     }
@@ -1002,6 +1010,32 @@ 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
+
+  /* There's no guarantee that errno will be unchanged, even on
+     success.  Cygwin's lstat(), for example, will often set errno to
+     ENOSYS.  In case of success, reset errno to zero.  */
+  if (result == 0)
+    errno = 0;
+
+  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).
@@ -1013,124 +1047,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++;
-       from++;
-       if (*from == '/')
+      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++;
+         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 (;;)
+
+  base = orig_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] == '/')
+      int move_base = 0;
+
+      while (*from == '/')
+       from++;
+
+      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;
-           }
-       }
-       else if (from[0] == '.' && from[1] == '.' && from[2] == '\0')
-       {
-           if (base == to)
-           {
-               if (!absolute)
+             /* Don't simplify if there was no previous component.  */
+             if (absolute && orig_base == to)
                {
-                   *to++ = *from++;
-                   *to++ = *from++;
+                 from += 2;
+                 continue;
                }
-           }
-           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])
+             /* Don't simplify if the previous component was "../",
+                or if an error has already occurred with (l)stat.  */
+             if (base != to && errno == 0)
                {
-                   to--;
-                   goto done;
+                 /* 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;
            }
-       
+       }
+
+      /* 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 stat() on the result
-       will always work. */
-    if (to == path)
-      *to++ = '.';
-    
-    *to = '\0';
-
-    return path;
+  /* Change the empty string to "." so that it is not treated as stdin.
+     Null terminate.  */
+  if (to == path)
+    *to++ = '.';
+  *to = '\0';
+
+  return path;
+#else /* VMS  */
+  errno = 0;
+  return path;
+#endif /* !VMS  */
 }