This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

splitting up cpplib, revised



Here is a much less invasive patch to split up cpplib.  It just breaks
out all the file handling code to cppfiles.c.  A bunch of the code in
do_include has been moved out to a separate function, find_include_file.
This should make it much easier to merge in the rewrite of file
handling from cpplib.

I also fixed a number of bugs related to pathnames and VMS.  A VMSie
should probably look at that part, but considering that cpplib
wouldn't even link on VMS before, it has to be an improvement.

`make bootstrap' completes successfully.  I don't have a system on
which fix-header is useful, but it links.

zw

1998-10-25 15:06 -0500  Zack Weinberg  <zack@rabi.phys.columbia.edu>

	* cpplib.c: Merge do_once into do_pragma.  Break file handling
	  code out of do_include. 
	  Move append_include_chain, deps_output,
	  file_cleanup, redundant_include_p, import_hash,
	  lookup_import, add_import, read_filename_string, read_name_map,
	  open_include_file, finclude, safe_read to cppfiles.c.
	  Move prototypes for deps_output, append_include_chain,
	  finclude to cpplib.h.  Move definition of struct
	  file_name_list there also.

	* cppfiles.c: New file.  Contains all the above functions
	  broken out of cpplib.c; also hack_vms_include_specification
	  from cccp.c and find_include_file, a new function broken out of
	  do_include.  

	* Makefile.in (cppmain): Depend on cppfiles.o.
	  (fix-header): Likewise.
	  (cppfiles.o): New target.
	* configure.in (--enable-c-cpplib): Add cppfiles.o to
	  extra_c_objs.  Add ../cppfiles.o to extra_cxx_objs.

============================================================
Index: Makefile.in
--- Makefile.in	1998/10/22 14:47:52	1.187
+++ Makefile.in	1998/10/25 20:01:07
@@ -1881,9 +1881,9 @@
 	  -c `echo $(srcdir)/cccp.c | sed 's,^\./,,'`
 
 cppmain$(exeext): cppmain.o cpplib.o cpphash.o cppalloc.o cpperror.o cppexp.o \
-  prefix.o version.o mbchar.o @extra_cpp_objs@ $(LIBDEPS)
+  cppfiles.o prefix.o version.o mbchar.o @extra_cpp_objs@ $(LIBDEPS)
 	$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ cppmain.o cpplib.o cpphash.o \
-	  mbchar.o @extra_cpp_objs@ \
+	  cppfiles.o mbchar.o @extra_cpp_objs@ \
 	  cppalloc.o cpperror.o cppexp.o prefix.o version.o $(LIBS)
 
 cppmain.o: cppmain.c $(CONFIG_H) cpplib.h system.h gansidecl.h
@@ -1902,6 +1902,8 @@
 
 cppexp.o: cppexp.c $(CONFIG_H) cpplib.h system.h gansidecl.h
 
+cppfiles.o: cppfiles.c $(CONFIG_H) cpplib.h system.h gansidecl.h
+
 cpphash.o: cpphash.c cpplib.h cpphash.h $(CONFIG_H) system.h gansidecl.h
 
 cppalloc.o: cppalloc.c $(CONFIG_H) cpplib.h system.h gansidecl.h
@@ -2116,10 +2118,10 @@
 	rm -rf fixtmp.c
 
 fix-header: fix-header.o scan-decls.o scan.o xsys-protos.h $(HOST_LIBDEPS) \
-   cpplib.o cpphash.o cppalloc.o cppexp.o prefix.o version.o
+   cpplib.o cpphash.o cppfiles.o cppalloc.o cppexp.o prefix.o version.o
 	$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ fix-header.o \
 	   scan-decls.o scan.o cpplib.o cpphash.o cppalloc.o prefix.o \
-	   version.o cppexp.o $(HOST_LIBS)
+	   version.o cppexp.o cppfiles.o $(HOST_LIBS)
 
 fix-header.o: fix-header.c $(srcdir)/../include/obstack.h scan.h \
 	xsys-protos.h $(build_xm_file) system.h cpplib.h cpphash.h
============================================================
Index: configure.in
--- configure.in	1998/10/12 11:14:11	1.166
+++ configure.in	1998/10/25 20:01:08
@@ -190,9 +190,9 @@
 [  --enable-c-cpplib       link cpplib directly into C and C++ compilers
                           (implies --enable-cpplib).],
 if test x$enable_c_cpplib != xno; then
-  extra_c_objs="${extra_c_objs} cpplib.o cppexp.o cpphash.o cpperror.o"
+  extra_c_objs="${extra_c_objs} cpplib.o cppexp.o cpphash.o cppfiles.o cpperror.o"
   extra_c_objs="${extra_c_objs} prefix.o"
-  extra_cxx_objs="${extra_cxx_objs} ../cpplib.o ../cppexp.o ../cpphash.o ../cpperror.o ../prefix.o"
+  extra_cxx_objs="${extra_cxx_objs} ../cpplib.o ../cppexp.o ../cpphash.o ../cppfiles.o ../cpperror.o ../prefix.o"
   extra_c_flags=-DUSE_CPPLIB=1
   cpp_main=cppmain
 fi)
============================================================
Index: cpplib.c
--- cpplib.c	1998/10/17 20:26:10	1.39
+++ cpplib.c	1998/10/25 20:01:09
@@ -88,9 +88,6 @@
 #ifndef STANDARD_INCLUDE_DIR
 #define STANDARD_INCLUDE_DIR "/usr/include"
 #endif
-#ifndef INCLUDE_LEN_FUDGE
-#define INCLUDE_LEN_FUDGE 0
-#endif
 
 /* Symbols to predefine.  */
 
@@ -199,10 +196,6 @@
 extern void cpp_hash_cleanup PARAMS ((cpp_reader *));
 
 static char *my_strerror		PROTO ((int));
-static void add_import			PROTO ((cpp_reader *, int, char *));
-static void append_include_chain	PROTO ((cpp_reader *,
-						struct file_name_list *,
-						struct file_name_list *));
 static void make_assertion		PROTO ((cpp_reader *, char *, U_CHAR *));
 static void path_include		PROTO ((cpp_reader *, char *));
 static void initialize_builtins		PROTO ((cpp_reader *));
@@ -210,38 +203,27 @@
 #if 0
 static void trigraph_pcp ();
 #endif
-static int finclude			PROTO ((cpp_reader *, int, char *,
-						int, struct file_name_list *));
 static void validate_else		PROTO ((cpp_reader *, char *));
 static int comp_def_part		PROTO ((int, U_CHAR *, int, U_CHAR *,
 						int, int));
 #ifdef abort
 extern void fancy_abort ();
 #endif
-static int lookup_import		PROTO ((cpp_reader *, char *,
-						struct file_name_list *));
-static int redundant_include_p		PROTO ((cpp_reader *, char *));
-static int is_system_include		PROTO ((cpp_reader *, char *));
-static struct file_name_map *read_name_map	PROTO ((cpp_reader *, char *));
-static char *read_filename_string	PROTO ((int, FILE *));
-static int open_include_file		PROTO ((cpp_reader *, char *,
-						struct file_name_list *));
 static int check_macro_name		PROTO ((cpp_reader *, U_CHAR *, char *));
 static int compare_defs			PROTO ((cpp_reader *,
 						DEFINITION *, DEFINITION *));
 static int compare_token_lists		PROTO ((struct arglist *,
 						struct arglist *));
+static int is_system_include		PROTO ((cpp_reader *, char *));
 static HOST_WIDE_INT eval_if_expression	PROTO ((cpp_reader *, U_CHAR *, int));
 static int change_newlines		PROTO ((U_CHAR *, int));
 static struct arglist *read_token_list	PROTO ((cpp_reader *, int *));
 static void free_token_list		PROTO ((struct arglist *));
-static int safe_read			PROTO ((int, char *, int));
 static void push_macro_expansion PARAMS ((cpp_reader *,
 					  U_CHAR *, int, HASHNODE *));
 static struct cpp_pending *nreverse_pending PARAMS ((struct cpp_pending *));
 extern char *xrealloc ();
 static char *xcalloc			PROTO ((unsigned, unsigned));
-static char *savestring			PROTO ((char *));
 
 static void conditional_skip		PROTO ((cpp_reader *, int,
 					       enum node_type, U_CHAR *));
@@ -259,25 +241,6 @@
 extern char *version_string;
 extern struct tm *localtime ();
 
-struct file_name_list
-  {
-    struct file_name_list *next;
-    char *fname;
-    /* If the following is nonzero, it is a macro name.
-       Don't include the file again if that macro is defined.  */
-    U_CHAR *control_macro;
-    /* If the following is nonzero, it is a C-language system include
-       directory.  */
-    int c_system_include_path;
-    /* Mapping of file names for this directory.  */
-    struct file_name_map *name_map;
-    /* Non-zero if name_map is valid.  */
-    int got_name_map;
-  };
-
-/* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found
-   via the same directory as the file that #included it.  */
-#define SELF_DIR_DUMMY ((struct file_name_list *) (~0))
 
 /* #include "file" looks in source file dir, then stack.  */
 /* #include <file> just looks in the stack.  */
@@ -365,7 +328,6 @@
 #ifdef SCCS_DIRECTIVE
 static int do_sccs PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
 #endif
-static int do_once PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
 static int do_assert PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
 static int do_unassert PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
 static int do_warning PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
@@ -402,13 +364,13 @@
 };
 
 /* table to tell if char can be part of a C identifier.  */
-U_CHAR is_idchar[256];
+U_CHAR is_idchar[256] = { 0 };
 /* table to tell if char can be first char of a c identifier.  */
-U_CHAR is_idstart[256];
+U_CHAR is_idstart[256] = { 0 };
 /* table to tell if c is horizontal space.  */
-U_CHAR is_hor_space[256];
+U_CHAR is_hor_space[256] = { 0 };
 /* table to tell if c is horizontal or vertical space.  */
-static U_CHAR is_space[256];
+U_CHAR is_space[256] = { 0 };
 
 /* Initialize syntactic classifications of characters.  */
 
@@ -614,85 +576,7 @@
       cpp_pop_buffer (pfile);
     }
 }
-
-/* Append a chain of `struct file_name_list's
-   to the end of the main include chain.
-   FIRST is the beginning of the chain to append, and LAST is the end.  */
-
-static void
-append_include_chain (pfile, first, last)
-     cpp_reader *pfile;
-     struct file_name_list *first, *last;
-{
-  struct cpp_options *opts = CPP_OPTIONS (pfile);
-  struct file_name_list *dir;
-
-  if (!first || !last)
-    return;
-
-  if (opts->include == 0)
-    opts->include = first;
-  else
-    opts->last_include->next = first;
-
-  if (opts->first_bracket_include == 0)
-    opts->first_bracket_include = first;
-
-  for (dir = first; ; dir = dir->next) {
-    int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE;
-    if (len > pfile->max_include_len)
-      pfile->max_include_len = len;
-    if (dir == last)
-      break;
-  }
-
-  last->next = NULL;
-  opts->last_include = last;
-}
-
-/* Add output to `deps_buffer' for the -M switch.
-   STRING points to the text to be output.
-   SPACER is ':' for targets, ' ' for dependencies, zero for text
-   to be inserted literally.  */
 
-static void
-deps_output (pfile, string, spacer)
-     cpp_reader *pfile;
-     char *string;
-     int spacer;
-{
-  int size = strlen (string);
-
-  if (size == 0)
-    return;
-
-#ifndef MAX_OUTPUT_COLUMNS
-#define MAX_OUTPUT_COLUMNS 72
-#endif
-  if (spacer
-      && pfile->deps_column > 0
-      && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS)
-    {
-      deps_output (pfile, " \\\n  ", 0);
-      pfile->deps_column = 0;
-    }
-
-  if (pfile->deps_size + size + 8 > pfile->deps_allocated_size)
-    {
-      pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2;
-      pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer,
-					      pfile->deps_allocated_size);
-    }
-  if (spacer == ' ' && pfile->deps_column > 0)
-    pfile->deps_buffer[pfile->deps_size++] = ' ';
-  bcopy (string, &pfile->deps_buffer[pfile->deps_size], size);
-  pfile->deps_size += size;
-  pfile->deps_column += size;
-  if (spacer == ':')
-    pfile->deps_buffer[pfile->deps_size++] = ':';
-  pfile->deps_buffer[pfile->deps_size] = 0;
-}
-
 /* Given a colon-separated list of file names PATH,
    add all the names to the search path for include files.  */
 
@@ -805,19 +689,6 @@
   return 0;
 }
 
-int
-file_cleanup (pbuf, pfile)
-     cpp_buffer *pbuf;
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-{
-  if (pbuf->buf)
-    {
-      free (pbuf->buf);
-      pbuf->buf = 0;
-    }
-  return 0;
-}
-
 /* Assuming we have read '/'.
    If this is the start of a comment (followed by '*' or '/'),
    skip to the end of the comment, and return ' '.
@@ -3076,29 +2947,21 @@
 {
   int importing = (keyword->type == T_IMPORT);
   int skip_dirs = (keyword->type == T_INCLUDE_NEXT);
+  int angle_brackets = 0;	/* 0 for "...", 1 for <...> */
   char *fname;		/* Dynamically allocated fname buffer */
-  char *pcftry;
-  U_CHAR *fbeg, *fend;		/* Beginning and end of fname */
+  char *fbeg, *fend;		/* Beginning and end of fname */
+  long flen;
+
   enum cpp_token token;
 
   /* Chain of dirs to search */
   struct file_name_list *search_start = CPP_OPTIONS (pfile)->include;
-  struct file_name_list dsp[1];	/* First in chain, if #include "..." */
-  struct file_name_list *searchptr = 0;
+  struct file_name_list dsp;	/* First in chain, if #include "..." */
+  struct file_name_list *foundhere, *ptr;
+  
   long old_written = CPP_WRITTEN (pfile);
-
-  int flen;
 
-  int f;			/* file number */
-
-  int angle_brackets = 0;	/* 0 for "...", 1 for <...> */
-  char *pcfbuf;
-#if 0
-  int pcf = -1;
-  char *pcfbuflimit;
-#endif
-  int pcfnum;
-  f= -1;			/* JF we iz paranoid! */
+  int fd;
 
   if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p)
     {
@@ -3132,9 +2995,9 @@
 
   if (token == CPP_STRING)
     {
-      /* FIXME - check no trailing garbage */
       fbeg = pfile->token_buffer + old_written + 1;
       fend = CPP_PWRITTEN (pfile) - 1;
+      *fend = '\0';
       if (fbeg[-1] == '<')
 	{
 	  angle_brackets = 1;
@@ -3158,8 +3021,8 @@
 		{
 		  /* Found a named file.  Figure out dir of the file,
 		     and put it in front of the search list.  */
-		  dsp[0].next = search_start;
-		  search_start = dsp;
+		  dsp.next = search_start;
+		  search_start = &dsp;
 #ifndef VMS
 		  ep = rindex (nam, '/');
 #else				/* VMS */
@@ -3171,17 +3034,17 @@
 		  if (ep != NULL)
 		    {
 		      n = ep - nam;
-		      dsp[0].fname = (char *) alloca (n + 1);
-		      strncpy (dsp[0].fname, nam, n);
-		      dsp[0].fname[n] = '\0';
+		      dsp.fname = (char *) alloca (n + 1);
+		      strncpy (dsp.fname, nam, n);
+		      dsp.fname[n] = '\0';
 		      if (n + INCLUDE_LEN_FUDGE > pfile->max_include_len)
 			pfile->max_include_len = n + INCLUDE_LEN_FUDGE;
 		    }
 		  else
 		    {
-		      dsp[0].fname = 0; /* Current directory */
+		      dsp.fname = 0; /* Current directory */
 		    }
-		  dsp[0].got_name_map = 0;
+		  dsp.got_name_map = 0;
 		  break;
 		}
 	    }
@@ -3201,6 +3064,11 @@
       /* If -I-, start with the first -I dir after the -I-.  */
       if (CPP_OPTIONS (pfile)->first_bracket_include)
 	search_start = CPP_OPTIONS (pfile)->first_bracket_include;
+
+      /* Append the missing `.h' to the name. */
+      CPP_PUTS (pfile, ".h", 3)
+      CPP_NUL_TERMINATE_Q (pfile);
+
       fbeg = pfile->token_buffer + old_written;
       fend = CPP_PWRITTEN (pfile);
     }
@@ -3214,14 +3082,11 @@
       return 0;
     }
 
-  *fend = 0;
-
   token = get_directive_token (pfile);
   if (token != CPP_VSPACE)
     {
       cpp_error (pfile, "junk at end of `#include'");
-      while (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
-	token = get_directive_token (pfile);
+      skip_rest_of_line (pfile);
     }
 
   /* For #include_next, skip in the search path
@@ -3254,127 +3119,57 @@
 
   /* Allocate this permanently, because it gets stored in the definitions
      of macros.  */
-  fname = (char *) xmalloc (pfile->max_include_len + flen + 4);
   /* + 2 above for slash and terminating null.  */
-  /* + 2 added for '.h' on VMS (to support '#include filename') */
+  fname = (char *) xmalloc (pfile->max_include_len + flen + 2);
 
-  /* If specified file name is absolute, just open it.  */
+  fd = find_include_file (pfile, fbeg, flen, fname,
+			  importing, search_start, &foundhere);
 
-  if (*fbeg == '/') {
-    strncpy (fname, fbeg, flen);
-    fname[flen] = 0;
-    if (redundant_include_p (pfile, fname))
+  if (fd == -2)
+    {
+      free (fname);
       return 0;
-    if (importing)
-      f = lookup_import (pfile, fname, NULL_PTR);
-    else
-      f = open_include_file (pfile, fname, NULL_PTR);
-    if (f == -2)
-      return 0;		/* Already included this file */
-  } else {
-    /* Search directory path, trying to open the file.
-       Copy each filename tried into FNAME.  */
-
-    for (searchptr = search_start; searchptr; searchptr = searchptr->next) {
-      if (searchptr->fname) {
-	/* The empty string in a search path is ignored.
-	   This makes it possible to turn off entirely
-	   a standard piece of the list.  */
-	if (searchptr->fname[0] == 0)
-	  continue;
-	strcpy (fname, searchptr->fname);
-	strcat (fname, "/");
-	fname[strlen (fname) + flen] = 0;
-      } else {
-	fname[0] = 0;
-      }
-      strncat (fname, fbeg, flen);
-#ifdef VMS
-      /* Change this 1/2 Unix 1/2 VMS file specification into a
-         full VMS file specification */
-      if (searchptr->fname && (searchptr->fname[0] != 0)) {
-	/* Fix up the filename */
-	hack_vms_include_specification (fname);
-      } else {
-      	/* This is a normal VMS filespec, so use it unchanged.  */
-	strncpy (fname, fbeg, flen);
-	fname[flen] = 0;
-	/* if it's '#include filename', add the missing .h */
-	if (index(fname,'.')==NULL) {
-	  strcat (fname, ".h");
-	}
-      }
-#endif /* VMS */
-      /* ??? There are currently 3 separate mechanisms for avoiding processing
-	 of redundant include files: #import, #pragma once, and
-	 redundant_include_p.  It would be nice if they were unified.  */
-      if (redundant_include_p (pfile, fname))
-	return 0;
-      if (importing)
-	f = lookup_import (pfile, fname, searchptr);
-      else
-	f = open_include_file (pfile, fname, searchptr);
-      if (f == -2)
-	return 0;			/* Already included this file */
-#ifdef EACCES
-      else if (f == -1 && errno == EACCES)
-	cpp_warning (pfile, "Header file %s exists, but is not readable",
-		     fname);
-#endif
-      if (f >= 0)
-	break;
     }
-  }
-
-  if (f < 0)
+  
+  if (fd == -1)
     {
-      /* A file that was not found.  */
-      strncpy (fname, fbeg, flen);
-      fname[flen] = 0;
-      /* If generating dependencies and -MG was specified, we assume missing
-	 files are leaf files, living in the same directory as the source file
-	 or other similar place; these missing files may be generated from
-	 other files and may not exist yet (eg: y.tab.h).  */
-
-      if (CPP_OPTIONS(pfile)->print_deps_missing_files
-	  && CPP_PRINT_DEPS (pfile)
-	  > (angle_brackets || (pfile->system_include_depth > 0)))
-	{
-	  /* If it was requested as a system header file,
-	     then assume it belongs in the first place to look for such.  */
-	  if (angle_brackets)
+      if (CPP_OPTIONS (pfile)->print_deps_missing_files
+	  && CPP_PRINT_DEPS (pfile) > (angle_brackets ||
+				       (pfile->system_include_depth > 0)))
+        {
+	  if (!angle_brackets)
+	    deps_output (pfile, fbeg, ' ');
+	  else
 	    {
-	      for (searchptr = search_start; searchptr;
-		   searchptr = searchptr->next)
-		{
-		  if (searchptr->fname)
+	      /* If requested as a system header, assume it belongs in
+		 the first system header directory. */
+	      if (CPP_OPTIONS (pfile)->first_bracket_include)
+	        ptr = CPP_OPTIONS (pfile)->first_bracket_include;
+	      else
+		ptr = CPP_OPTIONS (pfile)->include;
+	      for (; ptr; ptr = ptr->next)
+		  if (ptr->fname)
 		    {
 		      char *p;
 
-		      if (searchptr->fname[0] == 0)
+		      if (ptr->fname[0] == 0)
 			continue;
-		      p = (char *) alloca (strlen (searchptr->fname)
+		      p = (char *) alloca (strlen (ptr->fname)
 					   + strlen (fname) + 2);
-		      strcpy (p, searchptr->fname);
+		      strcpy (p, ptr->fname);
 		      strcat (p, "/");
 		      strcat (p, fname);
 		      deps_output (pfile, p, ' ');
 		      break;
 		    }
-		}
-	    }
-	  else
-	    {
-	      /* Otherwise, omit the directory, as if the file existed
-		 in the directory with the source.  */
-	      deps_output (pfile, fname, ' ');
 	    }
 	}
-      /* If -M was specified, and this header file won't be added to the
-	 dependency list, then don't count this as an error, because we can
-	 still produce correct output.  Otherwise, we can't produce correct
-	 output, because there may be dependencies we need inside the missing
-	 file, and we don't know what directory this missing file exists in.*/
+      /* If -M was specified, and this header file won't be added to
+	 the dependency list, then don't count this as an error,
+	 because we can still produce correct output.  Otherwise, we
+	 can't produce correct output, because there may be
+	 dependencies we need inside the missing file, and we don't
+	 know what directory this missing file exists in. */
       else if (CPP_PRINT_DEPS (pfile)
 	       && (CPP_PRINT_DEPS (pfile)
 		   <= (angle_brackets || (pfile->system_include_depth > 0))))
@@ -3383,26 +3178,19 @@
 	cpp_error_from_errno (pfile, fname);
       else
 	cpp_error (pfile, "No include path in which to find %s", fname);
-    }
-  else {
-    /* Check to see if this include file is a once-only include file.
-       If so, give up.  */
-
-    struct file_name_list *ptr;
 
-    for (ptr = pfile->dont_repeat_files; ptr; ptr = ptr->next) {
-      if (!strcmp (ptr->fname, fname)) {
-	close (f);
-        return 0;				/* This file was once'd.  */
-      }
+      free (fname);
+      return 0;
     }
 
-    for (ptr = pfile->all_include_files; ptr; ptr = ptr->next) {
-      if (!strcmp (ptr->fname, fname))
-        break;				/* This file was included before.  */
-    }
+  /* If we get here, we have a file to process. */
+
+  for (ptr = pfile->all_include_files; ptr; ptr = ptr->next)
+    if (!strcmp (ptr->fname, fname))
+      break;				/* This file was included before.  */
 
-    if (ptr == 0) {
+  if (ptr == 0)
+    {
       /* This is the first time for this file.  */
       /* Add it to list of files included.  */
 
@@ -3418,95 +3206,38 @@
       if (CPP_PRINT_DEPS (pfile)
 	  > (angle_brackets || (pfile->system_include_depth > 0)))
 	deps_output (pfile, fname, ' ');
-    }   
-
-    /* Handle -H option.  */
-    if (CPP_OPTIONS(pfile)->print_include_names)
-      {
-	cpp_buffer *buf = CPP_BUFFER (pfile);
-	while ((buf = CPP_PREV_BUFFER (buf)) != CPP_NULL_BUFFER (pfile))
-	  putc ('.', stderr);
-	fprintf (stderr, "%s\n", fname);
-      }
-
-    if (angle_brackets)
-      pfile->system_include_depth++;
-
-    /* Actually process the file.  */
-
-    /* Record file on "seen" list for #import.  */
-    add_import (pfile, f, fname);
-
-    pcftry = (char *) alloca (strlen (fname) + 30);
-    pcfbuf = 0;
-    pcfnum = 0;
-
-#if 0
-    if (!no_precomp)
-      {
-	struct stat stat_f;
-
-	fstat (f, &stat_f);
-
-	do {
-	  sprintf (pcftry, "%s%d", fname, pcfnum++);
+    }
 
-	  pcf = open (pcftry, O_RDONLY, 0666);
-	  if (pcf != -1)
-	    {
-	      struct stat s;
+  /* Handle -H option.  */
+  if (CPP_OPTIONS(pfile)->print_include_names)
+    {
+      cpp_buffer *buf = CPP_BUFFER (pfile);
+      while ((buf = CPP_PREV_BUFFER (buf)) != CPP_NULL_BUFFER (pfile))
+	putc ('.', stderr);
+      fprintf (stderr, "%s\n", fname);
+    }
 
-	      fstat (pcf, &s);
-	      if (bcmp ((char *) &stat_f.st_ino, (char *) &s.st_ino,
-			sizeof (s.st_ino))
-		  || stat_f.st_dev != s.st_dev)
-		{
-		  pcfbuf = check_precompiled (pcf, fname, &pcfbuflimit);
-		  /* Don't need it any more.  */
-		  close (pcf);
-		}
-	      else
-		{
-		  /* Don't need it at all.  */
-		  close (pcf);
-		  break;
-		}
-	    }
-	} while (pcf != -1 && !pcfbuf);
-      }
-#endif
-    
-    /* Actually process the file */
-    if (cpp_push_buffer (pfile, NULL, 0) == NULL)
+  /* Actually process the file */
+  if (cpp_push_buffer (pfile, NULL, 0) == NULL)
+    {
+      close (fd);
+      free (fname);
       return 0;
-    if (finclude (pfile, f, fname, is_system_include (pfile, fname),
-		  searchptr != dsp ? searchptr : SELF_DIR_DUMMY))
-      {
-	output_line_command (pfile, 0, enter_file);
-	pfile->only_seen_white = 2;
-      }
+    }
 
-    if (angle_brackets)
-      pfile->system_include_depth--;
-  }
-  return 0;
-}
+  if (angle_brackets)
+    pfile->system_include_depth++;
 
-/* Return nonzero if there is no need to include file NAME
-   because it has already been included and it contains a conditional
-   to make a repeated include do nothing.  */
+  if (finclude (pfile, fd, fname, is_system_include (pfile, fname),
+		foundhere != &dsp ? foundhere : SELF_DIR_DUMMY))
+    {
+      output_line_command (pfile, 0, enter_file);
+      pfile->only_seen_white = 2;
+    }
+  
+  if (angle_brackets)
+    pfile->system_include_depth--;
 
-static int
-redundant_include_p (pfile, name)
-     cpp_reader *pfile;
-     char *name;
-{
-  struct file_name_list *l = pfile->all_include_files;
-  for (; l; l = l->next)
-    if (! strcmp (name, l->fname)
-	&& l->control_macro
-	&& cpp_lookup (pfile, l->control_macro, -1, -1))
-      return 1;
   return 0;
 }
 
@@ -3545,7 +3276,6 @@
   return 0;
 }
 
-
 /*
  * Install a name in the assertion hash table.
  *
@@ -3910,38 +3640,6 @@
   return 0;
 }
 
-/* Remember the name of the current file being read from so that we can
-   avoid ever including it again.  */
-
-static int
-do_once (pfile, keyword, unused1, unused2)
-     cpp_reader *pfile;
-     struct directive *keyword ATTRIBUTE_UNUSED;
-     U_CHAR *unused1 ATTRIBUTE_UNUSED, *unused2 ATTRIBUTE_UNUSED;
-{
-  cpp_buffer *ip = NULL;
-  struct file_name_list *new;
-
-  for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip))
-    {
-      if (ip == CPP_NULL_BUFFER (pfile))
-	return 0;
-      if (ip->fname != NULL)
-	break;
-    }
-
-    
-  new = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
-  new->next = pfile->dont_repeat_files;
-  pfile->dont_repeat_files = new;
-  new->fname = savestring (ip->fname);
-  new->control_macro = 0;
-  new->got_name_map = 0;
-  new->c_system_include_path = 0;
-
-  return 0;
-}
-
 /* Report program identification.  */
 
 static int
@@ -3972,14 +3670,33 @@
 {
   while (*buf == ' ' || *buf == '\t')
     buf++;
-  if (!strncmp (buf, "once", 4)) {
-    /* Allow #pragma once in system headers, since that's not the user's
-       fault.  */
-    if (!CPP_BUFFER (pfile)->system_header_p)
-      cpp_warning (pfile, "`#pragma once' is obsolete");
-    do_once (pfile, NULL, NULL, NULL);
-  }
+  if (!strncmp (buf, "once", 4))
+    {
+      cpp_buffer *ip = NULL;
+      struct file_name_list *new;
 
+      /* Allow #pragma once in system headers, since that's not the user's
+	 fault.  */
+      if (!CPP_BUFFER (pfile)->system_header_p)
+	cpp_warning (pfile, "`#pragma once' is obsolete");
+      
+      for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip))
+        {
+	  if (ip == CPP_NULL_BUFFER (pfile))
+	    return 0;
+	  if (ip->fname != NULL)
+	    break;
+	}
+      
+      new = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
+      new->next = pfile->dont_repeat_files;
+      new->fname = savestring (ip->fname);
+      new->control_macro = 0;
+      new->got_name_map = 0;
+      new->c_system_include_path = 0;
+      pfile->dont_repeat_files = new;
+    }
+
   if (!strncmp (buf, "implementation", 14)) {
     /* Be quiet about `#pragma implementation' for a file only if it hasn't
        been included yet.  */
@@ -5270,444 +4987,6 @@
   return 1;
 }
 
-
-/* Maintain and search list of included files, for #import.  */
-
-/* Hash a file name for import_hash_table.  */
-
-static int 
-import_hash (f)
-     char *f;
-{
-  int val = 0;
-
-  while (*f) val += *f++;
-  return (val%IMPORT_HASH_SIZE);
-}
-
-/* Search for file FILENAME in import_hash_table.
-   Return -2 if found, either a matching name or a matching inode.
-   Otherwise, open the file and return a file descriptor if successful
-   or -1 if unsuccessful.  */
-
-static int
-lookup_import (pfile, filename, searchptr)
-     cpp_reader *pfile;
-     char *filename;
-     struct file_name_list *searchptr;
-{
-  struct import_file *i;
-  int h;
-  int hashval;
-  struct stat sb;
-  int fd;
-
-  hashval = import_hash (filename);
-
-  /* Attempt to find file in list of already included files */
-  i = pfile->import_hash_table[hashval];
-
-  while (i) {
-    if (!strcmp (filename, i->name))
-      return -2;		/* return found */
-    i = i->next;
-  }
-  /* Open it and try a match on inode/dev */
-  fd = open_include_file (pfile, filename, searchptr);
-  if (fd < 0)
-    return fd;
-  fstat (fd, &sb);
-  for (h = 0; h < IMPORT_HASH_SIZE; h++) {
-    i = pfile->import_hash_table[h];
-    while (i) {
-      /* Compare the inode and the device.
-	 Supposedly on some systems the inode is not a scalar.  */
-      if (!bcmp ((char *) &i->inode, (char *) &sb.st_ino, sizeof (sb.st_ino))
-	  && i->dev == sb.st_dev) {
-        close (fd);
-        return -2;		/* return found */
-      }
-      i = i->next;
-    }
-  }
-  return fd;			/* Not found, return open file */
-}
-
-/* Add the file FNAME, open on descriptor FD, to import_hash_table.  */
-
-static void
-add_import (pfile, fd, fname)
-     cpp_reader *pfile;
-     int fd;
-     char *fname;
-{
-  struct import_file *i;
-  int hashval;
-  struct stat sb;
-
-  hashval = import_hash (fname);
-  fstat (fd, &sb);
-  i = (struct import_file *)xmalloc (sizeof (struct import_file));
-  i->name = (char *)xmalloc (strlen (fname)+1);
-  strcpy (i->name, fname);
-  bcopy ((char *) &sb.st_ino, (char *) &i->inode, sizeof (sb.st_ino));
-  i->dev = sb.st_dev;
-  i->next = pfile->import_hash_table[hashval];
-  pfile->import_hash_table[hashval] = i;
-}
-
-/* The file_name_map structure holds a mapping of file names for a
-   particular directory.  This mapping is read from the file named
-   FILE_NAME_MAP_FILE in that directory.  Such a file can be used to
-   map filenames on a file system with severe filename restrictions,
-   such as DOS.  The format of the file name map file is just a series
-   of lines with two tokens on each line.  The first token is the name
-   to map, and the second token is the actual name to use.  */
-
-struct file_name_map
-{
-  struct file_name_map *map_next;
-  char *map_from;
-  char *map_to;
-};
-
-#define FILE_NAME_MAP_FILE "header.gcc"
-
-/* Read a space delimited string of unlimited length from a stdio
-   file.  */
-
-static char *
-read_filename_string (ch, f)
-     int ch;
-     FILE *f;
-{
-  char *alloc, *set;
-  int len;
-
-  len = 20;
-  set = alloc = xmalloc (len + 1);
-  if (! is_space[ch])
-    {
-      *set++ = ch;
-      while ((ch = getc (f)) != EOF && ! is_space[ch])
-	{
-	  if (set - alloc == len)
-	    {
-	      len *= 2;
-	      alloc = xrealloc (alloc, len + 1);
-	      set = alloc + len / 2;
-	    }
-	  *set++ = ch;
-	}
-    }
-  *set = '\0';
-  ungetc (ch, f);
-  return alloc;
-}
-
-/* This structure holds a linked list of file name maps, one per directory.  */
-
-struct file_name_map_list
-{
-  struct file_name_map_list *map_list_next;
-  char *map_list_name;
-  struct file_name_map *map_list_map;
-};
-
-/* Read the file name map file for DIRNAME.  */
-
-static struct file_name_map *
-read_name_map (pfile, dirname)
-     cpp_reader *pfile;
-     char *dirname;
-{
-  register struct file_name_map_list *map_list_ptr;
-  char *name;
-  FILE *f;
-
-  for (map_list_ptr = CPP_OPTIONS (pfile)->map_list; map_list_ptr;
-       map_list_ptr = map_list_ptr->map_list_next)
-    if (! strcmp (map_list_ptr->map_list_name, dirname))
-      return map_list_ptr->map_list_map;
-
-  map_list_ptr = ((struct file_name_map_list *)
-		  xmalloc (sizeof (struct file_name_map_list)));
-  map_list_ptr->map_list_name = savestring (dirname);
-  map_list_ptr->map_list_map = NULL;
-
-  name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
-  strcpy (name, dirname);
-  if (*dirname)
-    strcat (name, "/");
-  strcat (name, FILE_NAME_MAP_FILE);
-  f = fopen (name, "r");
-  if (!f)
-    map_list_ptr->map_list_map = NULL;
-  else
-    {
-      int ch;
-      int dirlen = strlen (dirname);
-
-      while ((ch = getc (f)) != EOF)
-	{
-	  char *from, *to;
-	  struct file_name_map *ptr;
-
-	  if (is_space[ch])
-	    continue;
-	  from = read_filename_string (ch, f);
-	  while ((ch = getc (f)) != EOF && is_hor_space[ch])
-	    ;
-	  to = read_filename_string (ch, f);
-
-	  ptr = ((struct file_name_map *)
-		 xmalloc (sizeof (struct file_name_map)));
-	  ptr->map_from = from;
-
-	  /* Make the real filename absolute.  */
-	  if (*to == '/')
-	    ptr->map_to = to;
-	  else
-	    {
-	      ptr->map_to = xmalloc (dirlen + strlen (to) + 2);
-	      strcpy (ptr->map_to, dirname);
-	      ptr->map_to[dirlen] = '/';
-	      strcpy (ptr->map_to + dirlen + 1, to);
-	      free (to);
-	    }	      
-
-	  ptr->map_next = map_list_ptr->map_list_map;
-	  map_list_ptr->map_list_map = ptr;
-
-	  while ((ch = getc (f)) != '\n')
-	    if (ch == EOF)
-	      break;
-	}
-      fclose (f);
-    }
-  
-  map_list_ptr->map_list_next = CPP_OPTIONS (pfile)->map_list;
-  CPP_OPTIONS (pfile)->map_list = map_list_ptr;
-
-  return map_list_ptr->map_list_map;
-}  
-
-/* Try to open include file FILENAME.  SEARCHPTR is the directory
-   being tried from the include file search path.  This function maps
-   filenames on file systems based on information read by
-   read_name_map.  */
-
-static int
-open_include_file (pfile, filename, searchptr)
-     cpp_reader *pfile;
-     char *filename;
-     struct file_name_list *searchptr;
-{
-  if (CPP_OPTIONS (pfile)->remap)
-    {
-      register struct file_name_map *map;
-      register char *from;
-      char *p, *dir;
-
-      if (searchptr && ! searchptr->got_name_map)
-	{
-	  searchptr->name_map = read_name_map (pfile,
-					       searchptr->fname
-					       ? searchptr->fname : ".");
-	  searchptr->got_name_map = 1;
-	}
-
-      /* First check the mapping for the directory we are using.  */
-      if (searchptr && searchptr->name_map)
-	{
-	  from = filename;
-	  if (searchptr->fname)
-	    from += strlen (searchptr->fname) + 1;
-	  for (map = searchptr->name_map; map; map = map->map_next)
-	    {
-	      if (! strcmp (map->map_from, from))
-		{
-		  /* Found a match.  */
-		  return open (map->map_to, O_RDONLY, 0666);
-		}
-	    }
-	}
-
-      /* Try to find a mapping file for the particular directory we are
-	 looking in.  Thus #include <sys/types.h> will look up sys/types.h
-	 in /usr/include/header.gcc and look up types.h in
-	 /usr/include/sys/header.gcc.  */
-      p = rindex (filename, '/');
-      if (! p)
-	p = filename;
-      if (searchptr
-	  && searchptr->fname
-	  && strlen (searchptr->fname) == (size_t) (p - filename)
-	  && ! strncmp (searchptr->fname, filename, p - filename))
-	{
-	  /* FILENAME is in SEARCHPTR, which we've already checked.  */
-	  return open (filename, O_RDONLY, 0666);
-	}
-
-      if (p == filename)
-	{
-	  dir = ".";
-	  from = filename;
-	}
-      else
-	{
-	  dir = (char *) alloca (p - filename + 1);
-	  bcopy (filename, dir, p - filename);
-	  dir[p - filename] = '\0';
-	  from = p + 1;
-	}
-      for (map = read_name_map (pfile, dir); map; map = map->map_next)
-	if (! strcmp (map->map_from, from))
-	  return open (map->map_to, O_RDONLY, 0666);
-    }
-
-  return open (filename, O_RDONLY, 0666);
-}
-
-/* Process the contents of include file FNAME, already open on descriptor F,
-   with output to OP.
-   SYSTEM_HEADER_P is 1 if this file resides in any one of the known
-   "system" include directories (as decided by the `is_system_include'
-   function above).
-   DIRPTR is the link in the dir path through which this file was found,
-   or 0 if the file name was absolute or via the current directory.
-   Return 1 on success, 0 on failure.
-
-   The caller is responsible for the cpp_push_buffer.  */
-
-static int
-finclude (pfile, f, fname, system_header_p, dirptr)
-     cpp_reader *pfile;
-     int f;
-     char *fname;
-     int system_header_p;
-     struct file_name_list *dirptr;
-{
-  struct stat st;
-  size_t st_size;
-  long i;
-  int length;
-  cpp_buffer *fp;			/* For input stack frame */
-#if 0
-  int missing_newline = 0;
-#endif
-
-  if (fstat (f, &st) < 0)
-    {
-      cpp_perror_with_name (pfile, fname);
-      close (f);
-      cpp_pop_buffer (pfile);
-      return 0;
-    }
-
-  fp = CPP_BUFFER (pfile);
-  fp->nominal_fname = fp->fname = fname;
-#if 0
-  fp->length = 0;
-#endif
-  fp->dir = dirptr;
-  fp->system_header_p = system_header_p;
-  fp->lineno = 1;
-  fp->colno = 1;
-  fp->cleanup = file_cleanup;
-
-  if (S_ISREG (st.st_mode)) {
-    st_size = (size_t) st.st_size;
-    if (st_size != st.st_size || st_size + 2 < st_size) {
-      cpp_error (pfile, "file `%s' too large", fname);
-      close (f);
-      return 0;
-    }
-    fp->buf = (U_CHAR *) xmalloc (st_size + 2);
-    fp->alimit = fp->buf + st_size + 2;
-    fp->cur = fp->buf;
-
-    /* Read the file contents, knowing that st_size is an upper bound
-       on the number of bytes we can read.  */
-    length = safe_read (f, fp->buf, st_size);
-    fp->rlimit = fp->buf + length;
-    if (length < 0) goto nope;
-  }
-  else if (S_ISDIR (st.st_mode)) {
-    cpp_error (pfile, "directory `%s' specified in #include", fname);
-    close (f);
-    return 0;
-  } else {
-    /* Cannot count its file size before reading.
-       First read the entire file into heap and
-       copy them into buffer on stack.  */
-
-    size_t bsize = 2000;
-
-    st_size = 0;
-    fp->buf = (U_CHAR *) xmalloc (bsize + 2);
-
-    for (;;) {
-      i = safe_read (f, fp->buf + st_size, bsize - st_size);
-      if (i < 0)
-	goto nope;      /* error! */
-      st_size += i;
-      if (st_size != bsize)
-	break;	/* End of file */
-      bsize *= 2;
-      fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2);
-    }
-    fp->cur = fp->buf;
-    length = st_size;
-  }
-
-  if ((length > 0 && fp->buf[length - 1] != '\n')
-      /* Backslash-newline at end is not good enough.  */
-      || (length > 1 && fp->buf[length - 2] == '\\')) {
-    fp->buf[length++] = '\n';
-#if 0
-    missing_newline = 1;
-#endif
-  }
-  fp->buf[length] = '\0';
-  fp->rlimit = fp->buf + length;
-
-  /* Close descriptor now, so nesting does not use lots of descriptors.  */
-  close (f);
-
-  /* Must do this before calling trigraph_pcp, so that the correct file name
-     will be printed in warning messages.  */
-
-  pfile->input_stack_listing_current = 0;
-
-#if 0
-  if (!no_trigraphs)
-    trigraph_pcp (fp);
-#endif
-
-#if 0
-  rescan (op, 0);
-
-  if (missing_newline)
-    fp->lineno--;
-
-  if (CPP_PEDANTIC (pfile) && missing_newline)
-    pedwarn ("file does not end in newline");
-
-  indepth--;
-  input_file_stack_tick++;
-  free (fp->buf);
-#endif
-  return 1;
-
- nope:
-
-  cpp_perror_with_name (pfile, fname);
-  close (f);
-  free (fp->buf);
-  return 1;
-}
-
 /* This is called after options have been processed.
  * Check options for consistency, and setup for processing input
  * from the file named FNAME.  (Use standard input if FNAME==NULL.)
@@ -7297,45 +6576,11 @@
     tokens = next;
   }
 }
-
-/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
-   retrying if necessary.  If MAX_READ_LEN is defined, read at most
-   that bytes at a time.  Return a negative value if an error occurs,
-   otherwise return the actual number of bytes read,
-   which must be LEN unless end-of-file was reached.  */
-
-static int
-safe_read (desc, ptr, len)
-     int desc;
-     char *ptr;
-     int len;
-{
-  int left, rcount, nchars;
-
-  left = len;
-  while (left > 0) {
-    rcount = left;
-#ifdef MAX_READ_LEN
-    if (rcount > MAX_READ_LEN)
-      rcount = MAX_READ_LEN;
-#endif
-    nchars = read (desc, ptr, rcount);
-    if (nchars < 0)
-      {
-#ifdef EINTR
-	if (errno == EINTR)
-	  continue;
-#endif
-	return nchars;
-      }
-    if (nchars == 0)
-      break;
-    ptr += nchars;
-    left -= nchars;
-  }
-  return len - left;
-}
 
+/* FIXME: savestring() should be renamed strdup() and both should
+   be moved into cppalloc.c.  We can't do that right now because
+   then we'd get multiple-symbol clashes with toplev.c and several
+   other people. */
 static char *
 xcalloc (number, size)
      unsigned number, size;
@@ -7346,7 +6591,7 @@
   return ptr;
 }
 
-static char *
+char *
 savestring (input)
      char *input;
 {
============================================================
Index: cpplib.h
--- cpplib.h	1998/10/11 00:05:11	1.10
+++ cpplib.h	1998/10/25 20:01:09
@@ -510,6 +510,27 @@
 #define CPP_PEDANTIC(PFILE) (CPP_OPTIONS (PFILE)->pedantic)
 #define CPP_PRINT_DEPS(PFILE) (CPP_OPTIONS (PFILE)->print_deps)
 
+struct file_name_list
+  {
+    struct file_name_list *next;
+    char *fname;
+    /* If the following is nonzero, it is a macro name.
+       Don't include the file again if that macro is defined.  */
+    U_CHAR *control_macro;
+    /* If the following is nonzero, it is a C-language system include
+       directory.  */
+    int c_system_include_path;
+    /* Mapping of file names for this directory.  */
+    struct file_name_map *name_map;
+    /* Non-zero if name_map is valid.  */
+    int got_name_map;
+  };
+
+/* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found
+   via the same directory as the file that #included it.  */
+#define SELF_DIR_DUMMY ((struct file_name_list *) (~0))
+
+    
 /* Name under which this program was invoked.  */
 
 extern char *progname;
@@ -623,6 +644,8 @@
 };
 
 extern unsigned char is_idchar[256];
+extern unsigned char is_hor_space[256];
+extern unsigned char is_space[256];
 
 /* Stack of conditionals currently in progress
    (including both successful and failing conditionals).  */
@@ -685,6 +708,25 @@
 extern void cpp_file_line_for_message PROTO ((cpp_reader *, char *, int, int));
 extern void cpp_print_containing_files PROTO ((cpp_reader *));
 
+/* In cppfiles.c */
+extern void append_include_chain	PROTO ((cpp_reader *,
+						struct file_name_list *,
+						struct file_name_list *));
+extern int finclude			PROTO ((cpp_reader *, int, char *,
+						int, struct file_name_list *));
+extern int find_include_file		PROTO ((cpp_reader *, char *,
+						unsigned long, char *, int,
+						struct file_name_list *,
+						struct file_name_list **));
+extern void deps_output			PROTO ((cpp_reader *, char *, int));
+
+/* Bleargh. */
+extern char *savestring			PROTO ((char *));
+#ifndef INCLUDE_LEN_FUDGE
+#define INCLUDE_LEN_FUDGE 0
+#endif
+
+    
 #ifdef __cplusplus
 }
 #endif
============================================================
Index: cppfiles.c
--- cppfiles.c	Wed Dec 31 19:00:00 1969
+++ cppfiles.c	Sun Oct 25 14:31:39 1998	1.1
@@ -0,0 +1,1023 @@
+/* Part of CPP library.  (include file handling)
+   Copyright (C) 1986, 87, 89, 92 - 95, 1998 Free Software Foundation, Inc.
+   Written by Per Bothner, 1994.
+   Based on CCCP program by Paul Rubin, June 1986
+   Adapted to ANSI C, Richard Stallman, Jan 1987
+   Split out of cpplib.c, Zack Weinberg, Oct 1998
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them.   Help stamp out software-hoarding!  */
+
+#include "config.h"
+#include "system.h"
+#include "gansidecl.h"
+#include "cpplib.h"
+
+/* The entry points to this file are: find_include_file, finclude,
+   append_include_chain, deps_output, and file_cleanup.
+   file_cleanup is only called through CPP_BUFFER(pfile)->cleanup,
+   so it's static anyway. */
+
+static void add_import			PROTO ((cpp_reader *, int, char *));
+static int lookup_import		PROTO ((cpp_reader *, char *,
+						struct file_name_list *));
+static int redundant_include_p		PROTO ((cpp_reader *, char *));
+static struct file_name_map *read_name_map	PROTO ((cpp_reader *, char *));
+static char *read_filename_string	PROTO ((int, FILE *));
+static int open_include_file		PROTO ((cpp_reader *, char *,
+						struct file_name_list *));
+static int safe_read			PROTO ((int, char *, int));
+
+/* Not safe to prototype these. */
+extern char *xmalloc();
+extern char *xrealloc();
+
+/* Append a chain of `struct file_name_list's
+   to the end of the main include chain.
+   FIRST is the beginning of the chain to append, and LAST is the end.  */
+
+void
+append_include_chain (pfile, first, last)
+     cpp_reader *pfile;
+     struct file_name_list *first, *last;
+{
+  struct cpp_options *opts = CPP_OPTIONS (pfile);
+  struct file_name_list *dir;
+
+  if (!first || !last)
+    return;
+
+  if (opts->include == 0)
+    opts->include = first;
+  else
+    opts->last_include->next = first;
+
+  if (opts->first_bracket_include == 0)
+    opts->first_bracket_include = first;
+
+  for (dir = first; ; dir = dir->next) {
+    int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE;
+    if (len > pfile->max_include_len)
+      pfile->max_include_len = len;
+    if (dir == last)
+      break;
+  }
+
+  last->next = NULL;
+  opts->last_include = last;
+}
+
+/* Add output to `deps_buffer' for the -M switch.
+   STRING points to the text to be output.
+   SPACER is ':' for targets, ' ' for dependencies, zero for text
+   to be inserted literally.  */
+
+void
+deps_output (pfile, string, spacer)
+     cpp_reader *pfile;
+     char *string;
+     int spacer;
+{
+  int size;
+
+  if (!*string)
+    return;
+
+#ifdef VMS
+  hack_vms_include_specification (string);
+#endif
+
+  size = strlen (string);
+
+#ifndef MAX_OUTPUT_COLUMNS
+#define MAX_OUTPUT_COLUMNS 72
+#endif
+  if (spacer
+      && pfile->deps_column > 0
+      && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS)
+    {
+      deps_output (pfile, " \\\n  ", 0);
+      pfile->deps_column = 0;
+    }
+
+  if (pfile->deps_size + size + 8 > pfile->deps_allocated_size)
+    {
+      pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2;
+      pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer,
+					      pfile->deps_allocated_size);
+    }
+  if (spacer == ' ' && pfile->deps_column > 0)
+    pfile->deps_buffer[pfile->deps_size++] = ' ';
+  bcopy (string, &pfile->deps_buffer[pfile->deps_size], size);
+  pfile->deps_size += size;
+  pfile->deps_column += size;
+  if (spacer == ':')
+    pfile->deps_buffer[pfile->deps_size++] = ':';
+  pfile->deps_buffer[pfile->deps_size] = 0;
+}
+
+static int
+file_cleanup (pbuf, pfile)
+     cpp_buffer *pbuf;
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+{
+  if (pbuf->buf)
+    {
+      free (pbuf->buf);
+      pbuf->buf = 0;
+    }
+  return 0;
+}
+
+int
+find_include_file (pfile, fbeg, flen, fname,
+		   importing, search_start, foundhere)
+     cpp_reader *pfile;
+     char *fbeg;
+     unsigned long flen;
+     char *fname;
+     int importing;
+     struct file_name_list *search_start;
+     struct file_name_list **foundhere;
+{
+  struct file_name_list *searchptr;
+  int f;
+    
+  /* If specified file name is absolute, just open it.  */
+
+  if (*fbeg == '/')
+  {
+    strcpy (fname, fbeg);
+#ifdef VMS
+    hack_vms_include_specification (fname);
+#endif
+    if (redundant_include_p (pfile, fname))
+      return -2;
+    if (importing)
+      f = lookup_import (pfile, fname, NULL_PTR);
+    else
+      f = open_include_file (pfile, fname, NULL_PTR);
+    if (f == -2)
+      return -2;	/* Already included this file */
+  }
+  else
+  {
+    /* Search directory path, trying to open the file.
+       Copy each filename tried into FNAME.  */
+
+    for (searchptr = search_start; searchptr; searchptr = searchptr->next)
+    {
+      unsigned int l = 0;
+      if (searchptr->fname)
+      {
+	/* The empty string in a search path is ignored.
+	   This makes it possible to turn off entirely
+	   a standard piece of the list.  */
+	if (searchptr->fname[0] == 0)
+	  continue;
+
+	l = strlen (searchptr->fname);
+
+	bcopy (searchptr->fname, fname, l);
+	fname[l++] = '/';
+      }
+
+      bcopy (fbeg, &fname[l], flen);
+      fname[flen+l] = '\0';
+#ifdef VMS
+      hack_vms_include_specification (fname);
+#endif /* VMS */
+      /* ??? There are currently 3 separate mechanisms for avoiding processing
+	 of redundant include files: #import, #pragma once, and
+	 redundant_include_p.  It would be nice if they were unified.  */
+      if (redundant_include_p (pfile, fname))
+	return -2;
+      if (importing)
+	f = lookup_import (pfile, fname, searchptr);
+      else
+	f = open_include_file (pfile, fname, searchptr);
+      if (f == -2)
+	return -2;			/* Already included this file */
+#ifdef EACCES
+      else if (f == -1 && errno == EACCES)
+	cpp_warning (pfile, "Header file %s exists, but is not readable",
+		     fname);
+#endif
+      if (f >= 0)
+	break;
+    }
+  }
+
+  if (f < 0)
+    {
+      /* A file that was not found.  */
+      bcopy (fbeg, fname, flen);
+      fname[flen] = 0;
+
+      return -1;
+    }
+  else
+    {
+      /* Check to see if this include file is a once-only include file.
+	 If so, give up.  */
+
+      struct file_name_list *ptr;
+
+      for (ptr = pfile->dont_repeat_files; ptr; ptr = ptr->next)
+	  if (!strcmp (ptr->fname, fname))
+	    {
+	      close (f);
+	      return -2;		/* This file was once'd.  */
+	    }
+    }
+
+    /* Record file on "seen" list for #import.  */
+    add_import (pfile, f, fname);
+
+    *foundhere = searchptr;
+    return f;
+}
+
+/* Return nonzero if there is no need to include file NAME
+   because it has already been included and it contains a conditional
+   to make a repeated include do nothing.  */
+
+static int
+redundant_include_p (pfile, name)
+     cpp_reader *pfile;
+     char *name;
+{
+  struct file_name_list *l = pfile->all_include_files;
+  for (; l; l = l->next)
+    if (! strcmp (name, l->fname)
+	&& l->control_macro
+	&& cpp_lookup (pfile, l->control_macro, -1, -1))
+      return 1;
+  return 0;
+}
+
+
+
+/* Maintain and search list of included files, for #import.  */
+
+/* Hash a file name for import_hash_table.  */
+
+static int 
+import_hash (f)
+     char *f;
+{
+  int val = 0;
+
+  while (*f) val += *f++;
+  return (val%IMPORT_HASH_SIZE);
+}
+
+/* Search for file FILENAME in import_hash_table.
+   Return -2 if found, either a matching name or a matching inode.
+   Otherwise, open the file and return a file descriptor if successful
+   or -1 if unsuccessful.  */
+
+static int
+lookup_import (pfile, filename, searchptr)
+     cpp_reader *pfile;
+     char *filename;
+     struct file_name_list *searchptr;
+{
+  struct import_file *i;
+  int h;
+  int hashval;
+  struct stat sb;
+  int fd;
+
+  hashval = import_hash (filename);
+
+  /* Attempt to find file in list of already included files */
+  i = pfile->import_hash_table[hashval];
+
+  while (i) {
+    if (!strcmp (filename, i->name))
+      return -2;		/* return found */
+    i = i->next;
+  }
+  /* Open it and try a match on inode/dev */
+  fd = open_include_file (pfile, filename, searchptr);
+  if (fd < 0)
+    return fd;
+  fstat (fd, &sb);
+  for (h = 0; h < IMPORT_HASH_SIZE; h++) {
+    i = pfile->import_hash_table[h];
+    while (i) {
+      /* Compare the inode and the device.
+	 Supposedly on some systems the inode is not a scalar.  */
+      if (!bcmp ((char *) &i->inode, (char *) &sb.st_ino, sizeof (sb.st_ino))
+	  && i->dev == sb.st_dev) {
+        close (fd);
+        return -2;		/* return found */
+      }
+      i = i->next;
+    }
+  }
+  return fd;			/* Not found, return open file */
+}
+
+/* Add the file FNAME, open on descriptor FD, to import_hash_table.  */
+
+static void
+add_import (pfile, fd, fname)
+     cpp_reader *pfile;
+     int fd;
+     char *fname;
+{
+  struct import_file *i;
+  int hashval;
+  struct stat sb;
+
+  hashval = import_hash (fname);
+  fstat (fd, &sb);
+  i = (struct import_file *)xmalloc (sizeof (struct import_file));
+  i->name = (char *)xmalloc (strlen (fname)+1);
+  strcpy (i->name, fname);
+  bcopy ((char *) &sb.st_ino, (char *) &i->inode, sizeof (sb.st_ino));
+  i->dev = sb.st_dev;
+  i->next = pfile->import_hash_table[hashval];
+  pfile->import_hash_table[hashval] = i;
+}
+
+/* The file_name_map structure holds a mapping of file names for a
+   particular directory.  This mapping is read from the file named
+   FILE_NAME_MAP_FILE in that directory.  Such a file can be used to
+   map filenames on a file system with severe filename restrictions,
+   such as DOS.  The format of the file name map file is just a series
+   of lines with two tokens on each line.  The first token is the name
+   to map, and the second token is the actual name to use.  */
+
+struct file_name_map
+{
+  struct file_name_map *map_next;
+  char *map_from;
+  char *map_to;
+};
+
+#define FILE_NAME_MAP_FILE "header.gcc"
+
+/* Read a space delimited string of unlimited length from a stdio
+   file.  */
+
+static char *
+read_filename_string (ch, f)
+     int ch;
+     FILE *f;
+{
+  char *alloc, *set;
+  int len;
+
+  len = 20;
+  set = alloc = xmalloc (len + 1);
+  if (! is_space[ch])
+    {
+      *set++ = ch;
+      while ((ch = getc (f)) != EOF && ! is_space[ch])
+	{
+	  if (set - alloc == len)
+	    {
+	      len *= 2;
+	      alloc = xrealloc (alloc, len + 1);
+	      set = alloc + len / 2;
+	    }
+	  *set++ = ch;
+	}
+    }
+  *set = '\0';
+  ungetc (ch, f);
+  return alloc;
+}
+
+/* This structure holds a linked list of file name maps, one per directory.  */
+
+struct file_name_map_list
+{
+  struct file_name_map_list *map_list_next;
+  char *map_list_name;
+  struct file_name_map *map_list_map;
+};
+
+/* Read the file name map file for DIRNAME.  */
+
+static struct file_name_map *
+read_name_map (pfile, dirname)
+     cpp_reader *pfile;
+     char *dirname;
+{
+  register struct file_name_map_list *map_list_ptr;
+  char *name;
+  FILE *f;
+
+  for (map_list_ptr = CPP_OPTIONS (pfile)->map_list; map_list_ptr;
+       map_list_ptr = map_list_ptr->map_list_next)
+    if (! strcmp (map_list_ptr->map_list_name, dirname))
+      return map_list_ptr->map_list_map;
+
+  map_list_ptr = ((struct file_name_map_list *)
+		  xmalloc (sizeof (struct file_name_map_list)));
+  map_list_ptr->map_list_name = savestring (dirname);
+  map_list_ptr->map_list_map = NULL;
+
+  name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
+  strcpy (name, dirname);
+  if (*dirname)
+    strcat (name, "/");
+  strcat (name, FILE_NAME_MAP_FILE);
+  f = fopen (name, "r");
+  if (!f)
+    map_list_ptr->map_list_map = NULL;
+  else
+    {
+      int ch;
+      int dirlen = strlen (dirname);
+
+      while ((ch = getc (f)) != EOF)
+	{
+	  char *from, *to;
+	  struct file_name_map *ptr;
+
+	  if (is_space[ch])
+	    continue;
+	  from = read_filename_string (ch, f);
+	  while ((ch = getc (f)) != EOF && is_hor_space[ch])
+	    ;
+	  to = read_filename_string (ch, f);
+
+	  ptr = ((struct file_name_map *)
+		 xmalloc (sizeof (struct file_name_map)));
+	  ptr->map_from = from;
+
+	  /* Make the real filename absolute.  */
+	  if (*to == '/')
+	    ptr->map_to = to;
+	  else
+	    {
+	      ptr->map_to = xmalloc (dirlen + strlen (to) + 2);
+	      strcpy (ptr->map_to, dirname);
+	      ptr->map_to[dirlen] = '/';
+	      strcpy (ptr->map_to + dirlen + 1, to);
+	      free (to);
+	    }	      
+
+	  ptr->map_next = map_list_ptr->map_list_map;
+	  map_list_ptr->map_list_map = ptr;
+
+	  while ((ch = getc (f)) != '\n')
+	    if (ch == EOF)
+	      break;
+	}
+      fclose (f);
+    }
+  
+  map_list_ptr->map_list_next = CPP_OPTIONS (pfile)->map_list;
+  CPP_OPTIONS (pfile)->map_list = map_list_ptr;
+
+  return map_list_ptr->map_list_map;
+}  
+
+/* Try to open include file FILENAME.  SEARCHPTR is the directory
+   being tried from the include file search path.  This function maps
+   filenames on file systems based on information read by
+   read_name_map.  */
+
+static int
+open_include_file (pfile, filename, searchptr)
+     cpp_reader *pfile;
+     char *filename;
+     struct file_name_list *searchptr;
+{
+  if (CPP_OPTIONS (pfile)->remap)
+    {
+      register struct file_name_map *map;
+      register char *from;
+      char *p, *dir;
+
+      if (searchptr && ! searchptr->got_name_map)
+	{
+	  searchptr->name_map = read_name_map (pfile,
+					       searchptr->fname
+					       ? searchptr->fname : ".");
+	  searchptr->got_name_map = 1;
+	}
+
+      /* First check the mapping for the directory we are using.  */
+      if (searchptr && searchptr->name_map)
+	{
+	  from = filename;
+	  if (searchptr->fname)
+	    from += strlen (searchptr->fname) + 1;
+	  for (map = searchptr->name_map; map; map = map->map_next)
+	    {
+	      if (! strcmp (map->map_from, from))
+		{
+		  /* Found a match.  */
+		  return open (map->map_to, O_RDONLY, 0666);
+		}
+	    }
+	}
+
+      /* Try to find a mapping file for the particular directory we are
+	 looking in.  Thus #include <sys/types.h> will look up sys/types.h
+	 in /usr/include/header.gcc and look up types.h in
+	 /usr/include/sys/header.gcc.  */
+      p = rindex (filename, '/');
+      if (! p)
+	p = filename;
+      if (searchptr
+	  && searchptr->fname
+	  && strlen (searchptr->fname) == (size_t) (p - filename)
+	  && ! strncmp (searchptr->fname, filename, p - filename))
+	{
+	  /* FILENAME is in SEARCHPTR, which we've already checked.  */
+	  return open (filename, O_RDONLY, 0666);
+	}
+
+      if (p == filename)
+	{
+	  dir = ".";
+	  from = filename;
+	}
+      else
+	{
+	  dir = (char *) alloca (p - filename + 1);
+	  bcopy (filename, dir, p - filename);
+	  dir[p - filename] = '\0';
+	  from = p + 1;
+	}
+      for (map = read_name_map (pfile, dir); map; map = map->map_next)
+	if (! strcmp (map->map_from, from))
+	  return open (map->map_to, O_RDONLY, 0666);
+    }
+
+  return open (filename, O_RDONLY, 0666);
+}
+
+/* Process the contents of include file FNAME, already open on descriptor F,
+   with output to OP.
+   SYSTEM_HEADER_P is 1 if this file resides in any one of the known
+   "system" include directories (as decided by the `is_system_include'
+   function above).
+   DIRPTR is the link in the dir path through which this file was found,
+   or 0 if the file name was absolute or via the current directory.
+   Return 1 on success, 0 on failure.
+
+   The caller is responsible for the cpp_push_buffer.  */
+
+int
+finclude (pfile, f, fname, system_header_p, dirptr)
+     cpp_reader *pfile;
+     int f;
+     char *fname;
+     int system_header_p;
+     struct file_name_list *dirptr;
+{
+  struct stat st;
+  size_t st_size;
+  long i;
+  int length;
+  cpp_buffer *fp;			/* For input stack frame */
+#if 0
+  int missing_newline = 0;
+#endif
+
+  if (fstat (f, &st) < 0)
+    {
+      cpp_perror_with_name (pfile, fname);
+      close (f);
+      cpp_pop_buffer (pfile);
+      return 0;
+    }
+
+  fp = CPP_BUFFER (pfile);
+  fp->nominal_fname = fp->fname = fname;
+#if 0
+  fp->length = 0;
+#endif
+  fp->dir = dirptr;
+  fp->system_header_p = system_header_p;
+  fp->lineno = 1;
+  fp->colno = 1;
+  fp->cleanup = file_cleanup;
+
+  if (S_ISREG (st.st_mode)) {
+    st_size = (size_t) st.st_size;
+    if (st_size != st.st_size || st_size + 2 < st_size) {
+      cpp_error (pfile, "file `%s' too large", fname);
+      close (f);
+      return 0;
+    }
+    fp->buf = (U_CHAR *) xmalloc (st_size + 2);
+    fp->alimit = fp->buf + st_size + 2;
+    fp->cur = fp->buf;
+
+    /* Read the file contents, knowing that st_size is an upper bound
+       on the number of bytes we can read.  */
+    length = safe_read (f, fp->buf, st_size);
+    fp->rlimit = fp->buf + length;
+    if (length < 0) goto nope;
+  }
+  else if (S_ISDIR (st.st_mode)) {
+    cpp_error (pfile, "directory `%s' specified in #include", fname);
+    close (f);
+    return 0;
+  } else {
+    /* Cannot count its file size before reading.
+       First read the entire file into heap and
+       copy them into buffer on stack.  */
+
+    size_t bsize = 2000;
+
+    st_size = 0;
+    fp->buf = (U_CHAR *) xmalloc (bsize + 2);
+
+    for (;;) {
+      i = safe_read (f, fp->buf + st_size, bsize - st_size);
+      if (i < 0)
+	goto nope;      /* error! */
+      st_size += i;
+      if (st_size != bsize)
+	break;	/* End of file */
+      bsize *= 2;
+      fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2);
+    }
+    fp->cur = fp->buf;
+    length = st_size;
+  }
+
+  if ((length > 0 && fp->buf[length - 1] != '\n')
+      /* Backslash-newline at end is not good enough.  */
+      || (length > 1 && fp->buf[length - 2] == '\\')) {
+    fp->buf[length++] = '\n';
+#if 0
+    missing_newline = 1;
+#endif
+  }
+  fp->buf[length] = '\0';
+  fp->rlimit = fp->buf + length;
+
+  /* Close descriptor now, so nesting does not use lots of descriptors.  */
+  close (f);
+
+  /* Must do this before calling trigraph_pcp, so that the correct file name
+     will be printed in warning messages.  */
+
+  pfile->input_stack_listing_current = 0;
+
+#if 0
+  if (!no_trigraphs)
+    trigraph_pcp (fp);
+#endif
+
+#if 0
+  rescan (op, 0);
+
+  if (missing_newline)
+    fp->lineno--;
+
+  if (CPP_PEDANTIC (pfile) && missing_newline)
+    pedwarn ("file does not end in newline");
+
+  indepth--;
+  input_file_stack_tick++;
+  free (fp->buf);
+#endif
+  return 1;
+
+ nope:
+
+  cpp_perror_with_name (pfile, fname);
+  close (f);
+  free (fp->buf);
+  return 1;
+}
+
+/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
+   retrying if necessary.  If MAX_READ_LEN is defined, read at most
+   that bytes at a time.  Return a negative value if an error occurs,
+   otherwise return the actual number of bytes read,
+   which must be LEN unless end-of-file was reached.  */
+
+static int
+safe_read (desc, ptr, len)
+     int desc;
+     char *ptr;
+     int len;
+{
+  int left, rcount, nchars;
+
+  left = len;
+  while (left > 0) {
+    rcount = left;
+#ifdef MAX_READ_LEN
+    if (rcount > MAX_READ_LEN)
+      rcount = MAX_READ_LEN;
+#endif
+    nchars = read (desc, ptr, rcount);
+    if (nchars < 0)
+      {
+#ifdef EINTR
+	if (errno == EINTR)
+	  continue;
+#endif
+	return nchars;
+      }
+    if (nchars == 0)
+      break;
+    ptr += nchars;
+    left -= nchars;
+  }
+  return len - left;
+}
+
+#ifdef VMS
+
+/* Under VMS we need to fix up the "include" specification filename.
+
+   Rules for possible conversions
+
+	fullname		tried paths
+
+	name			name
+	./dir/name		[.dir]name
+	/dir/name		dir:name
+	/name			[000000]name, name
+	dir/name		dir:[000000]name, dir:name, dir/name
+	dir1/dir2/name		dir1:[dir2]name, dir1:[000000.dir2]name
+	path:/name		path:[000000]name, path:name
+	path:/dir/name		path:[000000.dir]name, path:[dir]name
+	path:dir/name		path:[dir]name
+	[path]:[dir]name	[path.dir]name
+	path/[dir]name		[path.dir]name
+
+   The path:/name input is constructed when expanding <> includes. */
+
+
+static void
+hack_vms_include_specification (fullname)
+     char *fullname;
+{
+  register char *basename, *unixname, *local_ptr, *first_slash;
+  int f, check_filename_before_returning, must_revert;
+  char Local[512];
+
+  check_filename_before_returning = 0;
+  must_revert = 0;
+  /* See if we can find a 1st slash. If not, there's no path information.  */
+  first_slash = index (fullname, '/');
+  if (first_slash == 0)
+    return 0;				/* Nothing to do!!! */
+
+  /* construct device spec if none given.  */
+
+  if (index (fullname, ':') == 0)
+    {
+
+      /* If fullname has a slash, take it as device spec.  */
+
+      if (first_slash == fullname)
+	{
+	  first_slash = index (fullname+1, '/');	/* 2nd slash ? */
+	  if (first_slash)
+	    *first_slash = ':';				/* make device spec  */
+	  for (basename = fullname; *basename != 0; basename++)
+	    *basename = *(basename+1);			/* remove leading slash  */
+	}
+      else if ((first_slash[-1] != '.')		/* keep ':/', './' */
+	    && (first_slash[-1] != ':')
+	    && (first_slash[-1] != ']'))	/* or a vms path  */
+	{
+	  *first_slash = ':';
+	}
+      else if ((first_slash[1] == '[')		/* skip './' in './[dir'  */
+	    && (first_slash[-1] == '.'))
+	fullname += 2;
+    }
+
+  /* Get part after first ':' (basename[-1] == ':')
+     or last '/' (basename[-1] == '/').  */
+
+  basename = base_name (fullname);
+
+  local_ptr = Local;			/* initialize */
+
+  /* We are trying to do a number of things here.  First of all, we are
+     trying to hammer the filenames into a standard format, such that later
+     processing can handle them.
+     
+     If the file name contains something like [dir.], then it recognizes this
+     as a root, and strips the ".]".  Later processing will add whatever is
+     needed to get things working properly.
+     
+     If no device is specified, then the first directory name is taken to be
+     a device name (or a rooted logical).  */
+
+  /* Point to the UNIX filename part (which needs to be fixed!)
+     but skip vms path information.
+     [basename != fullname since first_slash != 0].  */
+
+  if ((basename[-1] == ':')		/* vms path spec.  */
+      || (basename[-1] == ']')
+      || (basename[-1] == '>'))
+    unixname = basename;
+  else
+    unixname = fullname;
+
+  if (*unixname == '/')
+    unixname++;
+
+  /* If the directory spec is not rooted, we can just copy
+     the UNIX filename part and we are done.  */
+
+  if (((basename - fullname) > 1)
+     && (  (basename[-1] == ']')
+        || (basename[-1] == '>')))
+    {
+      if (basename[-2] != '.')
+	{
+
+	/* The VMS part ends in a `]', and the preceding character is not a `.'.
+	   -> PATH]:/name (basename = '/name', unixname = 'name')
+	   We strip the `]', and then splice the two parts of the name in the
+	   usual way.  Given the default locations for include files in cccp.c,
+	   we will only use this code if the user specifies alternate locations
+	   with the /include (-I) switch on the command line.  */
+
+	  basename -= 1;	/* Strip "]" */
+	  unixname--;		/* backspace */
+	}
+      else
+	{
+
+	/* The VMS part has a ".]" at the end, and this will not do.  Later
+	   processing will add a second directory spec, and this would be a syntax
+	   error.  Thus we strip the ".]", and thus merge the directory specs.
+	   We also backspace unixname, so that it points to a '/'.  This inhibits the
+	   generation of the 000000 root directory spec (which does not belong here
+	   in this case).  */
+
+	  basename -= 2;	/* Strip ".]" */
+	  unixname--;		/* backspace */
+	}
+    }
+
+  else
+
+    {
+
+      /* We drop in here if there is no VMS style directory specification yet.
+         If there is no device specification either, we make the first dir a
+         device and try that.  If we do not do this, then we will be essentially
+         searching the users default directory (as if they did a #include "asdf.h").
+        
+         Then all we need to do is to push a '[' into the output string. Later
+         processing will fill this in, and close the bracket.  */
+
+      if ((unixname != fullname)	/* vms path spec found.  */
+	 && (basename[-1] != ':'))
+	*local_ptr++ = ':';		/* dev not in spec.  take first dir */
+
+      *local_ptr++ = '[';		/* Open the directory specification */
+    }
+
+    if (unixname == fullname)		/* no vms dir spec.  */
+      {
+	must_revert = 1;
+	if ((first_slash != 0)		/* unix dir spec.  */
+	    && (*unixname != '/')	/* not beginning with '/'  */
+	    && (*unixname != '.'))	/* or './' or '../'  */
+	  *local_ptr++ = '.';		/* dir is local !  */
+      }
+
+  /* at this point we assume that we have the device spec, and (at least
+     the opening "[" for a directory specification.  We may have directories
+     specified already.
+
+     If there are no other slashes then the filename will be
+     in the "root" directory.  Otherwise, we need to add
+     directory specifications.  */
+
+  if (index (unixname, '/') == 0)
+    {
+      /* if no directories specified yet and none are following.  */
+      if (local_ptr[-1] == '[')
+	{
+	  /* Just add "000000]" as the directory string */
+	  strcpy (local_ptr, "000000]");
+	  local_ptr += strlen (local_ptr);
+	  check_filename_before_returning = 1; /* we might need to fool with this later */
+	}
+    }
+  else
+    {
+
+      /* As long as there are still subdirectories to add, do them.  */
+      while (index (unixname, '/') != 0)
+	{
+	  /* If this token is "." we can ignore it
+	       if it's not at the beginning of a path.  */
+	  if ((unixname[0] == '.') && (unixname[1] == '/'))
+	    {
+	      /* remove it at beginning of path.  */
+	      if (  ((unixname == fullname)		/* no device spec  */
+		    && (fullname+2 != basename))	/* starts with ./ */
+							/* or  */
+		 || ((basename[-1] == ':')		/* device spec  */
+		    && (unixname-1 == basename)))	/* and ./ afterwards  */
+		*local_ptr++ = '.';		 	/* make '[.' start of path.  */
+	      unixname += 2;
+	      continue;
+	    }
+
+	  /* Add a subdirectory spec. Do not duplicate "." */
+	  if (  local_ptr[-1] != '.'
+	     && local_ptr[-1] != '['
+	     && local_ptr[-1] != '<')
+	    *local_ptr++ = '.';
+
+	  /* If this is ".." then the spec becomes "-" */
+	  if (  (unixname[0] == '.')
+	     && (unixname[1] == '.')
+	     && (unixname[2] == '/'))
+	    {
+	      /* Add "-" and skip the ".." */
+	      if ((local_ptr[-1] == '.')
+		  && (local_ptr[-2] == '['))
+		local_ptr--;			/* prevent [.-  */
+	      *local_ptr++ = '-';
+	      unixname += 3;
+	      continue;
+	    }
+
+	  /* Copy the subdirectory */
+	  while (*unixname != '/')
+	    *local_ptr++= *unixname++;
+
+	  unixname++;			/* Skip the "/" */
+	}
+
+      /* Close the directory specification */
+      if (local_ptr[-1] == '.')		/* no trailing periods */
+	local_ptr--;
+
+      if (local_ptr[-1] == '[')		/* no dir needed */
+	local_ptr--;
+      else
+	*local_ptr++ = ']';
+    }
+
+  /* Now add the filename.  */
+
+  while (*unixname)
+    *local_ptr++ = *unixname++;
+  *local_ptr = 0;
+
+  /* Now append it to the original VMS spec.  */
+
+  strcpy ((must_revert==1)?fullname:basename, Local);
+
+  /* If we put a [000000] in the filename, try to open it first. If this fails,
+     remove the [000000], and return that name.  This provides flexibility
+     to the user in that they can use both rooted and non-rooted logical names
+     to point to the location of the file.  */
+
+  if (check_filename_before_returning)
+    {
+      f = open (fullname, O_RDONLY, 0666);
+      if (f >= 0)
+	{
+	  /* The file name is OK as it is, so return it as is.  */
+	  close (f);
+	  return 1;
+	}
+
+      /* The filename did not work.  Try to remove the [000000] from the name,
+	 and return it.  */
+
+      basename = index (fullname, '[');
+      local_ptr = index (fullname, ']') + 1;
+      strcpy (basename, local_ptr);		/* this gets rid of it */
+
+    }
+
+  return 1;
+}
+#endif	/* VMS */



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]