OSDN Git Service

* config/i386/sol2.h (PREFERRED_DEBUGGING_TYPE): Use stabs.
[pf3gnuchains/gcc-fork.git] / gcc / cccp.c
index a989bbe..4a90648 100644 (file)
@@ -1,5 +1,5 @@
 /* C Compatible Compiler Preprocessor (CCCP)
-   Copyright (C) 1986, 87, 89, 92-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1986, 87, 89, 92-98, 1999 Free Software Foundation, Inc.
    Written by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
 
@@ -19,72 +19,27 @@ Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA. */
 
 #include "config.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <signal.h>
 
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-#  include <time.h>
-#endif
-#endif
+#include "system.h"
+#include <signal.h>
 
 #ifdef HAVE_SYS_RESOURCE_H
 # include <sys/resource.h>
 #endif
 
-#if HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
-
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#include <errno.h>
-
-#if HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-#endif
-#endif
-
 typedef unsigned char U_CHAR;
 
-#include "gansidecl.h"
 #include "pcp.h"
+#include "intl.h"
+#include "prefix.h"
 
-#ifdef NEED_DECLARATION_INDEX
-extern char *index ();
-#endif
-
-#ifdef NEED_DECLARATION_RINDEX
-extern char *rindex ();
-#endif
-
-#ifdef NEED_DECLARATION_GETENV
-extern char *getenv ();
-#endif
+#ifdef MULTIBYTE_CHARS
+#include "mbchar.h"
+#include <locale.h>
+#endif /* MULTIBYTE_CHARS */
 
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
-# define __attribute__(x)
+#ifndef GET_ENV_PATH_LIST
+#define GET_ENV_PATH_LIST(VAR,NAME)    do { (VAR) = getenv (NAME); } while (0)
 #endif
 
 #ifndef STANDARD_INCLUDE_DIR
@@ -96,6 +51,11 @@ extern char *getenv ();
 # define PATH_SEPARATOR ':'
 #endif
 
+/* By default, a slash separates directory names.  */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+#endif
+
 /* By default, the suffix for object files is ".o".  */
 #ifdef OBJECT_SUFFIX
 # define HAVE_OBJECT_SUFFIX
@@ -103,30 +63,6 @@ extern char *getenv ();
 # define OBJECT_SUFFIX ".o"
 #endif
 
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-# include <stdarg.h>
-# define PRINTF_ALIST(msg) char *msg, ...
-# define PRINTF_DCL(msg)
-# define PRINTF_PROTO(ARGS, m, n) PROTO (ARGS) __attribute__ ((format (__printf__, m, n)))
-#else
-# include <varargs.h>
-# define PRINTF_ALIST(msg) msg, va_alist
-# define PRINTF_DCL(msg) char *msg; va_dcl
-# define PRINTF_PROTO(ARGS, m, n) () __attribute__ ((format (__printf__, m, n)))
-# define vfprintf(file, msg, args) \
-    { \
-      char *a0 = va_arg(args, char *); \
-      char *a1 = va_arg(args, char *); \
-      char *a2 = va_arg(args, char *); \
-      char *a3 = va_arg(args, char *); \
-      fprintf (file, msg, a0, a1, a2, a3); \
-    }
-#endif
-
-#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
-#define PRINTF_PROTO_2(ARGS) PRINTF_PROTO(ARGS, 2, 3)
-#define PRINTF_PROTO_3(ARGS) PRINTF_PROTO(ARGS, 3, 4)
-
 /* VMS-specific definitions */
 #ifdef VMS
 #include <descrip.h>
@@ -136,10 +72,12 @@ extern char *getenv ();
 #define fopen(fname,mode)      VMS_fopen (fname,mode)
 #define freopen(fname,mode,ofile) VMS_freopen (fname,mode,ofile)
 #define fstat(fd,stbuf)                VMS_fstat (fd,stbuf)
+#define fwrite(ptr,size,nitems,stream) VMS_fwrite (ptr,size,nitems,stream)
 static int VMS_fstat (), VMS_stat ();
 static int VMS_open ();
 static FILE *VMS_fopen ();
 static FILE *VMS_freopen ();
+static size_t VMS_fwrite ();
 static void hack_vms_include_specification ();
 #define INO_T_EQ(a, b) (!bcmp((char *) &(a), (char *) &(b), sizeof (a)))
 #define INO_T_HASH(a) 0
@@ -147,47 +85,11 @@ static void hack_vms_include_specification ();
 #endif /* VMS */
 
 /* Windows does not natively support inodes, and neither does MSDOS.  */
-#if (defined (_WIN32) && ! defined (CYGWIN32)) || defined (__MSDOS__)
+#if (defined (_WIN32) && ! defined (__CYGWIN__) && ! defined (_UWIN)) \
+  || defined (__MSDOS__)
 #define INO_T_EQ(a, b) 0
 #endif
 
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-
-#undef MIN
-#undef MAX
-#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
-#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
-
-/* Find the largest host integer type and set its size and type.
-   Watch out: on some crazy hosts `long' is shorter than `int'.  */
-
-#ifndef HOST_WIDE_INT
-# if HAVE_INTTYPES_H
-#  include <inttypes.h>
-#  define HOST_WIDE_INT intmax_t
-# else
-#  if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)
-#   define HOST_WIDE_INT int
-#  else
-#  if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG || ! (defined LONG_LONG_MAX || defined LLONG_MAX))
-#   define HOST_WIDE_INT long
-#  else
-#   define HOST_WIDE_INT long long
-#  endif
-#  endif
-# endif
-#endif
-
-#ifndef S_ISREG
-#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-
-#ifndef S_ISDIR
-#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-
 #ifndef INO_T_EQ
 #define INO_T_EQ(a, b) ((a) == (b))
 #endif
@@ -203,23 +105,8 @@ static void hack_vms_include_specification ();
 /* External declarations.  */
 
 extern char *version_string;
-extern char *update_path PROTO((char *, char *));
-#ifndef VMS
-#ifndef HAVE_STRERROR
-extern int sys_nerr;
-extern char *sys_errlist[];
-#else  /* HAVE_STRERROR */
-char *strerror ();
-#endif
-#else  /* VMS */
-char *strerror (int,...);
-#endif
-HOST_WIDE_INT parse_escape PROTO((char **, HOST_WIDE_INT));
-HOST_WIDE_INT parse_c_expression PROTO((char *, int));
-
-#ifndef errno
-extern int errno;
-#endif
+HOST_WIDEST_INT parse_escape PROTO((char **, HOST_WIDEST_INT));
+HOST_WIDEST_INT parse_c_expression PROTO((char *, int));
 \f
 /* Name under which this program was invoked.  */
 
@@ -358,6 +245,10 @@ static int warn_trigraphs;
 
 static int warn_undef;
 
+/* Nonzero means warn if we find white space where it doesn't belong.  */
+
+static int warn_white_space;
+
 /* Nonzero means warn if #import is used.  */
 
 static int warn_import = 1;
@@ -374,6 +265,10 @@ int traditional;
 
 int c89;
 
+/* Nonzero for the 199x C Standard.  */
+
+int c9x;
+
 /* Nonzero causes output not to be done,
    but directives such as #define that have side effects
    are still obeyed.  */
@@ -408,6 +303,8 @@ static struct file_buf {
   char *fname;
   /* Filename specified with #line directive.  */
   char *nominal_fname;
+  /* The length of nominal_fname, which may contain embedded NULs.  */
+  size_t nominal_fname_len;
   /* Include file description.  */
   struct include_file *inc;
   /* Record where in the search path this file was found.
@@ -492,49 +389,49 @@ static struct default_include {
   int cxx_aware;               /* Includes in this directory don't need to
                                   be wrapped in extern "C" when compiling
                                   C++.  */
+  int included;                 /* Set if the directory is acceptable.  */
 } include_defaults_array[]
 #ifdef INCLUDE_DEFAULTS
   = INCLUDE_DEFAULTS;
 #else
   = {
     /* Pick up GNU C++ specific include files.  */
-    { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },
-    { OLD_GPLUSPLUS_INCLUDE_DIR, 0, 1, 1 },
+    { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1, 0 },
 #ifdef CROSS_COMPILE
     /* This is the dir for fixincludes.  Put it just before
        the files that we fix.  */
-    { GCC_INCLUDE_DIR, "GCC", 0, 0 },
+    { GCC_INCLUDE_DIR, "GCC", 0, 0, 0 },
     /* For cross-compilation, this dir name is generated
        automatically in Makefile.in.  */
-    { CROSS_INCLUDE_DIR, "GCC", 0, 0 },
+    { CROSS_INCLUDE_DIR, "GCC", 0, 0, 0 },
 #ifdef TOOL_INCLUDE_DIR
     /* This is another place that the target system's headers might be.  */
-    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
+    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0, 0 },
 #endif
 #else /* not CROSS_COMPILE */
 #ifdef LOCAL_INCLUDE_DIR
     /* This should be /usr/local/include and should come before
        the fixincludes-fixed header files.  */
-    { LOCAL_INCLUDE_DIR, 0, 0, 1 },
+    { LOCAL_INCLUDE_DIR, 0, 0, 1, 0 },
 #endif
 #ifdef TOOL_INCLUDE_DIR
     /* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.
        Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h.  */
-    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
+    { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0, 0 },
 #endif
     /* This is the dir for fixincludes.  Put it just before
        the files that we fix.  */
-    { GCC_INCLUDE_DIR, "GCC", 0, 0 },
+    { GCC_INCLUDE_DIR, "GCC", 0, 0, 0 },
     /* Some systems have an extra dir of include files.  */
 #ifdef SYSTEM_INCLUDE_DIR
-    { SYSTEM_INCLUDE_DIR, 0, 0, 0 },
+    { SYSTEM_INCLUDE_DIR, 0, 0, 0, 0 },
 #endif
 #ifndef STANDARD_INCLUDE_COMPONENT
 #define STANDARD_INCLUDE_COMPONENT 0
 #endif
-    { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 },
+    { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0, 0 },
 #endif /* not CROSS_COMPILE */
-    { 0, 0, 0, 0 }
+    { 0, 0, 0, 0, 0 }
     };
 #endif /* no INCLUDE_DEFAULTS */
 
@@ -646,6 +543,7 @@ struct definition {
   U_CHAR *expansion;
   int line;                    /* Line number of definition */
   char *file;                  /* File of definition */
+  size_t file_len;             /* Length of file (which can contain NULs) */
   char rest_args;              /* Nonzero if last arg. absorbs the rest */
   struct reflist {
     struct reflist *next;
@@ -691,6 +589,11 @@ union hashval {
 static char rest_extension[] = "...";
 #define REST_EXTENSION_LENGTH  (sizeof (rest_extension) - 1)
 
+/* This is the implicit parameter name when using variable number of
+   parameters for macros using the ISO C 9x extension.  */
+static char va_args_name[] = "__VA_ARGS__";
+#define VA_ARGS_NAME_LENGTH    (sizeof (va_args_name) - 1)
+
 /* The structure of a node in the hash table.  The hash table
    has entries for all tokens defined by #define directives (type T_MACRO),
    plus some special tokens like __LINE__ (these each have their own
@@ -737,6 +640,7 @@ enum node_type {
  T_DISABLED,   /* macro temporarily turned off for rescan */
  T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */
  T_PCSTRING,   /* precompiled string (hashval is KEYDEF *) */
+ T_POISON,     /* defined with `#pragma poison' */
  T_UNUSED      /* Used for something not defined.  */
  };
 
@@ -766,13 +670,6 @@ static HASHNODE *hashtab[HASHSIZE];
 #define HASHSTEP(old, c) ((old << 2) + c)
 #define MAKE_POS(v) (v & 0x7fffffff) /* make number positive */
 
-/* Symbols to predefine.  */
-
-#ifdef CPP_PREDEFINES
-static char *predefs = CPP_PREDEFINES;
-#else
-static char *predefs = "";
-#endif
 \f
 /* We let tm.h override the types used here, to handle trivial differences
    such as the choice of unsigned int or long unsigned int for size_t.
@@ -805,6 +702,8 @@ char * wchar_type = WCHAR_TYPE;
 #ifndef USER_LABEL_PREFIX
 #define USER_LABEL_PREFIX ""
 #endif
+char * user_label_prefix = USER_LABEL_PREFIX;
+#undef USER_LABEL_PREFIX
 
 /* The string value for __REGISTER_PREFIX__ */
 
@@ -868,7 +767,8 @@ struct directive {
   enum node_type type;         /* Code which describes which directive.  */
 };
 
-#define IS_INCLUDE_DIRECTIVE_TYPE(t) (T_INCLUDE <= (t) && (t) <= T_IMPORT)
+#define IS_INCLUDE_DIRECTIVE_TYPE(t) \
+((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT)
 
 /* These functions are declared to return int instead of void since they
    are going to be placed in the table and some old compilers have trouble with
@@ -890,7 +790,6 @@ static int do_sccs DO_PROTO;
 #endif
 static int do_unassert DO_PROTO;
 static int do_undef DO_PROTO;
-static int do_warning DO_PROTO;
 static int do_xifdef DO_PROTO;
 
 /* Here is the actual list of #-directives, most-often-used first.  */
@@ -909,7 +808,7 @@ static struct directive directive_table[] = {
   {  6, do_include, "import", T_IMPORT},
   {  5, do_undef, "undef", T_UNDEF},
   {  5, do_error, "error", T_ERROR},
-  {  7, do_warning, "warning", T_WARNING},
+  {  7, do_error, "warning", T_WARNING},
 #ifdef SCCS_DIRECTIVE
   {  4, do_sccs, "sccs", T_SCCS},
 #endif
@@ -932,8 +831,6 @@ U_CHAR is_idstart[256];
 static U_CHAR is_hor_space[256];
 /* table to tell if c is horizontal or vertical space.  */
 U_CHAR is_space[256];
-/* names of some characters */
-static char *char_name[256];
 
 #define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
 #define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
@@ -943,6 +840,10 @@ static int errors = 0;                     /* Error counter for exit code */
 /* Name of output file, for error messages.  */
 static char *out_fname;
 
+/* Nonzero to ignore \ in string constants.  Use to treat #line 1 "A:\file.h
+   as a non-form feed.  If you want it to be a form feed, you must use
+   # 1 "\f".  */
+static int ignore_escape_flag = 1;
 
 /* Stack of conditionals currently in progress
    (including both successful and failing conditionals).  */
@@ -950,6 +851,7 @@ static char *out_fname;
 struct if_stack {
   struct if_stack *next;       /* for chaining to the next stack frame */
   char *fname;         /* copied from input when frame is made */
+  size_t fname_len;            /* similarly */
   int lineno;                  /* similarly */
   int if_succeeded;            /* true if a leg of this if-group
                                    has been passed through rescan */
@@ -986,6 +888,7 @@ static void path_include PROTO((char *));
 static U_CHAR *index0 PROTO((U_CHAR *, int, size_t));
 
 static void trigraph_pcp PROTO((FILE_BUF *));
+static void check_white_space PROTO((FILE_BUF *));
 
 static void newline_fix PROTO((U_CHAR *));
 static void name_newline_fix PROTO((U_CHAR *));
@@ -1017,14 +920,14 @@ static void record_control_macro PROTO((struct include_file *, U_CHAR *));
 
 static char *check_precompiled PROTO((int, struct stat *, char *, char **));
 static int check_preconditions PROTO((char *));
-static void pcfinclude PROTO((U_CHAR *, U_CHAR *, U_CHAR *, FILE_BUF *));
+static void pcfinclude PROTO((U_CHAR *, U_CHAR *, FILE_BUF *));
 static void pcstring_used PROTO((HASHNODE *));
 static void write_output PROTO((void));
 static void pass_thru_directive PROTO((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
 
 static MACRODEF create_definition PROTO((U_CHAR *, U_CHAR *, FILE_BUF *));
 
-static int check_macro_name PROTO((U_CHAR *, char *));
+static int check_macro_name PROTO((U_CHAR *, int));
 static int compare_defs PROTO((DEFINITION *, DEFINITION *));
 static int comp_def_part PROTO((int, U_CHAR *, int, U_CHAR *, int, int));
 
@@ -1042,14 +945,14 @@ static void delete_assertion PROTO((ASSERTION_HASHNODE *));
 
 static void do_once PROTO((void));
 
-static HOST_WIDE_INT eval_if_expression PROTO((U_CHAR *, int));
+static HOST_WIDEST_INT eval_if_expression PROTO((U_CHAR *, int));
 static void conditional_skip PROTO((FILE_BUF *, int, enum node_type, U_CHAR *, FILE_BUF *));
 static void skip_if_group PROTO((FILE_BUF *, int, FILE_BUF *));
 static void validate_else PROTO((U_CHAR *, U_CHAR *));
 
 static U_CHAR *skip_to_end_of_comment PROTO((FILE_BUF *, int *, int));
 static U_CHAR *skip_quoted_string PROTO((U_CHAR *, U_CHAR *, int, int *, int *, int *));
-static char *quote_string PROTO((char *, char *));
+static char *quote_string PROTO((char *, char *, size_t));
 static U_CHAR *skip_paren_group PROTO((FILE_BUF *));
 
 /* Last arg to output_line_directive.  */
@@ -1059,27 +962,29 @@ static void output_line_directive PROTO((FILE_BUF *, FILE_BUF *, int, enum file_
 static void macroexpand PROTO((HASHNODE *, FILE_BUF *));
 
 struct argdata;
-static char *macarg PROTO((struct argdata *, int));
+static int macarg PROTO((struct argdata *, int));
 
-static U_CHAR *macarg1 PROTO((U_CHAR *, U_CHAR *, int *, int *, int *, int));
+static U_CHAR *macarg1 PROTO((U_CHAR *, U_CHAR *, struct hashnode *, int *, int *, int *, int));
 
 static int discard_comments PROTO((U_CHAR *, int, int));
 
-static int change_newlines PROTO((U_CHAR *, int));
+static void change_newlines PROTO((struct argdata *));
 
-char *my_strerror PROTO((int));
-void error PRINTF_PROTO_1((char *, ...));
-static void verror PROTO((char *, va_list));
+static void notice PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1;
+static void vnotice PROTO((const char *, va_list));
+void error PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1;
+void verror PROTO((const char *, va_list));
 static void error_from_errno PROTO((char *));
-void warning PRINTF_PROTO_1((char *, ...));
-static void vwarning PROTO((char *, va_list));
-static void error_with_line PRINTF_PROTO_2((int, char *, ...));
-static void verror_with_line PROTO((int, char *, va_list));
-static void vwarning_with_line PROTO((int, char *, va_list));
-static void warning_with_line PRINTF_PROTO_2((int, char *, ...));
-void pedwarn PRINTF_PROTO_1((char *, ...));
-void pedwarn_with_line PRINTF_PROTO_2((int, char *, ...));
-static void pedwarn_with_file_and_line PRINTF_PROTO_3((char *, int, char *, ...));
+void warning PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1;
+static void vwarning PROTO((const char *, va_list));
+static void error_with_line PVPROTO((int, const char *, ...)) ATTRIBUTE_PRINTF_2;
+static void verror_with_line PROTO((int, const char *, va_list));
+static void vwarning_with_line PROTO((int, const char *, va_list));
+static void warning_with_line PVPROTO((int, const char *, ...)) ATTRIBUTE_PRINTF_2;
+void pedwarn PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1;
+void pedwarn_with_line PVPROTO((int, const char *, ...)) ATTRIBUTE_PRINTF_2;
+static void pedwarn_with_file_and_line PVPROTO((const char *, size_t, int, const char *, ...)) ATTRIBUTE_PRINTF_4;
+static void pedwarn_strange_white_space PROTO((int));
 
 static void print_containing_files PROTO((void));
 
@@ -1099,28 +1004,25 @@ static void dump_arg_n PROTO((DEFINITION *, int, FILE *));
 static void initialize_char_syntax PROTO((void));
 static void initialize_builtins PROTO((FILE_BUF *, FILE_BUF *));
 
-static void make_definition PROTO((char *, FILE_BUF *));
+static void make_definition PROTO((char *));
 static void make_undef PROTO((char *, FILE_BUF *));
 
-static void make_assertion PROTO((char *, char *));
+static void make_assertion PROTO((const char *, const char *));
 
-static struct file_name_list *new_include_prefix PROTO((struct file_name_list *, char *, char *, char *));
+static struct file_name_list *new_include_prefix PROTO((struct file_name_list *, const char *, const char *, const char *));
 static void append_include_chain PROTO((struct file_name_list *, struct file_name_list *));
 
-static int quote_string_for_make PROTO((char *, char *));
-static void deps_output PROTO((char *, int));
+static int quote_string_for_make PROTO((char *, const char *));
+static void deps_output PROTO((const char *, int));
 
-static void fatal PRINTF_PROTO_1((char *, ...)) __attribute__ ((noreturn));
-void fancy_abort PROTO((void)) __attribute__ ((noreturn));
+void fatal PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
+void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN;
 static void perror_with_name PROTO((char *));
-static void pfatal_with_name PROTO((char *)) __attribute__ ((noreturn));
-static void pipe_closed PROTO((int)) __attribute__ ((noreturn));
-
-static void memory_full PROTO((void)) __attribute__ ((noreturn));
-GENERIC_PTR xmalloc PROTO((size_t));
-static GENERIC_PTR xrealloc PROTO((GENERIC_PTR, size_t));
-static GENERIC_PTR xcalloc PROTO((size_t, size_t));
-static char *savestring PROTO((char *));
+static void pfatal_with_name PROTO((char *)) ATTRIBUTE_NORETURN;
+static void pipe_closed PROTO((int)) ATTRIBUTE_NORETURN;
+
+static void memory_full PROTO((void)) ATTRIBUTE_NORETURN;
+static void print_help PROTO((void));
 \f
 /* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
    retrying if necessary.  If MAX_READ_LEN is defined, read at most
@@ -1191,6 +1093,77 @@ safe_write (desc, ptr, len)
     len -= written;
   }
 }
+
+\f
+static void
+print_help ()
+{
+  printf ("Usage: %s [switches] input output\n", progname);
+  printf ("Switches:\n");
+  printf ("  -include <file>           Include the contents of <file> before other files\n");
+  printf ("  -imacros <file>           Accept definition of macros in <file>\n");
+  printf ("  -iprefix <path>           Specify <path> as a prefix for next two options\n");
+  printf ("  -iwithprefix <dir>        Add <dir> to the end of the system include paths\n");
+  printf ("  -iwithprefixbefore <dir>  Add <dir> to the end of the main include paths\n");
+  printf ("  -isystem <dir>            Add <dir> to the start of the system include paths\n");
+  printf ("  -idirafter <dir>          Add <dir> to the end of the system include paths\n");
+  printf ("  -I <dir>                  Add <dir> to the end of the main include paths\n");
+  printf ("  -nostdinc                 Do not search the system include directories\n");
+  printf ("  -nostdinc++               Do not search the system include directories for C++\n");
+  printf ("  -o <file>                 Put output into <file>\n");
+  printf ("  -pedantic                 Issue all warnings demanded by strict ANSI C\n");
+  printf ("  -traditional              Follow K&R pre-processor behaviour\n");
+  printf ("  -trigraphs                Support ANSI C trigraphs\n");
+  printf ("  -lang-c                   Assume that the input sources are in C\n");
+  printf ("  -lang-c89                 Assume that the input is C89; depricated\n");
+  printf ("  -lang-c++                 Assume that the input sources are in C++\n");
+  printf ("  -lang-objc                Assume that the input sources are in ObjectiveC\n");
+  printf ("  -lang-objc++              Assume that the input sources are in ObjectiveC++\n");
+  printf ("  -lang-asm                 Assume that the input sources are in assembler\n");
+  printf ("  -lang-chill               Assume that the input sources are in Chill\n");
+  printf ("  -std=<std name>           Specify the conformance standard; one of:\n");
+  printf ("                            gnu89, gnu9x, c89, c9x, iso9899:1990,\n");
+  printf ("                            iso9899:199409, iso9899:199x\n");
+  printf ("  -+                        Allow parsing of C++ style features\n");
+  printf ("  -w                        Inhibit warning messages\n");
+  printf ("  -Wtrigraphs               Warn if trigraphs are encountered\n");
+  printf ("  -Wno-trigraphs            Do not warn about trigraphs\n");
+  printf ("  -Wcomment{s}              Warn if one comment starts inside another\n");
+  printf ("  -Wno-comment{s}           Do not warn about comments\n");
+  printf ("  -Wtraditional             Warn if a macro argument is/would be turned into\n");
+  printf ("                             a string if -traditional is specified\n");
+  printf ("  -Wno-traditional          Do not warn about stringification\n");
+  printf ("  -Wundef                   Warn if an undefined macro is used by #if\n");
+  printf ("  -Wno-undef                Do not warn about testing undefined macros\n");
+  printf ("  -Wimport                  Warn about the use of the #import directive\n");
+  printf ("  -Wno-import               Do not warn about the use of #import\n");
+  printf ("  -Werror                   Treat all warnings as errors\n");
+  printf ("  -Wno-error                Do not treat warnings as errors\n");
+  printf ("  -Wall                     Enable all preprocessor warnings\n");
+  printf ("  -M                        Generate make dependencies\n");
+  printf ("  -MM                       As -M, but ignore system header files\n");
+  printf ("  -MD                       As -M, but put output in a .d file\n");
+  printf ("  -MMD                      As -MD, but ignore system header files\n");
+  printf ("  -MG                       Treat missing header file as generated files\n");
+  printf ("  -g                        Include #define and #undef directives in the output\n");
+  printf ("  -D<macro>                 Define a <macro> with string '1' as its value\n");
+  printf ("  -D<macro>=<val>           Define a <macro> with <val> as its value\n");
+  printf ("  -A<question> (<answer>)   Assert the <answer> to <question>\n");
+  printf ("  -U<macro>                 Undefine <macro> \n");
+  printf ("  -u or -undef              Do not predefine any macros\n");
+  printf ("  -v                        Display the version number\n");
+  printf ("  -H                        Print the name of header files as they are used\n");
+  printf ("  -C                        Do not discard comments\n");
+  printf ("  -dM                       Display a list of macro definitions active at end\n");
+  printf ("  -dD                       Preserve macro definitions in output\n");
+  printf ("  -dN                       As -dD except that only the names are preserved\n");
+  printf ("  -dI                       Include #include directives in the output\n");
+  printf ("  -ifoutput                 Describe skipped code blocks in output \n");
+  printf ("  -P                        Do not generate #line directives\n");
+  printf ("  -$                        Do not include '$' in identifiers\n");
+  printf ("  -remap                    Remap file names when including files.\n");
+  printf ("  -h or --help              Display this information\n");
+}
 \f
 int
 main (argc, argv)
@@ -1202,17 +1175,17 @@ main (argc, argv)
   char *cp;
   int f, i;
   FILE_BUF *fp;
-  char **pend_files = (char **) xmalloc (argc * sizeof (char *));
-  char **pend_defs = (char **) xmalloc (argc * sizeof (char *));
-  char **pend_undefs = (char **) xmalloc (argc * sizeof (char *));
-  char **pend_assertions = (char **) xmalloc (argc * sizeof (char *));
-  char **pend_includes = (char **) xmalloc (argc * sizeof (char *));
+
+  char **pend_files;
+  char **pend_defs;
+  char **pend_undefs;
+  char **pend_assertions;
+  char **pend_includes;
 
   /* Record the option used with each element of pend_assertions.
      This is preparation for supporting more than one option for making
      an assertion.  */
-  char **pend_assertion_options = (char **) xmalloc (argc * sizeof (char *));
-  int inhibit_predefs = 0;
+  char **pend_assertion_options;
   int no_standard_includes = 0;
   int no_standard_cplusplus_includes = 0;
   int missing_newline = 0;
@@ -1249,13 +1222,19 @@ main (argc, argv)
   signal (SIGPIPE, pipe_closed);
 #endif
 
+#ifdef HAVE_LC_MESSAGES
+  setlocale (LC_MESSAGES, "");
+#endif
+  (void) bindtextdomain (PACKAGE, localedir);
+  (void) textdomain (PACKAGE);
+
   progname = base_name (argv[0]);
 
 #ifdef VMS
   {
     /* Remove extension from PROGNAME.  */
     char *p;
-    char *s = progname = savestring (progname);
+    char *s = progname = xstrdup (progname);
 
     if ((p = rindex (s, ';')) != 0) *p = '\0'; /* strip version number */
     if ((p = rindex (s, '.')) != 0             /* strip type iff ".exe" */
@@ -1267,6 +1246,16 @@ main (argc, argv)
   }
 #endif
 
+  /* Do not invoke xmalloc before this point, since locale and
+     progname need to be set first, in case a diagnostic is issued.  */
+     
+  pend_files = (char **) xmalloc (argc * sizeof (char *));
+  pend_defs = (char **) xmalloc (argc * sizeof (char *));
+  pend_undefs = (char **) xmalloc (argc * sizeof (char *));
+  pend_assertions = (char **) xmalloc (argc * sizeof (char *));
+  pend_includes = (char **) xmalloc (argc * sizeof (char *));
+  pend_assertion_options = (char **) xmalloc (argc * sizeof (char *));
+
   in_fname = NULL;
   out_fname = NULL;
 
@@ -1286,12 +1275,21 @@ main (argc, argv)
   bzero ((char *) pend_assertions, argc * sizeof (char *));
   bzero ((char *) pend_includes, argc * sizeof (char *));
 
+#ifdef MULTIBYTE_CHARS
+  /* Change to the native locale for multibyte conversions.  */
+  setlocale (LC_CTYPE, "");
+  literal_codeset = getenv ("LANG");
+#endif
+
   /* Process switches and find input file name.  */
 
   for (i = 1; i < argc; i++) {
     if (argv[i][0] != '-') {
       if (out_fname != NULL)
-       fatal ("Usage: %s [switches] input output", argv[0]);
+       {
+         print_help ();
+         fatal ("Too many arguments");
+       }
       else if (in_fname != NULL)
        out_fname = argv[i];
       else
@@ -1301,20 +1299,20 @@ main (argc, argv)
 
       case 'i':
        if (!strcmp (argv[i], "-include")) {
-         int temp = i;
-
          if (i + 1 == argc)
            fatal ("Filename missing after `-include' option");
-         else
-           simplify_filename (pend_includes[temp] = argv[++i]);
+         else {
+           i++;
+           simplify_filename (pend_includes[i] = argv[i]);
+         }
        }
        if (!strcmp (argv[i], "-imacros")) {
-         int temp = i;
-
          if (i + 1 == argc)
            fatal ("Filename missing after `-imacros' option");
-         else
-           simplify_filename (pend_files[temp] = argv[++i]);
+         else {
+           i++;
+           simplify_filename (pend_files[i] = argv[i]);
+         }
        }
        if (!strcmp (argv[i], "-iprefix")) {
          if (i + 1 == argc)
@@ -1348,7 +1346,7 @@ main (argc, argv)
          if (include_prefix != 0)
            prefix = include_prefix;
          else {
-           prefix = savestring (GCC_INCLUDE_DIR);
+           prefix = xstrdup (GCC_INCLUDE_DIR);
            /* Remove the `include' from /usr/local/lib/gcc.../include.  */
            if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
              prefix[strlen (prefix) - 7] = 0;
@@ -1373,7 +1371,7 @@ main (argc, argv)
          if (include_prefix != 0)
            prefix = include_prefix;
          else {
-           prefix = savestring (GCC_INCLUDE_DIR);
+           prefix = xstrdup (GCC_INCLUDE_DIR);
            /* Remove the `include' from /usr/local/lib/gcc.../include.  */
            if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
              prefix[strlen (prefix) - 7] = 0;
@@ -1440,18 +1438,18 @@ main (argc, argv)
 
       case 'l':
        if (! strcmp (argv[i], "-lang-c"))
-         cplusplus = 0, cplusplus_comments = 1, c89 = 0, objc = 0;
-       if (! strcmp (argv[i], "-lang-c89"))
-         cplusplus = 0, cplusplus_comments = 0, c89 = 1, objc = 0;
-       if (! strcmp (argv[i], "-lang-c++"))
-         cplusplus = 1, cplusplus_comments = 1, c89 = 0, objc = 0;
-       if (! strcmp (argv[i], "-lang-objc"))
-         cplusplus = 0, cplusplus_comments = 1, c89 = 0, objc = 1;
-       if (! strcmp (argv[i], "-lang-objc++"))
-         cplusplus = 1, cplusplus_comments = 1, c89 = 0, objc = 1;
-       if (! strcmp (argv[i], "-lang-asm"))
+         cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 1, objc = 0;
+       else if (! strcmp (argv[i], "-lang-c89"))
+         cplusplus = 0, cplusplus_comments = 0, c89 = 1, c9x = 0, objc = 0;
+       else if (! strcmp (argv[i], "-lang-c++"))
+         cplusplus = 1, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 0;
+       else if (! strcmp (argv[i], "-lang-objc"))
+         cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 1;
+       else if (! strcmp (argv[i], "-lang-objc++"))
+         cplusplus = 1, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 1;
+       else if (! strcmp (argv[i], "-lang-asm"))
          lang_asm = 1;
-       if (! strcmp (argv[i], "-lint"))
+       else if (! strcmp (argv[i], "-lint"))
          for_lint = 1;
        break;
 
@@ -1459,6 +1457,18 @@ main (argc, argv)
        cplusplus = 1, cplusplus_comments = 1;
        break;
 
+      case 's':
+       if (!strcmp (argv[i], "-std=iso9899:1990")
+           || !strcmp (argv[i], "-std=iso9899:199409")
+           || !strcmp (argv[i], "-std=c89")
+           || !strcmp (argv[i], "-std=gnu89"))
+         cplusplus = 0, cplusplus_comments = 0, c89 = 1, c9x = 0, objc = 0;
+        else if (!strcmp (argv[i], "-std=iso9899:199x")
+                || !strcmp (argv[i], "-std=c9x")
+                || !strcmp (argv[i], "-std=gnu9x"))
+         cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 1, objc = 0;
+       break;
+
       case 'w':
        inhibit_warnings = 1;
        break;
@@ -1480,6 +1490,10 @@ main (argc, argv)
          warn_stringify = 1;
        else if (!strcmp (argv[i], "-Wno-traditional"))
          warn_stringify = 0;
+       else if (!strcmp (argv[i], "-Wwhite-space"))
+         warn_white_space = 1;
+       else if (!strcmp (argv[i], "-Wno-white-space"))
+         warn_white_space = 0;
        else if (!strcmp (argv[i], "-Wundef"))
          warn_undef = 1;
        else if (!strcmp (argv[i], "-Wno-undef"))
@@ -1496,9 +1510,17 @@ main (argc, argv)
          {
            warn_trigraphs = 1;
            warn_comments = 1;
+           warn_white_space = 1;
          }
        break;
 
+      case 'f':
+       if (!strcmp (argv[i], "-fleading-underscore"))
+         user_label_prefix = "_";
+       else if (!strcmp (argv[i], "-fno-leading-underscore"))
+         user_label_prefix = "";
+       break;
+
       case 'M':
        /* The style of the choices here is a bit mixed.
           The chosen scheme is a hybrid of keeping all options in one string
@@ -1571,8 +1593,15 @@ main (argc, argv)
          debug_output = 1;
        break;
 
+      case '-':
+       if (strcmp (argv[i], "--help") != 0)
+         return i;
+       print_help ();
+       exit (0);
+       break;
+
       case 'v':
-       fprintf (stderr, "GNU CPP version %s", version_string);
+       notice ("GNU CPP version %s", version_string);
 #ifdef TARGET_VERSION
        TARGET_VERSION;
 #endif
@@ -1610,7 +1639,6 @@ main (argc, argv)
               on the command line.  That way we can get rid of any
               that were passed automatically in from GCC.  */
            int j;
-           inhibit_predefs = 1;
            for (j = 0; j < i; j++)
              pend_defs[j] = pend_assertions[j] = 0;
          } else {
@@ -1647,15 +1675,15 @@ main (argc, argv)
       case 'I':                        /* Add directory to path for includes.  */
        {
          struct file_name_list *dirtmp;
+         char *dir = argv[i][2] ? argv[i] + 2 : argv[++i];
 
-         if (! ignore_srcdir && !strcmp (argv[i] + 2, "-")) {
+         if (! ignore_srcdir && !strcmp (dir, "-")) {
            ignore_srcdir = 1;
            /* Don't use any preceding -I directories for #include <...>.  */
            first_bracket_include = 0;
          }
          else {
-           dirtmp = new_include_prefix (last_include, NULL_PTR, "",
-                                        argv[i][2] ? argv[i] + 2 : argv[++i]);
+           dirtmp = new_include_prefix (last_include, NULL_PTR, "", dir);
            append_include_chain (dirtmp, dirtmp);
          }
        }
@@ -1678,12 +1706,6 @@ main (argc, argv)
          remap = 1;
        break;
 
-      case 'u':
-       /* Sun compiler passes undocumented switch "-undef".
-          Let's assume it means to inhibit the predefined symbols.  */
-       inhibit_predefs = 1;
-       break;
-
       case '\0': /* JF handle '-' as file name meaning stdin or stdout */
        if (in_fname == NULL) {
          in_fname = "";
@@ -1705,7 +1727,7 @@ main (argc, argv)
   /* Some people say that CPATH should replace the standard include dirs,
      but that seems pointless: it comes before them, so it overrides them
      anyway.  */
-  cp = getenv ("CPATH");
+  GET_ENV_PATH_LIST (cp, "CPATH");
   if (cp && ! no_standard_includes)
     path_include (cp);
 
@@ -1722,6 +1744,7 @@ main (argc, argv)
   if (in_fname == NULL)
     in_fname = "";
   fp->nominal_fname = fp->fname = in_fname;
+  fp->nominal_fname_len = strlen (in_fname);
   fp->lineno = 0;
 
   /* In C++, wchar_t is a distinct basic type, and we can expect
@@ -1733,135 +1756,6 @@ main (argc, argv)
      and option processing.  */
   initialize_builtins (fp, &outbuf);
 
-  /* Do standard #defines and assertions
-     that identify system and machine type.  */
-
-  if (!inhibit_predefs) {
-    char *p = (char *) alloca (strlen (predefs) + 1);
-
-#ifdef VMS
-    struct dsc$descriptor_s lcl_name;
-    struct item_list {
-      unsigned short length;  /* input length */
-      unsigned short code;    /* item code */   
-      unsigned long dptr;     /* data ptr */
-      unsigned long lptr;     /* output length ptr */
-    };
-
-    unsigned long syi_length;
-    char syi_data[16];
-
-    struct item_list items[] = {
-      { 16, SYI$_VERSION, 0, 0 },
-      { 0, 0, 0, 0 }
-    };
-
-    items[0].dptr = (unsigned long)syi_data;
-    items[0].lptr = (unsigned long)(&syi_length);
-
-    if (SYS$GETSYIW (0, 0, 0, items, NULL, NULL, NULL, NULL) == SS$_NORMAL)
-      {
-       unsigned long vms_version_value;
-       char *vers;
-
-       vers = syi_data;
-       vms_version_value = 0;
-
-       if (*vers == 'V')
-         vers++;
-       if (isdigit (*vers))
-         {
-           vms_version_value = (*vers - '0') * 10000000;
-         }
-       vers++;
-       if (*vers == '.')
-         {
-           vers++;
-           if (isdigit (*vers))
-             {
-               vms_version_value += (*vers - '0') * 100000;
-             }
-         }
-
-       if (vms_version_value > 0)
-         {
-           char versbuf[32];
-
-           sprintf (versbuf, "__VMS_VER=%08ld", vms_version_value);
-           if (debug_output)
-             output_line_directive (fp, &outbuf, 0, same_file);
-           make_definition (versbuf, &outbuf);
-         }
-      }
-#endif
-
-    strcpy (p, predefs);
-    while (*p) {
-      char *q;
-      while (*p == ' ' || *p == '\t')
-       p++;
-      /* Handle -D options.  */ 
-      if (p[0] == '-' && p[1] == 'D') {
-       q = &p[2];
-       while (*p && *p != ' ' && *p != '\t')
-         p++;
-       if (*p != 0)
-         *p++= 0;
-       if (debug_output)
-         output_line_directive (fp, &outbuf, 0, same_file);
-       make_definition (q, &outbuf);
-       while (*p == ' ' || *p == '\t')
-         p++;
-      } else if (p[0] == '-' && p[1] == 'A') {
-       /* Handle -A options (assertions).  */ 
-       char *assertion;
-       char *past_name;
-       char *value;
-       char *past_value;
-       char *termination;
-       int save_char;
-
-       assertion = &p[2];
-       past_name = assertion;
-       /* Locate end of name.  */
-       while (*past_name && *past_name != ' '
-              && *past_name != '\t' && *past_name != '(')
-         past_name++;
-       /* Locate `(' at start of value.  */
-       value = past_name;
-       while (*value && (*value == ' ' || *value == '\t'))
-         value++;
-       if (*value++ != '(')
-         abort ();
-       while (*value && (*value == ' ' || *value == '\t'))
-         value++;
-       past_value = value;
-       /* Locate end of value.  */
-       while (*past_value && *past_value != ' '
-              && *past_value != '\t' && *past_value != ')')
-         past_value++;
-       termination = past_value;
-       while (*termination && (*termination == ' ' || *termination == '\t'))
-         termination++;
-       if (*termination++ != ')')
-         abort ();
-       if (*termination && *termination != ' ' && *termination != '\t')
-         abort ();
-       /* Temporarily null-terminate the value.  */
-       save_char = *termination;
-       *termination = '\0';
-       /* Install the assertion.  */
-       make_assertion ("-A", assertion);
-       *termination = (char) save_char;
-       p = termination;
-       while (*p == ' ' || *p == '\t')
-         p++;
-      } else {
-       abort ();
-      }
-    }
-  }
-
   /* Now handle the command line options.  */
 
   /* Do -U's, -D's and -A's in the order they were seen.  */
@@ -1874,7 +1768,7 @@ main (argc, argv)
     if (pend_defs[i]) {
       if (debug_output)
         output_line_directive (fp, &outbuf, 0, same_file);
-      make_definition (pend_defs[i], &outbuf);
+      make_definition (pend_defs[i]);
     }
     if (pend_assertions[i])
       make_assertion (pend_assertion_options[i], pend_assertions[i]);
@@ -1888,16 +1782,16 @@ main (argc, argv)
     switch ((objc << 1) + cplusplus)
       {
       case 0:
-       epath = getenv ("C_INCLUDE_PATH");
+       GET_ENV_PATH_LIST (epath, "C_INCLUDE_PATH");
        break;
       case 1:
-       epath = getenv ("CPLUS_INCLUDE_PATH");
+       GET_ENV_PATH_LIST (epath, "CPLUS_INCLUDE_PATH");
        break;
       case 2:
-       epath = getenv ("OBJC_INCLUDE_PATH");
+       GET_ENV_PATH_LIST (epath, "OBJC_INCLUDE_PATH");
        break;
       case 3:
-       epath = getenv ("OBJCPLUS_INCLUDE_PATH");
+       GET_ENV_PATH_LIST (epath, "OBJCPLUS_INCLUDE_PATH");
        break;
       }
     /* If the environment var for this language is set,
@@ -1920,7 +1814,7 @@ main (argc, argv)
        if (c == PATH_SEPARATOR || !c) {
          endp[-1] = 0;
          include_defaults[num_dirs].fname
-           = startp == endp ? "." : savestring (startp);
+           = startp == endp ? "." : xstrdup (startp);
          endp[-1] = c;
          include_defaults[num_dirs].component = 0;
          include_defaults[num_dirs].cplusplus = cplusplus;
@@ -1946,7 +1840,7 @@ main (argc, argv)
   if (!no_standard_includes) {
     struct default_include *p = include_defaults;
     char *specd_prefix = include_prefix;
-    char *default_prefix = savestring (GCC_INCLUDE_DIR);
+    char *default_prefix = xstrdup (GCC_INCLUDE_DIR);
     int default_len = 0;
     /* Remove the `include' from /usr/local/lib/gcc.../include.  */
     if (!strcmp (default_prefix + strlen (default_prefix) - 8, "/include")) {
@@ -1970,6 +1864,7 @@ main (argc, argv)
              append_include_chain (new, new);
              if (first_system_include == 0)
                first_system_include = new;
+             p->included = 1;
            }
          }
        }
@@ -1985,6 +1880,7 @@ main (argc, argv)
          append_include_chain (new, new);
          if (first_system_include == 0)
            first_system_include = new;
+         p->included = 1;
        }
       }
     }
@@ -1998,10 +1894,10 @@ main (argc, argv)
   /* With -v, print the list of dirs to search.  */
   if (verbose) {
     struct file_name_list *p;
-    fprintf (stderr, "#include \"...\" search starts here:\n");
+    notice ("#include \"...\" search starts here:\n");
     for (p = include; p; p = p->next) {
       if (p == first_bracket_include)
-       fprintf (stderr, "#include <...> search starts here:\n");
+       notice ("#include <...> search starts here:\n");
       if (!p->fname[0])
        fprintf (stderr, " .\n");
       else if (!strcmp (p->fname, "/") || !strcmp (p->fname, "//"))
@@ -2010,7 +1906,15 @@ main (argc, argv)
        /* Omit trailing '/'.  */
        fprintf (stderr, " %.*s\n", (int) strlen (p->fname) - 1, p->fname);
     }
-    fprintf (stderr, "End of search list.\n");
+    notice ("End of search list.\n");
+    {
+      struct default_include * d;
+      notice ("The following default directories have been omitted from the search path:\n");
+      for (d = include_defaults; d->fname; d++)
+       if (! d->included)
+         fprintf (stderr, " %s\n", d->fname);
+      notice ("End of omitted list.\n");
+    }
   }
 
   /* -MG doesn't select the form of output and must be specified with one of
@@ -2038,17 +1942,14 @@ main (argc, argv)
     else
       print_deps = 1;
 
-    s = spec;
     /* Find the space before the DEPS_TARGET, if there is one.  */
-    /* This should use index.  (mrs) */
-    while (*s != 0 && *s != ' ') s++;
-    if (*s != 0) {
+    s = index (spec, ' ');
+    if (s) {
       deps_target = s + 1;
       output_file = xmalloc (s - spec + 1);
       bcopy (spec, output_file, s - spec);
       output_file[s - spec] = 0;
-    }
-    else {
+    } else {
       deps_target = 0;
       output_file = spec;
     }
@@ -2109,8 +2010,9 @@ main (argc, argv)
       strcpy (q, OBJECT_SUFFIX);
 
       deps_output (p, ':');
-      deps_output (in_fname, ' ');
     }
+
+    deps_output (in_fname, ' ');
   }
 
   /* Scan the -imacros files before the main input.
@@ -2143,6 +2045,7 @@ main (argc, argv)
   if (fstat (f, &st) != 0)
     pfatal_with_name (in_fname);
   fp->nominal_fname = fp->fname = in_fname;
+  fp->nominal_fname_len = strlen (in_fname);
   fp->lineno = 1;
   fp->system_header_p = 0;
   /* JF all this is mine about reading pipes and ttys */
@@ -2197,6 +2100,9 @@ main (argc, argv)
   if (!no_trigraphs)
     trigraph_pcp (fp);
 
+  if (warn_white_space)
+    check_white_space (fp);
+
   /* Now that we know the input file is valid, open the output.  */
 
   if (!out_fname || !strcmp (out_fname, ""))
@@ -2407,13 +2313,43 @@ trigraph_pcp (buf)
     warning_with_line (0, "%lu trigraph(s) encountered",
                       (unsigned long) (fptr - bptr) / 2);
 }
+
+/* Warn about white space between backslash and end of line.  */
+
+static void
+check_white_space (buf)
+     FILE_BUF *buf;
+{
+  register U_CHAR *sptr = buf->buf;
+  register U_CHAR *lptr = sptr + buf->length;
+  register U_CHAR *nptr;
+  int line = 0;
+
+  nptr = sptr = buf->buf;
+  lptr = sptr + buf->length;
+  for (nptr = sptr;
+       (nptr = index0 (nptr, '\n', (size_t) (lptr - nptr))) != NULL;
+       nptr ++) {
+    register U_CHAR *p = nptr;
+    line++;
+    for (p = nptr; sptr < p; p--) {
+      if (! is_hor_space[p[-1]]) {
+       if (p[-1] == '\\' && p != nptr)
+         warning_with_line (line, 
+                            "`\\' followed by white space at end of line");
+       break;
+      }
+    }
+  }
+}
 \f
 /* Move all backslash-newline pairs out of embarrassing places.
    Exchange all such pairs following BP
    with any potentially-embarrassing characters that follow them.
    Potentially-embarrassing characters are / and *
    (because a backslash-newline inside a comment delimiter
-   would cause it not to be recognized).  */
+   would cause it not to be recognized).
+   We assume that *BP == '\\'.  */
 
 static void
 newline_fix (bp)
@@ -2422,21 +2358,24 @@ newline_fix (bp)
   register U_CHAR *p = bp;
 
   /* First count the backslash-newline pairs here.  */
-
-  while (p[0] == '\\' && p[1] == '\n')
+  do {
+    if (p[1] != '\n')
+      break;
     p += 2;
+  } while (*p == '\\');
 
   /* What follows the backslash-newlines is not embarrassing.  */
 
   if (*p != '/' && *p != '*')
+    /* What follows the backslash-newlines is not embarrassing.  */
     return;
 
   /* Copy all potentially embarrassing characters
      that follow the backslash-newline pairs
      down to where the pairs originally started.  */
-
-  while (*p == '*' || *p == '/')
+  do
     *bp++ = *p++;
+  while (*p == '*' || *p == '/');
 
   /* Now write the same number of pairs after the embarrassing chars.  */
   while (bp < p) {
@@ -2455,20 +2394,24 @@ name_newline_fix (bp)
   register U_CHAR *p = bp;
 
   /* First count the backslash-newline pairs here.  */
-  while (p[0] == '\\' && p[1] == '\n')
+  do {
+    if (p[1] != '\n')
+      break;
     p += 2;
+  } while (*p == '\\');
 
   /* What follows the backslash-newlines is not embarrassing.  */
 
   if (!is_idchar[*p])
+    /* What follows the backslash-newlines is not embarrassing.  */
     return;
 
   /* Copy all potentially embarrassing characters
      that follow the backslash-newline pairs
      down to where the pairs originally started.  */
-
-  while (is_idchar[*p])
+  do
     *bp++ = *p++;
+  while (is_idchar[*p]);
 
   /* Now write the same number of pairs after the embarrassing chars.  */
   while (bp < p) {
@@ -2494,7 +2437,7 @@ get_lintcmd (ibp, limit, argstart, arglen, cmdlen)
      U_CHAR **argstart;                /* point to command arg */
      int *arglen, *cmdlen;     /* how long they are */
 {
-  HOST_WIDE_INT linsize;
+  HOST_WIDEST_INT linsize;
   register U_CHAR *numptr;     /* temp for arg parsing */
 
   *arglen = 0;
@@ -2521,10 +2464,10 @@ get_lintcmd (ibp, limit, argstart, arglen, cmdlen)
   if ((linsize >= 7) && !bcmp (ibp, "VARARGS", 7)) {
     *cmdlen = 7;
     ibp += 7; linsize -= 7;
-    if ((linsize == 0) || ! isdigit (*ibp)) return "VARARGS";
+    if ((linsize == 0) || ! ISDIGIT (*ibp)) return "VARARGS";
 
     /* OK, read a number */
-    for (numptr = *argstart = ibp; (numptr < limit) && isdigit (*numptr);
+    for (numptr = *argstart = ibp; (numptr < limit) && ISDIGIT (*numptr);
         numptr++);
     *arglen = numptr - *argstart;
     return "VARARGS";
@@ -2546,7 +2489,7 @@ get_lintcmd (ibp, limit, argstart, arglen, cmdlen)
  * If OUTPUT_MARKS is nonzero, keep Newline markers found in the input
  * and insert them when appropriate.  This is set while scanning macro
  * arguments before substitution.  It is zero when scanning for final output.
- *   There are three types of Newline markers:
+ *   There are two types of Newline markers:
  *   * Newline -  follows a macro name that was not expanded
  *     because it appeared inside an expansion of the same macro.
  *     This marker prevents future expansion of that identifier.
@@ -2740,9 +2683,27 @@ do { ip = &instack[indepth];             \
              bp += 2;
            else if (*bp == '/' && bp[1] == '*') {
              bp += 2;
-             while (!(*bp == '*' && bp[1] == '/'))
-               bp++;
-             bp += 2;
+             while (1)
+               {
+                 if (*bp == '*')
+                   {
+                     if (bp[1] == '/')
+                       {
+                         bp += 2;
+                         break;
+                       }
+                   }
+                 else
+                   {
+#ifdef MULTIBYTE_CHARS
+                     int length;
+                     length = local_mblen (bp, limit - bp);
+                     if (length > 1)
+                       bp += (length - 1);
+#endif
+                   }
+                 bp++;
+               }
            }
            /* There is no point in trying to deal with C++ // comments here,
               because if there is one, then this # must be part of the
@@ -2818,9 +2779,11 @@ do { ip = &instack[indepth];             \
 
       /* Handle any pending identifier;
         but the L in L'...' or L"..." is not an identifier.  */
-      if (ident_length
-         && ! (ident_length == 1 && hash == HASHSTEP (0, 'L')))
-       goto specialchar;
+      if (ident_length) {
+       if (! (ident_length == 1 && hash == HASHSTEP (0, 'L')))
+         goto specialchar;
+       ident_length = hash = 0;
+      }
 
       start_line = ip->lineno;
 
@@ -2839,15 +2802,19 @@ do { ip = &instack[indepth];            \
          if (!traditional) {
            error_with_line (line_for_error (start_line),
                             "unterminated string or character constant");
-           error_with_line (multiline_string_line,
-                            "possible real start of unterminated constant");
-           multiline_string_line = 0;
+           if (multiline_string_line) {
+             error_with_line (multiline_string_line,
+                              "possible real start of unterminated constant");
+             multiline_string_line = 0;
+           }
          }
          break;
        }
        *obp++ = *ibp;
        switch (*ibp++) {
        case '\n':
+         if (warn_white_space && ip->fname && is_hor_space[ibp[-2]])
+           warning ("white space at end of line in string");
          ++ip->lineno;
          ++op->lineno;
          /* Traditionally, end of line ends a string constant with no error.
@@ -2870,20 +2837,28 @@ do { ip = &instack[indepth];            \
          break;
 
        case '\\':
-         if (ibp >= limit)
-           break;
          if (*ibp == '\n') {
-           /* Backslash newline is replaced by nothing at all,
-              but keep the line counts correct.  */
-           --obp;
+           /* Backslash newline is replaced by nothing at all, but
+              keep the line counts correct.  But if we are reading
+              from a macro, keep the backslash newline, since backslash
+              newlines have already been processed.  */
+           if (ip->macro) {
+             *obp++ = '\n';
+             ++op->lineno;
+           } else
+             --obp;
            ++ibp;
            ++ip->lineno;
          } else {
            /* ANSI stupidly requires that in \\ the second \
               is *not* prevented from combining with a newline.  */
-           while (*ibp == '\\' && ibp[1] == '\n') {
-             ibp += 2;
-             ++ip->lineno;
+           if (!ip->macro) {
+             while (*ibp == '\\' && ibp[1] == '\n') {
+               *obp++ = *ibp++;
+               *obp++ = *ibp++;
+               ++ip->lineno;
+               ++op->lineno;
+             }
            }
            *obp++ = *ibp++;
          }
@@ -2894,20 +2869,37 @@ do { ip = &instack[indepth];            \
          if (ibp[-1] == c)
            goto while2end;
          break;
+#ifdef MULTIBYTE_CHARS
+       default:
+         {
+           int length;
+           --ibp;
+           length = local_mblen (ibp, limit - ibp);
+           if (length > 0)
+             {
+               --obp;
+               bcopy (ibp, obp, length);
+               obp += length;
+               ibp += length;
+             }
+           else
+             ++ibp;
+         }
+         break;
+#endif
        }
       }
     while2end:
       break;
 
     case '/':
-      if (*ibp == '\\' && ibp[1] == '\n')
+      if (ip->macro != 0)
+       goto randomchar;
+      if (*ibp == '\\')
        newline_fix (ibp);
-
       if (*ibp != '*'
          && !(cplusplus_comments && *ibp == '/'))
        goto randomchar;
-      if (ip->macro != 0)
-       goto randomchar;
       if (ident_length)
        goto specialchar;
 
@@ -2923,24 +2915,39 @@ do { ip = &instack[indepth];            \
          U_CHAR *before_bp = ibp;
 
          while (++ibp < limit) {
-           if (*ibp == '\n') {
-             if (ibp[-1] != '\\') {
+           if (*ibp == '\n')
+             {
                if (put_out_comments) {
                  bcopy ((char *) before_bp, (char *) obp, ibp - before_bp);
                  obp += ibp - before_bp;
                }
                break;
              }
-             if (warn_comments)
-               warning ("multiline `//' comment");
-             ++ip->lineno;
-             /* Copy the newline into the output buffer, in order to
-                avoid the pain of a #line every time a multiline comment
-                is seen.  */
-             if (!put_out_comments)
-               *obp++ = '\n';
-             ++op->lineno;
-           }
+           if (*ibp == '\\')
+             {
+               if (ibp + 1 < limit && ibp[1] == '\n')
+                 {
+                   if (warn_comments)
+                     warning ("multiline `//' comment");
+                   ++ip->lineno;
+                   /* Copy the newline into the output buffer, in order to
+                      avoid the pain of a #line every time a multiline comment
+                      is seen.  */
+                   if (!put_out_comments)
+                     *obp++ = '\n';
+                   ++op->lineno;
+                   ++ibp;
+                 }
+             }
+           else
+             {
+#ifdef MULTIBYTE_CHARS
+               int length;
+               length = local_mblen (ibp, limit - ibp);
+               if (length > 1)
+                 ibp += (length - 1);
+#endif
+             }
          }
          break;
        }
@@ -3006,7 +3013,7 @@ do { ip = &instack[indepth];              \
          case '*':
            if (ibp[-2] == '/' && warn_comments)
              warning ("`/*' within comment");
-           if (*ibp == '\\' && ibp[1] == '\n')
+           if (*ibp == '\\')
              newline_fix (ibp);
            if (*ibp == '/')
              goto comment_end;
@@ -3029,6 +3036,16 @@ do { ip = &instack[indepth];             \
              goto limit_reached;
            }
            break;
+#ifdef MULTIBYTE_CHARS
+         default:
+           {
+             int length;
+             length = local_mblen (ibp, limit - ibp);
+             if (length > 1)
+               ibp += (length - 1);
+           }
+           break;
+#endif
          }
        }
       comment_end:
@@ -3058,9 +3075,11 @@ do { ip = &instack[indepth];             \
 
       if (ident_length == 0) {
        for (;;) {
-         while (ibp[0] == '\\' && ibp[1] == '\n') {
-           ++ip->lineno;
-           ibp += 2;
+         if (!ip->macro) {
+           while (ibp[0] == '\\' && ibp[1] == '\n') {
+             ++ip->lineno;
+             ibp += 2;
+           }
          }
          c = *ibp++;
          if (!is_idchar[c] && c != '.') {
@@ -3071,9 +3090,11 @@ do { ip = &instack[indepth];             \
          /* A sign can be part of a preprocessing number
             if it follows an `e' or `p'.  */
          if (c == 'e' || c == 'E' || c == 'p' || c == 'P') {
-           while (ibp[0] == '\\' && ibp[1] == '\n') {
-             ++ip->lineno;
-             ibp += 2;
+           if (!ip->macro) {
+             while (ibp[0] == '\\' && ibp[1] == '\n') {
+               ++ip->lineno;
+               ibp += 2;
+             }
            }
            if (*ibp == '+' || *ibp == '-') {
              *obp++ = *ibp++;
@@ -3333,35 +3354,6 @@ randomchar:
                      old_iln = ip->lineno;
                      old_oln = op->lineno;
                    }
-                   /* A comment: copy it unchanged or discard it.  */
-                   else if (*ibp == '/' && ibp[1] == '*') {
-                     if (put_out_comments) {
-                       *obp++ = '/';
-                       *obp++ = '*';
-                     } else if (! traditional) {
-                       *obp++ = ' ';
-                     }
-                     ibp += 2;
-                     while (ibp + 1 != limit
-                            && !(ibp[0] == '*' && ibp[1] == '/')) {
-                       /* We need not worry about newline-marks,
-                          since they are never found in comments.  */
-                       if (*ibp == '\n') {
-                         /* Newline in a file.  Count it.  */
-                         ++ip->lineno;
-                         ++op->lineno;
-                       }
-                       if (put_out_comments)
-                         *obp++ = *ibp++;
-                       else
-                         ibp++;
-                     }
-                     ibp += 2;
-                     if (put_out_comments) {
-                       *obp++ = '*';
-                       *obp++ = '/';
-                     }
-                   }
                    else if (is_space[*ibp]) {
                      *obp++ = *ibp++;
                      if (ibp[-1] == '\n') {
@@ -3388,6 +3380,100 @@ randomchar:
                        }
                      }
                    }
+                   else if (ip->macro)
+                     break;
+                   else if (*ibp == '/') {
+                     /* If a comment, copy it unchanged or discard it.  */
+                     if (ibp[1] == '\\')
+                       newline_fix (ibp + 1);
+                     if (ibp[1] == '*') {
+                       if (put_out_comments) {
+                         *obp++ = '/';
+                         *obp++ = '*';
+                       } else if (! traditional) {
+                         *obp++ = ' ';
+                       }
+                       for (ibp += 2; ibp < limit; ibp++) {
+                         /* We need not worry about newline-marks,
+                            since they are never found in comments.  */
+                         if (ibp[0] == '*') {
+                           if (ibp[1] == '\\')
+                             newline_fix (ibp + 1);
+                           if (ibp[1] == '/') {
+                             ibp += 2;
+                             if (put_out_comments) {
+                               *obp++ = '*';
+                               *obp++ = '/';
+                             }
+                             break;
+                           }
+                         }
+                         else if (*ibp == '\n') {
+                           /* Newline in a file.  Count it.  */
+                           ++ip->lineno;
+                           ++op->lineno;
+                         }
+                         else
+                           {
+#ifdef MULTIBYTE_CHARS
+                             int length;
+                             length = local_mblen (ibp, limit - ibp);
+                             if (length > 1)
+                               {
+                                 if (put_out_comments)
+                                   {
+                                     bcopy (ibp, obp, length - 1);
+                                     obp += length - 1;
+                                   }
+                                 ibp += (length - 1);
+                               }
+#endif
+                           }
+                         if (put_out_comments)
+                           *obp++ = *ibp;
+                       }
+                     } else if (ibp[1] == '/' && cplusplus_comments) {
+                       if (put_out_comments) {
+                         *obp++ = '/';
+                         *obp++ = '/';
+                       } else if (! traditional) {
+                         *obp++ = ' ';
+                       }
+                       for (ibp += 2; ; ibp++)
+                         {
+                           if (*ibp == '\n')
+                             break;
+                           if (*ibp == '\\' && ibp[1] == '\n')
+                             {
+                               if (put_out_comments)
+                                 *obp++ = *ibp++;
+                             }
+                           else
+                             {
+#ifdef MULTIBYTE_CHARS
+                               int length;
+                               length = local_mblen (ibp, limit - ibp);
+                               if (length > 1)
+                                 {
+                                   if (put_out_comments)
+                                     {
+                                       bcopy (ibp, obp, length - 1);
+                                       obp += length - 1;
+                                     }
+                                   ibp += (length - 1);
+                                 }
+#endif
+                             }
+                           if (put_out_comments)
+                             *obp++ = *ibp;
+                         }
+                     } else
+                       break;
+                   }
+                   else if (ibp[0] == '\\' && ibp[1] == '\n') {
+                     ibp += 2;
+                     ++ip->lineno;
+                   }
                    else break;
                  }
                  if (*ibp != '(') {
@@ -3548,6 +3634,7 @@ expand_to_temp_buffer (buf, limit, output_marks, assertions)
   ip = &instack[indepth];
   ip->fname = 0;
   ip->nominal_fname = 0;
+  ip->nominal_fname_len = 0;
   ip->inc = 0;
   ip->system_header_p = 0;
   ip->macro = 0;
@@ -3567,9 +3654,6 @@ expand_to_temp_buffer (buf, limit, output_marks, assertions)
   if (indepth != odepth)
     abort ();
 
-  /* Record the output.  */
-  obuf.length = obuf.bufp - obuf.buf;
-
   assertions_flag = save_assertions_flag;
   return obuf;
 }
@@ -3608,14 +3692,19 @@ handle_directive (ip, op)
   /* Record where the directive started.  do_xifdef needs this.  */
   directive_start = bp - 1;
 
+  ignore_escape_flag = 1;
+
   /* Skip whitespace and \-newline.  */
   while (1) {
     if (is_hor_space[*bp]) {
       if (*bp != ' ' && *bp != '\t' && pedantic)
-       pedwarn ("%s in preprocessing directive", char_name[*bp]);
+       pedwarn_strange_white_space (*bp);
       bp++;
-    } else if (*bp == '/' && (bp[1] == '*'
-                             || (cplusplus_comments && bp[1] == '/'))) {
+    } else if (*bp == '/') {
+      if (bp[1] == '\\')
+       newline_fix (bp + 1);
+      if (! (bp[1] == '*' || (cplusplus_comments && bp[1] == '/')))
+       break;
       ip->bufp = bp + 2;
       skip_to_end_of_comment (ip, &ip->lineno, 0);
       bp = ip->bufp;
@@ -3633,7 +3722,7 @@ handle_directive (ip, op)
     if (is_idchar[*cp])
       cp++;
     else {
-      if (*cp == '\\' && cp[1] == '\n')
+      if (*cp == '\\')
        name_newline_fix (cp);
       if (is_idchar[*cp])
        cp++;
@@ -3667,6 +3756,7 @@ handle_directive (ip, op)
        pedwarn ("`#' followed by integer");
       after_ident = ident;
       kt = line_directive_table;
+      ignore_escape_flag = 0;
       goto old_linenum;
     }
 
@@ -3723,18 +3813,33 @@ handle_directive (ip, op)
        register U_CHAR c = *bp++;
        switch (c) {
        case '\\':
-         if (bp < limit) {
-           if (*bp == '\n') {
-             ip->lineno++;
-             copy_directive = 1;
-             bp++;
-           } else if (traditional)
-             bp++;
-         }
+         if (*bp == '\n') {
+           ip->lineno++;
+           copy_directive = 1;
+           bp++;
+         } else if (traditional && bp < limit)
+           bp++;
          break;
 
+       case '"':
+         /* "..." is special for #include.  */
+         if (IS_INCLUDE_DIRECTIVE_TYPE (kt->type)) {
+           while (bp < limit && *bp != '\n') {
+             if (*bp == '"') {
+               bp++;
+               break;
+             }
+             if (*bp == '\\' && bp[1] == '\n') {
+               ip->lineno++;
+               copy_directive = 1;
+               bp++;
+             }
+             bp++;
+           }
+           break;
+         }
+         /* Fall through.  */
        case '\'':
-       case '\"':
          bp = skip_quoted_string (bp - 1, limit, ip->lineno, &ip->lineno, &copy_directive, &unterminated);
          /* Don't bother calling the directive if we already got an error
             message due to unterminated string.  Skip everything and pretend
@@ -3765,7 +3870,7 @@ handle_directive (ip, op)
          break;
 
        case '/':
-         if (*bp == '\\' && bp[1] == '\n')
+         if (*bp == '\\')
            newline_fix (bp);
          if (*bp == '*'
              || (cplusplus_comments && *bp == '/')) {
@@ -3794,7 +3899,7 @@ handle_directive (ip, op)
        case '\r':
        case '\v':
          if (pedantic)
-           pedwarn ("%s in preprocessing directive", char_name[c]);
+           pedwarn_strange_white_space (c);
          break;
 
        case '\n':
@@ -3814,7 +3919,8 @@ handle_directive (ip, op)
       /* If a directive should be copied through, and -C was given,
         pass it through before removing comments.  */
       if (!no_output && put_out_comments
-         && (kt->type == T_DEFINE ? dump_macros == dump_definitions
+         && ((kt->type == T_DEFINE || kt->type == T_UNDEF)
+             ? dump_macros == dump_definitions
              : IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes
              : kt->type == T_PRAGMA)) {
         int len;
@@ -3847,12 +3953,13 @@ handle_directive (ip, op)
        register U_CHAR *xp = buf;
        /* Need to copy entire directive into temp buffer before dispatching */
 
-       cp = (U_CHAR *) alloca (bp - buf + 5); /* room for directive plus
-                                                 some slop */
+       /* room for directive plus some slop */
+       cp = (U_CHAR *) alloca (2 * (bp - buf) + 5);
        buf = cp;
 
        /* Copy to the new buffer, deleting comments
-          and backslash-newlines (and whitespace surrounding the latter).  */
+          and backslash-newlines (and whitespace surrounding the latter
+          if outside of char and string constants).  */
 
        while (xp < bp) {
          register U_CHAR c = *xp++;
@@ -3896,16 +4003,32 @@ handle_directive (ip, op)
          case '\'':
          case '\"':
            {
+             int backslash_newlines_p;
+
              register U_CHAR *bp1
                = skip_quoted_string (xp - 1, bp, ip->lineno,
-                                     NULL_PTR, NULL_PTR, NULL_PTR);
-             while (xp != bp1)
-               if (*xp == '\\') {
-                 if (*++xp != '\n')
-                   *cp++ = '\\';
-                 else
-                   xp++;
-               } else
+                                     NULL_PTR, &backslash_newlines_p, 
+                                     NULL_PTR);
+             if (backslash_newlines_p)
+               while (xp != bp1)
+                 {
+                   /* With something like:
+
+                        #define X "a\
+                        b"
+
+                      we should still remove the backslash-newline
+                      pair as part of phase two.  */
+                   if (xp[0] == '\\' && xp[1] == '\n')
+                     xp += 2;
+                   else
+                     *cp++ = *xp++;
+                 }
+             else
+               /* This is the same as the loop above, but taking
+                  advantage of the fact that we know there are no
+                  backslash-newline pairs.  */
+               while (xp != bp1)
                  *cp++ = *xp++;
            }
            break;
@@ -3943,7 +4066,8 @@ handle_directive (ip, op)
         directives through.  */
 
       if (!no_output && already_output == 0
-         && (kt->type == T_DEFINE ? dump_names <= dump_macros
+         && ((kt->type == T_DEFINE || kt->type == T_UNDEF)
+             ? (int) dump_names <= (int) dump_macros
              : IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes
              : kt->type == T_PRAGMA)) {
         int len;
@@ -3972,7 +4096,7 @@ handle_directive (ip, op)
          bcopy (buf, (char *) op->bufp, len);
        }
        op->bufp += len;
-      }                                /* Don't we need a newline or #line? */
+      }
 
       /* Call the appropriate directive handler.  buf now points to
         either the appropriate place in the input buffer, or to
@@ -3994,12 +4118,19 @@ handle_directive (ip, op)
 static struct tm *
 timestamp ()
 {
-  static struct tm *timebuf;
-  if (!timebuf) {
+  static struct tm tmbuf;
+  if (! tmbuf.tm_mday) {
     time_t t = time ((time_t *) 0);
-    timebuf = localtime (&t);
+    struct tm *tm = localtime (&t);
+    if (tm)
+      tmbuf = *tm;
+    else {
+      /* Use 0000-01-01 00:00:00 if local time is not available.  */
+      tmbuf.tm_year = -1900;
+      tmbuf.tm_mday = 1;
+    }
   }
-  return timebuf;
+  return &tmbuf;
 }
 
 static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -4043,16 +4174,14 @@ special_symbol (hp, op)
   case T_FILE:
   case T_BASE_FILE:
     {
-      char *string;
-      if (hp->type == T_FILE)
-       string = ip->nominal_fname;
-      else
-       string = instack[0].nominal_fname;
+      FILE_BUF *p = hp->type == T_FILE ? ip : &instack[0];
+      char *string = p->nominal_fname;
 
       if (string)
        {
-         buf = (char *) alloca (3 + 4 * strlen (string));
-         quote_string (buf, string);
+         size_t string_len = p->nominal_fname_len;
+         buf = (char *) alloca (3 + 4 * string_len);
+         quote_string (buf, string, string_len);
        }
       else
        buf = "\"\"";
@@ -4092,7 +4221,7 @@ special_symbol (hp, op)
     break;
 
   case T_USER_LABEL_PREFIX_TYPE:
-    buf = USER_LABEL_PREFIX;
+    buf = user_label_prefix;
     break;
 
   case T_REGISTER_PREFIX_TYPE:
@@ -4153,7 +4282,12 @@ special_symbol (hp, op)
              || (hp->type == T_MACRO && hp->value.defn->predefined)))
        /* Output a precondition for this macro use.  */
        fprintf (pcp_outfile, "#define %s\n", hp->name);
-      buf = " 1 ";
+      if (hp->type == T_POISON) {
+       error("attempt to use poisoned `%s'.", hp->name);
+       buf = " 0 ";
+      } else {
+       buf = " 1 ";
+      }
     }
     else
       if (pcp_outfile && pcp_inside_if)        {
@@ -4174,6 +4308,11 @@ special_symbol (hp, op)
     }
     break;
 
+  case T_POISON:
+    error("attempt to use poisoned `%s'.", hp->name);
+    buf = " 0 ";       /* Consider poisoned symbol to not be defined */
+    break;
+
 oops:
 
     error ("`defined' without an identifier");
@@ -4243,16 +4382,18 @@ do_include (buf, limit, op, keyword)
       && !instack[indepth].system_header_p && !import_warning) {
     import_warning = 1;
     warning ("using `#import' is not recommended");
-    fprintf (stderr, "The fact that a certain header file need not be processed more than once\n");
-    fprintf (stderr, "should be indicated in the header file, not where it is used.\n");
-    fprintf (stderr, "The best way to do this is with a conditional of this form:\n\n");
-    fprintf (stderr, "  #ifndef _FOO_H_INCLUDED\n");
-    fprintf (stderr, "  #define _FOO_H_INCLUDED\n");
-    fprintf (stderr, "  ... <real contents of file> ...\n");
-    fprintf (stderr, "  #endif /* Not _FOO_H_INCLUDED */\n\n");
-    fprintf (stderr, "Then users can use `#include' any number of times.\n");
-    fprintf (stderr, "GNU C automatically avoids processing the file more than once\n");
-    fprintf (stderr, "when it is equipped with such a conditional.\n");
+    notice ("The fact that a certain header file need not be processed more than once\n\
+should be indicated in the header file, not where it is used.\n\
+The best way to do this is with a conditional of this form:\n\
+\n\
+  #ifndef _FOO_H_INCLUDED\n\
+  #define _FOO_H_INCLUDED\n\
+  ... <real contents of file> ...\n\
+  #endif /* Not _FOO_H_INCLUDED */\n\
+\n\
+Then users can use `#include' any number of times.\n\
+GNU C automatically avoids processing the file more than once\n\
+when it is equipped with such a conditional.\n");
   }
 
 get_filename:
@@ -4270,10 +4411,15 @@ get_filename:
       FILE_BUF *fp;
       /* Copy the operand text, concatenating the strings.  */
       {
-       while (fin != limit) {
-         while (fin != limit && *fin != '\"')
-           *fend++ = *fin++;
-         fin++;
+       for (;;) {
+         for (;;) {
+           if (fin == limit)
+             goto invalid_include_file_name;
+           *fend = *fin++;
+           if (*fend == '"')
+             break;
+           fend++;
+         }
          if (fin == limit)
            break;
          /* If not at the end, there had better be another string.  */
@@ -4301,11 +4447,22 @@ get_filename:
            /* Found a named file.  Figure out dir of the file,
               and put it in front of the search list.  */
            dsp = ((struct file_name_list *)
-                  alloca (sizeof (struct file_name_list) + strlen (nam)));
+                  alloca (sizeof (struct file_name_list)
+                          + fp->nominal_fname_len));
            strcpy (dsp->fname, nam);
            simplify_filename (dsp->fname);
            nam = base_name (dsp->fname);
            *nam = 0;
+#ifdef VMS
+           /* for hack_vms_include_specification(), a local
+              dir specification must start with "./" on VMS.  */
+           if (nam == dsp->fname)
+             {    
+               *nam++ = '.';
+               *nam++ = '/';
+               *nam = 0;
+             }
+#endif
            /* But for efficiency's sake, do not insert the dir
               if it matches the search list's first dir.  */
            dsp->next = search_start;
@@ -4341,8 +4498,10 @@ get_filename:
      * code from case '<' is repeated here) and generates a warning.
      * (Note: macro expansion of `xyz' takes precedence.)
      */
-    if (retried && isalpha(*(U_CHAR *) (--fbeg))) {
-      while (fin != limit && (!isspace(*fin)))
+    /* Note: The argument of ISALPHA() can be evaluated twice, so do
+       the pre-decrement outside of the macro. */
+    if (retried && (--fin, ISALPHA(*(U_CHAR *) (fin)))) {
+      while (fin != limit && (!ISSPACE(*fin)))
        *fend++ = *fin++;
       warning ("VAX-C-style include specification found, use '#include <filename.h>' !");
       vaxc_include = 1;
@@ -4356,16 +4515,18 @@ get_filename:
 #endif
 
   fail:
-    if (retried) {
-      error ("`#%s' expects \"FILENAME\" or <FILENAME>", keyword->name);
-      return 0;
-    } else {
+    if (! retried) {
       /* Expand buffer and then remove any newline markers.
         We can't just tell expand_to_temp_buffer to omit the markers,
         since it would put extra spaces in include file names.  */
       FILE_BUF trybuf;
       U_CHAR *src;
+      int errors_before_expansion = errors;
       trybuf = expand_to_temp_buffer (buf, limit, 1, 0);
+      if (errors != errors_before_expansion) {
+       free (trybuf.buf);
+       goto invalid_include_file_name;
+      }
       src = trybuf.buf;
       buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1);
       limit = buf;
@@ -4389,9 +4550,13 @@ get_filename:
       }
       *limit = 0;
       free (trybuf.buf);
-      retried++;
+      retried = 1;
       goto get_filename;
     }
+
+  invalid_include_file_name:
+    error ("`#%s' expects \"FILENAME\" or <FILENAME>", keyword->name);
+    return 0;
   }
 
   /* For #include_next, skip in the search path
@@ -4456,22 +4621,37 @@ get_filename:
          }
       }
 
-      strcpy (fname, searchptr->fname);
-      strcat (fname, fbeg);
 #ifdef VMS
       /* Change this 1/2 Unix 1/2 VMS file specification into a
          full VMS file specification */
-      if (searchptr->fname[0]) {
-       /* Fix up the filename */
-       hack_vms_include_specification (fname, vaxc_include);
-      } else {
-       /* This is a normal VMS filespec, so use it unchanged.  */
-       strcpy (fname, fbeg);
-       /* if it's '#include filename', add the missing .h */
-       if (vaxc_include && index(fname,'.')==NULL) {
-         strcat (fname, ".h");
+      if (searchptr->fname[0])
+       {
+         strcpy (fname, searchptr->fname);
+         if (fname[strlen (fname) - 1] == ':')
+           {
+             char *slashp;
+             slashp = strchr (fbeg, '/');
+
+             /* start at root-dir of logical device if no path given.  */
+             if (slashp == 0)
+               strcat (fname, "[000000]");
+           }
+         strcat (fname, fbeg);
+
+         /* Fix up the filename */
+         hack_vms_include_specification (fname, vaxc_include);
        }
-      }
+      else
+       {
+         /* This is a normal VMS filespec, so use it unchanged.  */
+         strcpy (fname, fbeg);
+         /* if it's '#include filename', add the missing .h */
+         if (vaxc_include && index(fname,'.')==NULL)
+           strcat (fname, ".h");
+       }
+#else
+      strcpy (fname, searchptr->fname);
+      strcat (fname, fbeg);
 #endif /* VMS */
       f = open_include_file (fname, searchptr, importing, &inc);
       if (f != -1) {
@@ -4583,10 +4763,8 @@ get_filename:
     
     /* Actually process the file */
     if (pcfbuf) {
-      pcfname = xmalloc (strlen (pcftry) + 1);
-      strcpy (pcfname, pcftry);
-      pcfinclude ((U_CHAR *) pcfbuf, (U_CHAR *) pcfbuflimit,
-                 (U_CHAR *) fname, op);
+      pcfname = xstrdup (pcftry);
+      pcfinclude ((U_CHAR *) pcfbuf, (U_CHAR *) fname, op);
     }
     else
       finclude (f, inc, op, is_system_include (fname), searchptr);
@@ -4630,7 +4808,7 @@ base_name (fname)
   char *s = fname;
   char *p;
 #if defined (__MSDOS__) || defined (_WIN32)
-  if (isalpha (s[0]) && s[1] == ':') s += 2;
+  if (ISALPHA (s[0]) && s[1] == ':') s += 2;
 #endif
 #ifdef VMS
   if ((p = rindex (s, ':'))) s = p + 1;        /* Skip device.  */
@@ -4652,12 +4830,16 @@ static int
 absolute_filename (filename)
      char *filename;
 {
-#if defined (__MSDOS__) || (defined (_WIN32) && !defined (__CYGWIN32__))
-  if (isalpha (filename[0]) && filename[1] == ':') filename += 2;
+#if defined (__MSDOS__) \
+  || (defined (_WIN32) && !defined (__CYGWIN__) && !defined (_UWIN))
+  if (ISALPHA (filename[0]) && filename[1] == ':') filename += 2;
 #endif
-#if defined (__CYGWIN32__)
+#if defined (__CYGWIN__)
   /* At present, any path that begins with a drive spec is absolute.  */
-  if (isalpha (filename[0]) && filename[1] == ':') return 1;
+  if (ISALPHA (filename[0]) && filename[1] == ':') return 1;
+#endif
+#ifdef VMS
+  if (index (filename, ':') != 0) return 1;
 #endif
   if (filename[0] == '/') return 1;
 #ifdef DIR_SEPARATOR
@@ -4666,6 +4848,20 @@ absolute_filename (filename)
   return 0;
 }
 
+/* Returns whether or not a given character is a directory separator.
+   Used by simplify_filename.  */
+static inline
+int
+is_dir_separator(ch)
+     char ch;
+{
+  return (ch == DIR_SEPARATOR)
+#if defined (DIR_SEPARATOR_2)
+          || (ch == DIR_SEPARATOR_2)
+#endif
+         ;
+}
+
 /* Remove unnecessary characters from FILENAME in place,
    to avoid unnecessary filename aliasing.
    Return the length of the resulting string.
@@ -4683,52 +4879,59 @@ simplify_filename (filename)
   char *to0;
 
   /* Remove redundant initial /s.  */
-  if (*from == '/') {
-    *to++ = '/';
-    if (*++from == '/') {
-      if (*++from == '/') {
-       /* 3 or more initial /s are equivalent to 1 /.  */
-       while (*++from == '/')
-         continue;
-      } else {
-       /* On some hosts // differs from /; Posix allows this.  */
-       static int slashslash_vs_slash;
-       if (slashslash_vs_slash == 0) {
-         struct stat s1, s2;
-         slashslash_vs_slash = ((stat ("/", &s1) == 0 && stat ("//", &s2) == 0
-                                 && INO_T_EQ (s1.st_ino, s2.st_ino)
-                                 && s1.st_dev == s2.st_dev)
-                                ? 1 : -1);
-       }
-       if (slashslash_vs_slash < 0)
-         *to++ = '/';
-      }
+  if (is_dir_separator (*from))
+    {
+      *to++ = DIR_SEPARATOR;
+      if (is_dir_separator (*++from))
+        {
+          if (is_dir_separator (*++from))
+            {
+              /* 3 or more initial /s are equivalent to 1 /.  */
+              while (is_dir_separator (*++from))
+                continue;
+            }
+          else
+            {
+             /* On some hosts // differs from /; Posix allows this.  */
+             *to++ = DIR_SEPARATOR;
+            }
+        }
     }
-  }
-  to0 = to;
 
-  for (;;) {
-    if (from[0] == '.' && from[1] == '/')
-      from += 2;
-    else {
-      /* Copy this component and trailing /, if any.  */
-      while ((*to++ = *from++) != '/') {
-       if (!to[-1]) {
-         /* Trim . component at end of nonempty name.  */
-         to -= filename <= to - 3 && to[-3] == '/' && to[-2] == '.';
-
-         /* Trim unnecessary trailing /s.  */
-         while (to0 < --to && to[-1] == '/')
-           continue;
+  to0 = to;
 
-         *to = 0;
-         return to - filename;
-       }
-      }
-    }
+  for (;;)
+    {
+#ifndef VMS
+      if (from[0] == '.' && from[1] == '/')
+        from += 2;
+      else
+#endif
+        {
+          /* Copy this component and trailing DIR_SEPARATOR, if any.  */
+          while (!is_dir_separator (*to++ = *from++))
+            {
+              if (!to[-1])
+                {
+                  /* Trim . component at end of nonempty name.  */
+                  to -= filename <= to - 3 && to[-3] == DIR_SEPARATOR && to[-2] == '.';
+
+                  /* Trim unnecessary trailing /s.  */
+                  while (to0 < --to && to[-1] == DIR_SEPARATOR)
+                    continue;
+
+                  *to = 0;
+                  return to - filename;
+                }
+            }
+#if defined(DIR_SEPARATOR_2)
+          /* Simplify to one directory separator.  */
+          to[-1] = DIR_SEPARATOR;
+#endif
+        }
 
     /* Skip /s after a /.  */
-    while (*from == '/')
+    while (is_dir_separator (*from))
       from++;
   }
 }
@@ -4811,7 +5014,7 @@ read_name_map (dirname)
 
   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_name = xstrdup (dirname);
   map_list_ptr->map_list_map = NULL;
 
   dirlen = strlen (dirname);
@@ -4908,7 +5111,16 @@ open_include_file (filename, searchptr, importing, pinc)
     fd = open (fname, O_RDONLY, 0);
 
     if (fd < 0)
-      return fd;
+      {
+#ifdef VMS
+       /* if #include <dir/file> fails, try again with hacked spec.  */
+       if (!hack_vms_include_specification (fname, 0))
+         return fd;
+       fd = open (fname, O_RDONLY, 0);
+       if (fd < 0)
+#endif
+         return fd;
+      }
 
     if (!inc) {
       /* FNAME was not in include_hashtab; insert a new entry.  */
@@ -4948,7 +5160,7 @@ open_include_file (filename, searchptr, importing, pinc)
   return fd;
 }
 
-/* Return the remapped name of the the include file FILENAME.
+/* Return the remapped name of the include file FILENAME.
    SEARCHPTR is the directory being tried from the include file path.  */
 
 static char *
@@ -5045,6 +5257,7 @@ finclude (f, inc, op, system_header_p, dirptr)
   fp = &instack[indepth + 1];
   bzero ((char *) fp, sizeof (FILE_BUF));
   fp->nominal_fname = fp->fname = fname;
+  fp->nominal_fname_len = strlen (fname);
   fp->inc = inc;
   fp->length = 0;
   fp->lineno = 1;
@@ -5112,6 +5325,9 @@ finclude (f, inc, op, system_header_p, dirptr)
   if (!no_trigraphs)
     trigraph_pcp (fp);
 
+  if (warn_white_space)
+    check_white_space (fp);
+
   output_line_directive (fp, op, 0, enter_file);
   rescan (op, 0);
 
@@ -5164,7 +5380,7 @@ static char *
 check_precompiled (pcf, st, fname, limit)
      int pcf;
      struct stat *st;
-     char *fname;
+     char *fname ATTRIBUTE_UNUSED;
      char **limit;
 {
   int length = 0;
@@ -5277,8 +5493,8 @@ check_preconditions (prec)
    in.  OP is the main output buffer.  */
 
 static void
-pcfinclude (buf, limit, name, op)
-     U_CHAR *buf, *limit, *name;
+pcfinclude (buf, name, op)
+     U_CHAR *buf, *name;
      FILE_BUF *op;
 {
   FILE_BUF tmpbuf;
@@ -5312,7 +5528,7 @@ pcfinclude (buf, limit, name, op)
       cp += 4 - ((size_t) cp & 3);
     
     /* Now get the string.  */
-    str = (STRINGDEF *) (GENERIC_PTR) cp;
+    str = (STRINGDEF *) (PTR) cp;
     string_start = cp += sizeof (STRINGDEF);
     
     for (; *cp; cp++)          /* skip the string */
@@ -5325,7 +5541,7 @@ pcfinclude (buf, limit, name, op)
     tmpbuf = expand_to_temp_buffer (string_start, cp++, 0, 0);
     /* Lineno is already set in the precompiled file */
     str->contents = tmpbuf.buf;
-    str->len = tmpbuf.length;
+    str->len = tmpbuf.bufp - tmpbuf.buf;
     str->writeflag = 0;
     str->filename = name;
     str->output_mark = outbuf.bufp - outbuf.buf;
@@ -5347,8 +5563,9 @@ pcfinclude (buf, limit, name, op)
     else
       /* Otherwise, for each key, */
       for (; nkeys--; free (tmpbuf.buf), cp = endofthiskey + 1) {
-       KEYDEF *kp = (KEYDEF *) (GENERIC_PTR) cp;
+       KEYDEF *kp = (KEYDEF *) (PTR) cp;
        HASHNODE *hp;
+       U_CHAR *bp;
        
        /* It starts with a KEYDEF structure */
        cp += sizeof (KEYDEF);
@@ -5360,20 +5577,19 @@ pcfinclude (buf, limit, name, op)
        
        /* Expand the key, and enter it into the hash table.  */
        tmpbuf = expand_to_temp_buffer (cp, endofthiskey, 0, 0);
-       tmpbuf.bufp = tmpbuf.buf;
+       bp = tmpbuf.buf;
        
-       while (is_hor_space[*tmpbuf.bufp])
-         tmpbuf.bufp++;
-       if (!is_idstart[*tmpbuf.bufp]
-           || tmpbuf.bufp == tmpbuf.buf + tmpbuf.length) {
+       while (is_hor_space[*bp])
+         bp++;
+       if (!is_idstart[*bp] || bp == tmpbuf.bufp) {
          str->writeflag = 1;
          continue;
        }
            
-       hp = lookup (tmpbuf.bufp, -1, -1);
+       hp = lookup (bp, -1, -1);
        if (hp == NULL) {
          kp->chain = 0;
-         install (tmpbuf.bufp, -1, T_PCSTRING, (char *) kp, -1);
+         install (bp, -1, T_PCSTRING, (char *) kp, -1);
        }
        else if (hp->type == T_PCSTRING) {
          kp->chain = hp->value.keydef;
@@ -5432,7 +5648,8 @@ write_output ()
                                     line_directive_len *= 2);
        sprintf (line_directive, "\n# %d ", next_string->lineno);
        strcpy (quote_string (line_directive + strlen (line_directive),
-                             (char *) next_string->filename),
+                             (char *) next_string->filename,
+                             strlen ((char *) next_string->filename)),
                "\n");
        safe_write (fileno (stdout), line_directive, strlen (line_directive));
        safe_write (fileno (stdout),
@@ -5464,7 +5681,7 @@ pass_thru_directive (buf, limit, op, keyword)
      FILE_BUF *op;
      struct directive *keyword;
 {
-  register unsigned keyword_length = keyword->length;
+  register int keyword_length = keyword->length;
 
   check_expand (op, 1 + keyword_length + (limit - buf));
   *op->bufp++ = '#';
@@ -5514,6 +5731,7 @@ create_definition (buf, limit, op)
   int sym_length;              /* and how long it is */
   int line = instack[indepth].lineno;
   char *file = instack[indepth].nominal_fname;
+  size_t file_len = instack[indepth].nominal_fname_len;
   int rest_args = 0;
 
   DEFINITION *defn;
@@ -5527,7 +5745,7 @@ create_definition (buf, limit, op)
     bp++;
 
   symname = bp;                        /* remember where it starts */
-  sym_length = check_macro_name (bp, "macro");
+  sym_length = check_macro_name (bp, 0);
   bp += sym_length;
 
   /* Lossage will occur if identifiers or control keywords are broken
@@ -5557,13 +5775,24 @@ create_definition (buf, limit, op)
                 rest_extension);
 
       if (!is_idstart[*bp])
+       {
+         if (c9x && limit - bp > (long) REST_EXTENSION_LENGTH
+             && bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0)
+           {
+             /* This is the ISO C 9x way to write macros with variable
+                number of arguments.  */
+             rest_args = 1;
+             temp->rest_args = 1;
+           }
+         else
        pedwarn ("invalid character in macro parameter name");
+       }
       
       /* Find the end of the arg name.  */
       while (is_idchar[*bp]) {
        bp++;
        /* do we have a "special" rest-args extension here? */
-       if (limit - bp > REST_EXTENSION_LENGTH
+       if (limit - bp > (long) REST_EXTENSION_LENGTH
            && bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) {
          if (pedantic && !instack[indepth].system_header_p)
            pedwarn ("ANSI C does not allow macro with variable arguments");
@@ -5572,6 +5801,13 @@ create_definition (buf, limit, op)
          break;
        }
       }
+      if (bp == temp->name && rest_args == 1)
+       {
+         /* This is the ISO C 9x style.  */
+         temp->name = (U_CHAR *) va_args_name;
+         temp->length = VA_ARGS_NAME_LENGTH;
+       }
+      else
       temp->length = bp - temp->name;
       if (rest_args == 1)
        bp += REST_EXTENSION_LENGTH;
@@ -5585,7 +5821,9 @@ create_definition (buf, limit, op)
        bp++;
        SKIP_WHITE_SPACE (bp);
        /* A comma at this point can only be followed by an identifier.  */
-       if (!is_idstart[*bp]) {
+       if (!is_idstart[*bp]
+           && !(c9x && limit - bp > (long) REST_EXTENSION_LENGTH
+               &&  bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0)) {
          error ("badly punctuated parameter list in `#define'");
          goto nope;
        }
@@ -5599,11 +5837,19 @@ create_definition (buf, limit, op)
 
        for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
          if (temp->length == otemp->length
-             && bcmp (temp->name, otemp->name, temp->length) == 0) {
+             && bcmp (temp->name, otemp->name, temp->length) == 0)
+           {
              error ("duplicate argument name `%.*s' in `#define'",
                     temp->length, temp->name);
              goto nope;
          }
+       if (rest_args == 0 && temp->length == VA_ARGS_NAME_LENGTH
+           && bcmp (temp->name, va_args_name, VA_ARGS_NAME_LENGTH) == 0)
+         {
+           error ("\
+reserved name `%s' used as argument name in `#define'", va_args_name);
+           goto nope;
+         }
       }
     }
 
@@ -5663,6 +5909,7 @@ create_definition (buf, limit, op)
 
   defn->line = line;
   defn->file = file;
+  defn->file_len = file_len;
 
   /* OP is null if this is a predefinition */
   defn->predefined = !op;
@@ -5690,6 +5937,7 @@ do_define (buf, limit, op, keyword)
 {
   int hashcode;
   MACRODEF mdef;
+  enum node_type newtype = keyword->type == T_DEFINE ? T_MACRO : T_POISON;
 
   /* If this is a precompiler run (with -pcp) pass thru #define directives.  */
   if (pcp_outfile && op)
@@ -5708,33 +5956,50 @@ do_define (buf, limit, op, keyword)
       /* Redefining a precompiled key is ok.  */
       if (hp->type == T_PCSTRING)
        ok = 1;
+      /* Redefining a poisoned identifier is even worse than `not ok'.  */
+      else if (hp->type == T_POISON)
+        ok = -1;
+      /* Poisoning anything else is not ok.  
+        The poison should always come first.  */
+      else if (newtype == T_POISON)
+       ok = 0;
       /* Redefining a macro is ok if the definitions are the same.  */
       else if (hp->type == T_MACRO)
        ok = ! compare_defs (mdef.defn, hp->value.defn);
       /* Redefining a constant is ok with -D.  */
       else if (hp->type == T_CONST)
         ok = ! done_initializing;
-      /* Print the warning if it's not ok.  */
-      if (!ok) {
-        /* If we are passing through #define and #undef directives, do
-          that for this re-definition now.  */
-        if (debug_output && op)
-         pass_thru_directive (buf, limit, op, keyword);
-
-       pedwarn ("`%.*s' redefined", mdef.symlen, mdef.symnam);
-       if (hp->type == T_MACRO)
-         pedwarn_with_file_and_line (hp->value.defn->file, hp->value.defn->line,
-                                     "this is the location of the previous definition");
-      }
-      /* Replace the old definition.  */
-      hp->type = T_MACRO;
-      hp->value.defn = mdef.defn;
+      
+      /* Print the warning or error if it's not ok.  */
+      if (ok <= 0) 
+       {
+         /* If we are passing through #define and #undef directives, do
+            that for this re-definition now.  */
+         if (debug_output && op)
+           pass_thru_directive (buf, limit, op, keyword);
+         
+         if (hp->type == T_POISON)
+           error ("redefining poisoned `%.*s'", mdef.symlen, mdef.symnam);
+         else
+           pedwarn ("`%.*s' redefined", mdef.symlen, mdef.symnam);
+         if (hp->type == T_MACRO)
+           pedwarn_with_file_and_line (hp->value.defn->file,
+                                       hp->value.defn->file_len,
+                                       hp->value.defn->line,
+                                       "this is the location of the previous definition");
+       }
+      if (hp->type != T_POISON)
+       {
+         /* Replace the old definition.  */
+         hp->type = newtype;
+         hp->value.defn = mdef.defn;
+       }
     } else {
       /* If we are passing through #define and #undef directives, do
         that for this new definition now.  */
       if (debug_output && op)
        pass_thru_directive (buf, limit, op, keyword);
-      install (mdef.symnam, mdef.symlen, T_MACRO,
+      install (mdef.symnam, mdef.symlen, newtype,
               (char *) mdef.defn, hashcode);
     }
   }
@@ -5747,12 +6012,12 @@ nope:
 }
 \f
 /* Check a purported macro name SYMNAME, and yield its length.
-   USAGE is the kind of name this is intended for.  */
+   ASSERTION is nonzero if this is really for an assertion name.  */
 
 static int
-check_macro_name (symname, usage)
+check_macro_name (symname, assertion)
      U_CHAR *symname;
-     char *usage;
+     int assertion;
 {
   U_CHAR *p;
   int sym_length;
@@ -5762,10 +6027,13 @@ check_macro_name (symname, usage)
   sym_length = p - symname;
   if (sym_length == 0
       || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
-    error ("invalid %s name", usage);
+    error (assertion ? "invalid assertion name" : "invalid macro name");
   else if (!is_idstart[*symname]
           || (sym_length == 7 && ! bcmp (symname, "defined", 7)))
-    error ("invalid %s name `%.*s'", usage, sym_length, symname);
+    error ((assertion
+           ? "invalid assertion name `%.*s'"
+           : "invalid macro name `%.*s'"),
+          sym_length, symname);
   return sym_length;
 }
 
@@ -5928,7 +6196,7 @@ collect_expansion (buf, end, nargs, arglist)
        break;
 
       case '\\':
-       if (p < limit && expected_delimiter) {
+       if (expected_delimiter) {
          /* In a string, backslash goes through
             and makes next char ordinary.  */
          *exp_p++ = *p++;
@@ -5998,7 +6266,7 @@ collect_expansion (buf, end, nargs, arglist)
       }
     } else {
       /* In -traditional mode, recognize arguments inside strings and
-        and character constants, and ignore special properties of #.
+        character constants, and ignore special properties of #.
         Arguments inside strings are considered "stringified", but no
         extra quote marks are supplied.  */
       switch (c) {
@@ -6043,6 +6311,25 @@ collect_expansion (buf, end, nargs, arglist)
       }
     }
 
+#ifdef MULTIBYTE_CHARS
+    /* Handle multibyte characters inside string and character literals.  */
+    if (expected_delimiter != '\0')
+      {
+       int length;
+       --p;
+       length = local_mblen (p, limit - p);
+       if (length > 1)
+         {
+           --exp_p;
+           bcopy (p, exp_p, length);
+           p += length;
+           exp_p += length;
+           continue;
+         }
+       ++p;
+      }
+#endif
+
     /* Handle the start of a symbol.  */
     if (is_idchar[c] && nargs > 0) {
       U_CHAR *id_beg = p - 1;
@@ -6155,8 +6442,8 @@ collect_expansion (buf, end, nargs, arglist)
 static int
 do_assert (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
-     FILE_BUF *op;
-     struct directive *keyword;
+     FILE_BUF *op ATTRIBUTE_UNUSED;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
   U_CHAR *bp;                  /* temp ptr into input buffer */
   U_CHAR *symname;             /* remember where symbol name starts */
@@ -6172,7 +6459,7 @@ do_assert (buf, limit, op, keyword)
     bp++;
 
   symname = bp;                        /* remember where it starts */
-  sym_length = check_macro_name (bp, "assertion");
+  sym_length = check_macro_name (bp, 1);
   bp += sym_length;
   /* #define doesn't do this, but we should.  */
   SKIP_WHITE_SPACE (bp);
@@ -6232,8 +6519,8 @@ do_assert (buf, limit, op, keyword)
 static int
 do_unassert (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
-     FILE_BUF *op;
-     struct directive *keyword;
+     FILE_BUF *op ATTRIBUTE_UNUSED;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
   U_CHAR *bp;                  /* temp ptr into input buffer */
   U_CHAR *symname;             /* remember where symbol name starts */
@@ -6251,7 +6538,7 @@ do_unassert (buf, limit, op, keyword)
     bp++;
 
   symname = bp;                        /* remember where it starts */
-  sym_length = check_macro_name (bp, "assertion");
+  sym_length = check_macro_name (bp, 1);
   bp += sym_length;
   /* #define doesn't do this, but we should.  */
   SKIP_WHITE_SPACE (bp);
@@ -6510,7 +6797,7 @@ assertion_install (name, len, hash)
   return hp;
 }
 
-/* Find the most recent hash node for name name (ending with first
+/* Find the most recent hash node for name "name" (ending with first
    non-identifier char) installed by install
 
    If LEN is >= 0, it is the length of the name.
@@ -6564,7 +6851,7 @@ static int
 do_line (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
      FILE_BUF *op;
-     struct directive *keyword;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
   register U_CHAR *bp;
   FILE_BUF *ip = &instack[indepth];
@@ -6577,9 +6864,10 @@ do_line (buf, limit, op, keyword)
 
   /* Point to macroexpanded line, which is null-terminated now.  */
   bp = tem.buf;
+  limit = tem.bufp;
   SKIP_WHITE_SPACE (bp);
 
-  if (!isdigit (*bp)) {
+  if (!ISDIGIT (*bp)) {
     error ("invalid format `#line' directive");
     return 0;
   }
@@ -6594,7 +6882,7 @@ do_line (buf, limit, op, keyword)
     pedwarn ("line number out of range in `#line' directive");
 
   /* skip over the line number.  */
-  while (isdigit (*bp))
+  while (ISDIGIT (*bp))
     bp++;
 
 #if 0 /* #line 10"foo.c" is supposed to be allowed.  */
@@ -6619,24 +6907,21 @@ do_line (buf, limit, op, keyword)
     p = bp;
     for (;;)
       switch ((*p++ = *bp++)) {
-      case '\0':
-       error ("invalid format `#line' directive");
-       return 0;
-
       case '\\':
-       {
-         char *bpc = (char *) bp;
-         HOST_WIDE_INT c = parse_escape (&bpc, (HOST_WIDE_INT) (U_CHAR) (-1));
-         bp = (U_CHAR *) bpc;
-         if (c < 0)
-           p--;
-         else
-           p[-1] = c;
-       }
+       if (! ignore_escape_flag)
+         {
+           char *bpc = (char *) bp;
+           HOST_WIDEST_INT c = parse_escape (&bpc, (HOST_WIDEST_INT) (U_CHAR) (-1));
+           bp = (U_CHAR *) bpc;
+           if (c < 0)
+             p--;
+           else
+             p[-1] = c;
+         }
        break;
 
       case '\"':
-       p[-1] = 0;
+       *--p = 0;
        goto fname_done;
       }
   fname_done:
@@ -6682,6 +6967,7 @@ do_line (buf, limit, op, keyword)
       if (hp->length == fname_length &&
          bcmp (hp->value.cpval, fname, fname_length) == 0) {
        ip->nominal_fname = hp->value.cpval;
+       ip->nominal_fname_len = fname_length;
        break;
       }
     if (hp == 0) {
@@ -6690,9 +6976,9 @@ do_line (buf, limit, op, keyword)
       hp->next = *hash_bucket;
       *hash_bucket = hp;
 
-      hp->length = fname_length;
       ip->nominal_fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE);
-      bcopy (fname, hp->value.cpval, fname_length);
+      ip->nominal_fname_len = hp->length = fname_length;
+      bcopy (fname, hp->value.cpval, fname_length + 1);
     }
   } else if (*bp) {
     error ("invalid format `#line' directive");
@@ -6724,16 +7010,20 @@ do_undef (buf, limit, op, keyword)
     pass_thru_directive (buf, limit, op, keyword);
 
   SKIP_WHITE_SPACE (buf);
-  sym_length = check_macro_name (buf, "macro");
+  sym_length = check_macro_name (buf, 0);
 
   while ((hp = lookup (buf, sym_length, -1)) != NULL) {
     /* If we are generating additional info for debugging (with -g) we
        need to pass through all effective #undef directives.  */
     if (debug_output && op)
       pass_thru_directive (orig_buf, limit, op, keyword);
-    if (hp->type != T_MACRO)
-      warning ("undefining `%s'", hp->name);
-    delete_macro (hp);
+    if (hp->type == T_POISON)
+      error ("cannot undefine poisoned `%s'", hp->name);
+    else {
+      if (hp->type != T_MACRO)
+        warning ("undefining `%s'", hp->name);
+      delete_macro (hp);
+    }
   }
 
   if (pedantic) {
@@ -6745,14 +7035,14 @@ do_undef (buf, limit, op, keyword)
   return 0;
 }
 \f
+
 /* Report an error detected by the program we are processing.
-   Use the text of the line in the error message.
-   (We use error because it prints the filename & line#.)  */
+   Use the text of the line in the error message.  */
 
 static int
 do_error (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
-     FILE_BUF *op;
+     FILE_BUF *op ATTRIBUTE_UNUSED;
      struct directive *keyword;
 {
   int length = limit - buf;
@@ -6760,31 +7050,24 @@ do_error (buf, limit, op, keyword)
   bcopy ((char *) buf, (char *) copy, length);
   copy[length] = 0;
   SKIP_WHITE_SPACE (copy);
-  error ("#error %s", copy);
-  return 0;
-}
 
-/* Report a warning detected by the program we are processing.
-   Use the text of the line in the warning message, then continue.
-   (We use error because it prints the filename & line#.)  */
+  switch (keyword->type) {
+  case T_ERROR:
+    error ("#error %s", copy);
+    break;
+
+  case T_WARNING:
+    if (pedantic && !instack[indepth].system_header_p)
+      pedwarn ("ANSI C does not allow `#warning'");
+    warning ("#warning %s", copy);
+    break;
+
+  default:
+    abort ();
+  }
 
-static int
-do_warning (buf, limit, op, keyword)
-     U_CHAR *buf, *limit;
-     FILE_BUF *op;
-     struct directive *keyword;
-{
-  int length = limit - buf;
-  U_CHAR *copy = (U_CHAR *) alloca (length + 1);
-  bcopy ((char *) buf, (char *) copy, length);
-  copy[length] = 0;
-  SKIP_WHITE_SPACE (copy);
-  /* Use `pedwarn' not `warning', because #warning isn't in the C Standard;
-     if -pedantic-errors is given, #warning should cause an error.  */
-  pedwarn ("#warning %s", copy);
   return 0;
 }
-
 /* Remember the name of the current file being read from so that we can
    avoid ever including it again.  */
 
@@ -6806,7 +7089,7 @@ static int
 do_ident (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
      FILE_BUF *op;
-     struct directive *keyword;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
   FILE_BUF trybuf;
   int len;
@@ -6848,6 +7131,29 @@ do_pragma (buf, limit, op, keyword)
     do_once ();
   }
 
+  if (!strncmp (buf, "poison", 6)) {
+    /* Poison these symbols so that all subsequent usage produces an
+       error message.  */
+    U_CHAR *p = buf + 6;
+
+    SKIP_WHITE_SPACE (p);
+    while (p < limit)
+      {
+       U_CHAR *end = p;
+       
+       while (end < limit && is_idchar[*end])
+         end++;
+       if (end < limit && !is_space[*end])
+         {
+           error ("invalid #pragma poison");
+           return 0;
+         }
+       do_define(p, end, op, keyword);
+       p = end;
+       SKIP_WHITE_SPACE (p);
+      }
+  }
+
   if (!strncmp ((char *) buf, "implementation", 14)) {
     /* Be quiet about `#pragma implementation' for a file only if it hasn't
        been included yet.  */
@@ -6859,8 +7165,9 @@ do_pragma (buf, limit, op, keyword)
       return 0;
 
     fname = p + 1;
-    if ((p = (U_CHAR *) index ((char *) fname, '\"')))
-      *p = '\0';
+    p = skip_quoted_string (p, limit, 0, NULL_PTR, NULL_PTR, NULL_PTR);
+    if (p[-1] == '"')
+      *--p = '\0';
     
     for (h = 0; h < INCLUDE_HASHSIZE; h++) {
       struct include_file *inc;
@@ -6906,9 +7213,9 @@ nope:
 
 static int
 do_sccs (buf, limit, op, keyword)
-     U_CHAR *buf, *limit;
-     FILE_BUF *op;
-     struct directive *keyword;
+     U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
+     FILE_BUF *op ATTRIBUTE_UNUSED;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
   if (pedantic)
     pedwarn ("ANSI C does not allow `#sccs'");
@@ -6932,9 +7239,9 @@ static int
 do_if (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
      FILE_BUF *op;
-     struct directive *keyword;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
-  HOST_WIDE_INT value;
+  HOST_WIDEST_INT value;
   FILE_BUF *ip = &instack[indepth];
 
   value = eval_if_expression (buf, limit - buf);
@@ -6949,9 +7256,9 @@ static int
 do_elif (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
      FILE_BUF *op;
-     struct directive *keyword;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
-  HOST_WIDE_INT value;
+  HOST_WIDEST_INT value;
   FILE_BUF *ip = &instack[indepth];
 
   if (if_stack == instack[indepth].if_stack) {
@@ -6961,9 +7268,13 @@ do_elif (buf, limit, op, keyword)
     if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
       error ("`#elif' after `#else'");
       fprintf (stderr, " (matches line %d", if_stack->lineno);
-      if (if_stack->fname != NULL && ip->fname != NULL
-         && strcmp (if_stack->fname, ip->nominal_fname) != 0)
-       fprintf (stderr, ", file %s", if_stack->fname);
+      if (! (if_stack->fname_len == ip->nominal_fname_len
+            && !bcmp (if_stack->fname, ip->nominal_fname,
+                      if_stack->fname_len))) {
+       fprintf (stderr, ", file ");
+       fwrite (if_stack->fname, sizeof if_stack->fname[0],
+               if_stack->fname_len, stderr);
+      }
       fprintf (stderr, ")\n");
     }
     if_stack->type = T_ELIF;
@@ -6986,14 +7297,14 @@ do_elif (buf, limit, op, keyword)
 /* Evaluate a #if expression in BUF, of length LENGTH, then parse the
    result as a C expression and return the value as an int.  */
 
-static HOST_WIDE_INT
+static HOST_WIDEST_INT
 eval_if_expression (buf, length)
      U_CHAR *buf;
      int length;
 {
   FILE_BUF temp_obuf;
   HASHNODE *save_defined;
-  HOST_WIDE_INT value;
+  HOST_WIDEST_INT value;
 
   save_defined = install ((U_CHAR *) "defined", -1, T_SPEC_DEFINED,
                          NULL_PTR, -1);
@@ -7002,7 +7313,7 @@ eval_if_expression (buf, length)
   pcp_inside_if = 0;
   delete_macro (save_defined); /* clean up special symbol */
 
-  temp_obuf.buf[temp_obuf.length] = '\n';
+  *temp_obuf.bufp = '\n';
   value = parse_c_expression ((char *) temp_obuf.buf,
                              warn_undef && !instack[indepth].system_header_p);
 
@@ -7071,7 +7382,7 @@ do_xifdef (buf, limit, op, keyword)
     HASHNODE *hp;
 
     if (! traditional) {
-      if (isdigit (buf[0]))
+      if (ISDIGIT (buf[0]))
        pedwarn ("`#%s' argument starts with a digit", keyword->name);
       else if (end != limit)
        pedwarn ("garbage at end of `#%s' argument", keyword->name);
@@ -7094,6 +7405,10 @@ do_xifdef (buf, limit, op, keyword)
       }
     }
 
+    if ((hp != NULL) && (hp->type == T_POISON)) {
+      error("attempt to use poisoned `%s'.", hp->name);
+      hp = NULL;
+    }
     skip = (hp == NULL) ^ (keyword->type == T_IFNDEF);
     if (start_of_file && !skip) {
       control_macro = (U_CHAR *) xmalloc (end - buf + 1);
@@ -7123,6 +7438,7 @@ conditional_skip (ip, skip, type, control_macro, op)
 
   temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
   temp->fname = ip->nominal_fname;
+  temp->fname_len = ip->nominal_fname_len;
   temp->lineno = ip->lineno;
   temp->next = if_stack;
   temp->control_macro = control_macro;
@@ -7159,6 +7475,7 @@ skip_if_group (ip, any, op)
   /* Save info about where the group starts.  */
   U_CHAR *beg_of_group = bp;
   int beg_lineno = ip->lineno;
+  int skipping_include_directive = 0;
 
   if (output_conditionals && op != 0) {
     char *ptr = "#failed\n";
@@ -7179,7 +7496,7 @@ skip_if_group (ip, any, op)
   while (bp < endb) {
     switch (*bp++) {
     case '/':                  /* possible comment */
-      if (*bp == '\\' && bp[1] == '\n')
+      if (*bp == '\\')
        newline_fix (bp);
       if (*bp == '*'
          || (cplusplus_comments && *bp == '/')) {
@@ -7187,22 +7504,49 @@ skip_if_group (ip, any, op)
        bp = skip_to_end_of_comment (ip, &ip->lineno, 0);
       }
       break;
+    case '<':
+      if (skipping_include_directive) {
+       while (bp < endb && *bp != '>' && *bp != '\n') {
+         if (*bp == '\\' && bp[1] == '\n') {
+           ip->lineno++;
+           bp++;
+         }
+         bp++;
+       }
+      }
+      break;
     case '\"':
+      if (skipping_include_directive) {
+       while (bp < endb && *bp != '\n') {
+         if (*bp == '"') {
+           bp++;
+           break;
+         }
+         if (*bp == '\\' && bp[1] == '\n') {
+           ip->lineno++;
+           bp++;
+         }
+         bp++;
+       }
+       break;
+      }
+      /* Fall through.  */
     case '\'':
       bp = skip_quoted_string (bp - 1, endb, ip->lineno, &ip->lineno,
                               NULL_PTR, NULL_PTR);
       break;
     case '\\':
-      /* Char after backslash loses its special meaning.  */
-      if (bp < endb) {
-       if (*bp == '\n')
-         ++ip->lineno;         /* But do update the line-count.  */
+      /* Char after backslash loses its special meaning in some cases.  */
+      if (*bp == '\n') {
+       ++ip->lineno;
+       bp++;
+      } else if (traditional && bp < endb)
        bp++;
-      }
       break;
     case '\n':
       ++ip->lineno;
       beg_of_line = bp;
+      skipping_include_directive = 0;
       break;
     case '%':
       if (beg_of_line == 0 || traditional)
@@ -7232,9 +7576,27 @@ skip_if_group (ip, any, op)
            bp += 2;
          else if (*bp == '/' && bp[1] == '*') {
            bp += 2;
-           while (!(*bp == '*' && bp[1] == '/'))
-             bp++;
-           bp += 2;
+           while (1)
+             {
+               if (*bp == '*')
+                 {
+                   if (bp[1] == '/')
+                     {
+                       bp += 2;
+                       break;
+                     }
+                 }
+               else
+                 {
+#ifdef MULTIBYTE_CHARS
+                   int length;
+                   length = local_mblen (bp, endb - bp);
+                   if (length > 1)
+                     bp += (length - 1);
+#endif
+                 }
+               bp++;
+             }
          }
          /* There is no point in trying to deal with C++ // comments here,
             because if there is one, then this # must be part of the
@@ -7264,6 +7626,8 @@ skip_if_group (ip, any, op)
        else if (*bp == '\\' && bp[1] == '\n')
          bp += 2;
        else if (*bp == '/') {
+         if (bp[1] == '\\')
+           newline_fix (bp + 1);
          if (bp[1] == '*') {
            for (bp += 2; ; bp++) {
              if (*bp == '\n')
@@ -7271,20 +7635,42 @@ skip_if_group (ip, any, op)
              else if (*bp == '*') {
                if (bp[-1] == '/' && warn_comments)
                  warning ("`/*' within comment");
+               if (bp[1] == '\\')
+                 newline_fix (bp + 1);
                if (bp[1] == '/')
                  break;
              }
+             else
+               {
+#ifdef MULTIBYTE_CHARS
+                 int length;
+                 length = local_mblen (bp, endb - bp);
+                 if (length > 1)
+                   bp += (length - 1);
+#endif
+               }
            }
            bp += 2;
          } else if (bp[1] == '/' && cplusplus_comments) {
            for (bp += 2; ; bp++) {
-             if (*bp == '\n') {
-               if (bp[-1] != '\\')
-                 break;
-               if (warn_comments)
-                 warning ("multiline `//' comment");
-               ip->lineno++;
-             }
+             if (*bp == '\n')
+               break;
+             if (*bp == '\\' && bp[1] == '\n')
+               {
+                 if (warn_comments)
+                   warning ("multiline `//' comment");
+                 ip->lineno++;
+                 bp++;
+               }
+             else
+               {
+#ifdef MULTIBYTE_CHARS
+                 int length;
+                 length = local_mblen (bp, endb - bp);
+                 if (length > 1)
+                   bp += (length - 1);
+#endif
+               }
            }
          } else
            break;
@@ -7302,7 +7688,7 @@ skip_if_group (ip, any, op)
        if (is_idchar[*bp])
          bp++;
        else {
-         if (*bp == '\\' && bp[1] == '\n')
+         if (*bp == '\\')
            name_newline_fix (bp);
          if (is_idchar[*bp])
            bp++;
@@ -7365,6 +7751,7 @@ skip_if_group (ip, any, op)
            if_stack = temp;
            temp->lineno = ip->lineno;
            temp->fname = ip->nominal_fname;
+           temp->fname_len = ip->nominal_fname_len;
            temp->type = kt->type;
            break;
          case T_ELSE:
@@ -7391,7 +7778,13 @@ skip_if_group (ip, any, op)
            free (temp);
            break;
 
-          default:
+         case T_INCLUDE:
+         case T_INCLUDE_NEXT:
+         case T_IMPORT:
+           skipping_include_directive = 1;
+           break;
+
+         default:
            break;
          }
          break;
@@ -7439,7 +7832,7 @@ static int
 do_else (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
      FILE_BUF *op;
-     struct directive *keyword;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
   FILE_BUF *ip = &instack[indepth];
 
@@ -7460,8 +7853,13 @@ do_else (buf, limit, op, keyword)
     if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
       error ("`#else' after `#else'");
       fprintf (stderr, " (matches line %d", if_stack->lineno);
-      if (strcmp (if_stack->fname, ip->nominal_fname) != 0)
-       fprintf (stderr, ", file %s", if_stack->fname);
+      if (! (if_stack->fname_len == ip->nominal_fname_len
+            && !bcmp (if_stack->fname, ip->nominal_fname,
+                      if_stack->fname_len))) {
+       fprintf (stderr, ", file ");
+       fwrite (if_stack->fname, sizeof if_stack->fname[0],
+               if_stack->fname_len, stderr);
+      }
       fprintf (stderr, ")\n");
     }
     if_stack->type = T_ELSE;
@@ -7482,7 +7880,7 @@ static int
 do_endif (buf, limit, op, keyword)
      U_CHAR *buf, *limit;
      FILE_BUF *op;
-     struct directive *keyword;
+     struct directive *keyword ATTRIBUTE_UNUSED;
 {
   if (pedantic) {
     SKIP_WHITE_SPACE (buf);
@@ -7569,6 +7967,15 @@ validate_else (p, limit)
              break;
            }
          }
+         else
+           {
+#ifdef MULTIBYTE_CHARS
+             int length;
+             length = local_mblen (p, limit - p);
+             if (length > 1)
+               p += (length - 1);
+#endif
+           }
        }
       }
       else if (cplusplus_comments && p[1] == '/')
@@ -7612,16 +8019,37 @@ skip_to_end_of_comment (ip, line_counter, nowarn)
   }
   if (cplusplus_comments && bp[-1] == '/') {
     for (; bp < limit; bp++) {
-      if (*bp == '\n') {
-       if (bp[-1] != '\\')
-         break;
-       if (!nowarn && warn_comments)
-         warning ("multiline `//' comment");
-       if (line_counter)
-         ++*line_counter;
-       if (op)
-         ++op->lineno;
-      }
+      if (*bp == '\n')
+       break;
+      if (*bp == '\\' && bp + 1 < limit && bp[1] == '\n')
+       {
+         if (!nowarn && warn_comments)
+           warning ("multiline `//' comment");
+         if (line_counter)
+           ++*line_counter;
+         if (op)
+           {
+             ++op->lineno;
+             *op->bufp++ = *bp;
+           }
+         ++bp;
+       }
+      else
+       {
+#ifdef MULTIBYTE_CHARS
+         int length;
+         length = local_mblen (bp, limit - bp);
+         if (length > 1)
+           {
+             if (op)
+               {
+                 bcopy (bp, op->bufp, length - 1);
+                 op->bufp += (length - 1);
+               }
+             bp += (length - 1);
+           }
+#endif
+       }
       if (op)
        *op->bufp++ = *bp;
     }
@@ -7650,7 +8078,7 @@ skip_to_end_of_comment (ip, line_counter, nowarn)
     case '*':
       if (bp[-2] == '/' && !nowarn && warn_comments)
        warning ("`/*' within comment");
-      if (*bp == '\\' && bp[1] == '\n')
+      if (*bp == '\\')
        newline_fix (bp);
       if (*bp == '/') {
         if (op)
@@ -7659,6 +8087,23 @@ skip_to_end_of_comment (ip, line_counter, nowarn)
        return bp;
       }
       break;
+#ifdef MULTIBYTE_CHARS
+    default:
+      {
+       int length;
+       bp--;
+       length = local_mblen (bp, limit - bp);
+       if (length <= 0)
+         length = 1;
+       if (op)
+         {
+           op->bufp--;
+           bcopy (bp, op->bufp, length);
+           op->bufp += length;
+         }
+       bp += length;
+      }
+#endif
     }
   }
 
@@ -7676,7 +8121,8 @@ skip_to_end_of_comment (ip, line_counter, nowarn)
    The input stack state is not changed.
 
    If COUNT_NEWLINES is nonzero, it points to an int to increment
-   for each newline passed.
+   for each newline passed; also, warn about any white space
+   just before line end.
 
    If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it
    if we pass a backslash-newline.
@@ -7715,10 +8161,11 @@ skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p,
          ++*count_newlines;
        bp += 2;
       }
-      if (*bp == '\n' && count_newlines) {
+      if (*bp == '\n') {
        if (backslash_newlines_p)
          *backslash_newlines_p = 1;
-       ++*count_newlines;
+       if (count_newlines)
+         ++*count_newlines;
       }
       bp++;
     } else if (c == '\n') {
@@ -7731,15 +8178,18 @@ skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p,
       }
       if (match == '\'') {
        error_with_line (line_for_error (start_line),
-                        "unterminated string or character constant");
+                        "unterminated character constant");
        bp--;
        if (eofp)
          *eofp = 1;
        break;
       }
       /* If not traditional, then allow newlines inside strings.  */
-      if (count_newlines)
+      if (count_newlines) {
+       if (warn_white_space && is_hor_space[bp[-2]])
+         warning ("white space at end of line in string");
        ++*count_newlines;
+      }
       if (multiline_string_line == 0) {
        if (pedantic)
          pedwarn_with_line (line_for_error (start_line),
@@ -7748,25 +8198,38 @@ skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p,
       }
     } else if (c == match)
       break;
+#ifdef MULTIBYTE_CHARS
+    {
+      int length;
+      --bp;
+      length = local_mblen (bp, limit - bp);
+      if (length <= 0)
+       length = 1;
+      bp += length;
+    }
+#endif
   }
   return bp;
 }
 
 /* Place into DST a quoted string representing the string SRC.
+   SRCLEN is the length of SRC; SRC may contain null bytes.
    Return the address of DST's terminating null.  */
 
 static char *
-quote_string (dst, src)
+quote_string (dst, src, srclen)
      char *dst, *src;
+     size_t srclen;
 {
   U_CHAR c;
+  char *srclim = src + srclen;
 
   *dst++ = '\"';
-  for (;;)
+  while (src != srclim)
     switch ((c = *src++))
       {
       default:
-        if (isprint (c))
+        if (ISPRINT (c))
          *dst++ = c;
        else
          {
@@ -7780,12 +8243,11 @@ quote_string (dst, src)
        *dst++ = '\\';
        *dst++ = c;
        break;
-      
-      case '\0':
-       *dst++ = '\"';
-       *dst = '\0';
-       return dst;
       }
+      
+  *dst++ = '\"';
+  *dst = '\0';
+  return dst;
 }
 
 /* Skip across a group of balanced parens, starting from IP->bufp.
@@ -7884,10 +8346,10 @@ output_line_directive (ip, op, conditional, file_change)
     ip->bufp++;
   }
 
-  line_directive_buf = (char *) alloca (4 * strlen (ip->nominal_fname) + 100);
+  line_directive_buf = (char *) alloca (4 * ip->nominal_fname_len + 100);
   sprintf (line_directive_buf, "# %d ", ip->lineno);
   line_end = quote_string (line_directive_buf + strlen (line_directive_buf),
-                          ip->nominal_fname);
+                          ip->nominal_fname, ip->nominal_fname_len);
   if (file_change != same_file) {
     *line_end++ = ' ';
     *line_end++ = file_change == enter_file ? '1' : '2';
@@ -7917,9 +8379,9 @@ output_line_directive (ip, op, conditional, file_change)
 /* This structure represents one parsed argument in a macro call.
    `raw' points to the argument text as written (`raw_length' is its length).
    `expanded' points to the argument's macro-expansion
-   (its length is `expand_length').
-   `stringified_length' is the length the argument would have
-   if stringified.
+   (its length is `expand_length', and its allocated size is `expand_size').
+   `stringified_length_bound' is an upper bound on the length
+   the argument would have if stringified.
    `use_count' is the number of times this macro arg is substituted
    into the macro.  If the actual use count exceeds 10, 
    the value stored is 10.
@@ -7928,8 +8390,8 @@ output_line_directive (ip, op, conditional, file_change)
 
 struct argdata {
   U_CHAR *raw, *expanded;
-  int raw_length, expand_length;
-  int stringified_length;
+  int raw_length, expand_length, expand_size;
+  int stringified_length_bound;
   U_CHAR *free1, *free2;
   char newlines;
   char use_count;
@@ -7973,15 +8435,15 @@ macroexpand (hp, op)
   if (nargs >= 0) {
     register int i;
     struct argdata *args;
-    char *parse_error = 0;
+    int parse_error = 0;
 
     args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
 
     for (i = 0; i < nargs; i++) {
       args[i].raw = (U_CHAR *) "";
       args[i].expanded = 0;
-      args[i].raw_length = args[i].expand_length
-       = args[i].stringified_length = 0;
+      args[i].raw_length = args[i].expand_length = args[i].expand_size
+       = args[i].stringified_length_bound = 0;
       args[i].free1 = args[i].free2 = 0;
       args[i].use_count = 0;
     }
@@ -8007,7 +8469,8 @@ macroexpand (hp, op)
       else
        parse_error = macarg (NULL_PTR, 0);
       if (parse_error) {
-       error_with_line (line_for_error (start_line), parse_error);
+       error_with_line (line_for_error (start_line),
+                        "unterminated macro call");
        break;
       }
       i++;
@@ -8074,7 +8537,7 @@ macroexpand (hp, op)
       xbuf_len = defn->length;
       for (ap = defn->pattern; ap != NULL; ap = ap->next) {
        if (ap->stringify)
-         xbuf_len += args[ap->argno].stringified_length;
+         xbuf_len += args[ap->argno].stringified_length_bound;
        else if (ap->raw_before != 0 || ap->raw_after != 0 || traditional)
          /* Add 4 for two newline-space markers to prevent
             token concatenation.  */
@@ -8089,13 +8552,20 @@ macroexpand (hp, op)
                                          1, 0);
 
            args[ap->argno].expanded = obuf.buf;
-           args[ap->argno].expand_length = obuf.length;
+           args[ap->argno].expand_length = obuf.bufp - obuf.buf;
+           args[ap->argno].expand_size = obuf.length;
            args[ap->argno].free2 = obuf.buf;
-         }
 
+           xbuf_len += args[ap->argno].expand_length;
+         } else {
+           /* If the arg appears more than once, its later occurrences
+              may have newline turned into backslash-'n', which is a
+              factor of 2 expansion.  */
+           xbuf_len += 2 * args[ap->argno].expand_length;
+         }
          /* Add 4 for two newline-space markers to prevent
             token concatenation.  */
-         xbuf_len += args[ap->argno].expand_length + 4;
+         xbuf_len += 4;
        }
        if (args[ap->argno].use_count < 10)
          args[ap->argno].use_count++;
@@ -8152,29 +8622,31 @@ macroexpand (hp, op)
          for (; i < arglen; i++) {
            c = arg->raw[i];
 
-           /* Special markers Newline Space
-              generate nothing for a stringified argument.  */
-           if (c == '\n' && arg->raw[i+1] != '\n') {
-             i++;
-             continue;
-           }
-
-           /* Internal sequences of whitespace are replaced by one space
-              except within an string or char token.  */
-           if (! in_string
-               && (c == '\n' ? arg->raw[i+1] == '\n' : is_space[c])) {
-             while (1) {
-               /* Note that Newline Space does occur within whitespace
-                  sequences; consider it part of the sequence.  */
-               if (c == '\n' && is_space[arg->raw[i+1]])
-                 i += 2;
-               else if (c != '\n' && is_space[c])
-                 i++;
-               else break;
-               c = arg->raw[i];
-             }
-             i--;
-             c = ' ';
+           if (in_string) {
+             /* Generate nothing for backslash-newline in a string.  */
+             if (c == '\\' && arg->raw[i + 1] == '\n') {
+               i++;
+               continue;
+             }
+           } else {
+             /* Special markers
+                generate nothing for a stringified argument.  */
+             if (c == '\n') {
+               i++;
+               continue;
+             }
+
+             /* Internal sequences of whitespace are replaced by one space
+                except within a string or char token.  */
+             if (is_space[c]) {
+               i++;
+               while (is_space[(c = arg->raw[i])])
+                 /* Newline markers can occur within a whitespace sequence;
+                    consider them part of the sequence.  */
+                 i += (c == '\n') + 1;
+               i--;
+               c = ' ';
+             }
            }
 
            if (escaped)
@@ -8182,22 +8654,41 @@ macroexpand (hp, op)
            else {
              if (c == '\\')
                escaped = 1;
-             if (in_string) {
+             else if (in_string) {
                if (c == in_string)
                  in_string = 0;
+               else
+                 {
+#ifdef MULTIBYTE_CHARS
+                   int length;
+                   length = local_mblen (arg->raw + i, arglen - i);
+                   if (length > 1)
+                     {
+                       bcopy (arg->raw + i, xbuf + totlen, length);
+                       i += length - 1;
+                       totlen += length;
+                       continue;
+                     }
+#endif
+                 }
              } else if (c == '\"' || c == '\'')
                in_string = c;
            }
 
-           /* Escape these chars */
-           if (c == '\"' || (in_string && c == '\\'))
+           /* Escape double-quote, and backslashes in strings.
+              Newlines in strings are best escaped as \n, since
+              otherwise backslash-backslash-newline-newline is
+              mishandled.  The C Standard doesn't allow newlines in
+              strings, so we can escape newlines as we please.  */
+           if (c == '\"'
+               || (in_string
+                   && (c == '\\'
+                       || (c == '\n' ? (c = 'n', 1) : 0))))
              xbuf[totlen++] = '\\';
-           if (isprint (c))
-             xbuf[totlen++] = c;
-           else {
-             sprintf ((char *) &xbuf[totlen], "\\%03o", (unsigned int) c);
-             totlen += 4;
-           }
+           /* We used to output e.g. \008 for control characters here,
+              but this doesn't conform to the C Standard.
+              Just output the characters as-is.  */
+           xbuf[totlen++] = c;
          }
          if (!traditional)
            xbuf[totlen++] = '\"'; /* insert ending quote */
@@ -8268,8 +8759,7 @@ macroexpand (hp, op)
            /* Don't bother doing change_newlines for subsequent
               uses of arg.  */
            arg->use_count = 1;
-           arg->expand_length
-             = change_newlines (arg->expanded, arg->expand_length);
+           change_newlines (arg);
          }
        }
 
@@ -8313,6 +8803,7 @@ macroexpand (hp, op)
 
     ip2->fname = 0;
     ip2->nominal_fname = 0;
+    ip2->nominal_fname_len = 0;
     ip2->inc = 0;
     /* This may not be exactly correct, but will give much better error
        messages for nested macro calls than using a line number of zero.  */
@@ -8338,30 +8829,30 @@ macroexpand (hp, op)
    REST_ARGS is passed to macarg1 to make it absorb the rest of the args.
    Return nonzero to indicate a syntax error.  */
 
-static char *
+static int
 macarg (argptr, rest_args)
      register struct argdata *argptr;
      int rest_args;
 {
   FILE_BUF *ip = &instack[indepth];
   int paren = 0;
-  int newlines = 0;
+  int lineno0 = ip->lineno;
   int comments = 0;
-  char *result = 0;
+  int result = 0;
 
   /* Try to parse as much of the argument as exists at this
      input stack level.  */
-  U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length,
-                       &paren, &newlines, &comments, rest_args);
+  U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro,
+                       &paren, &ip->lineno, &comments, rest_args);
 
   /* If we find the end of the argument at this level,
      set up *ARGPTR to point at it in the input stack.  */
-  if (!(ip->fname != 0 && (newlines != 0 || comments != 0))
+  if (!(ip->fname != 0 && (ip->lineno != lineno0 || comments != 0))
       && bp != ip->buf + ip->length) {
     if (argptr != 0) {
       argptr->raw = ip->bufp;
       argptr->raw_length = bp - ip->bufp;
-      argptr->newlines = newlines;
+      argptr->newlines = ip->lineno - lineno0;
     }
     ip->bufp = bp;
   } else {
@@ -8370,35 +8861,33 @@ macarg (argptr, rest_args)
        Therefore, we must allocate a temporary buffer and copy
        the macro argument into it.  */
     int bufsize = bp - ip->bufp;
-    int extra = newlines;
+    int extra = ip->lineno - lineno0;
     U_CHAR *buffer = (U_CHAR *) xmalloc (bufsize + extra + 1);
     int final_start = 0;
 
     bcopy ((char *) ip->bufp, (char *) buffer, bufsize);
     ip->bufp = bp;
-    ip->lineno += newlines;
 
     while (bp == ip->buf + ip->length) {
       if (instack[indepth].macro == 0) {
-       result = "unterminated macro call";
+       result = 1;
        break;
       }
       ip->macro->type = T_MACRO;
       if (ip->free_ptr)
        free (ip->free_ptr);
       ip = &instack[--indepth];
-      newlines = 0;
+      lineno0 = ip->lineno;
       comments = 0;
-      bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
-                   &newlines, &comments, rest_args);
+      bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro, &paren,
+                   &ip->lineno, &comments, rest_args);
       final_start = bufsize;
       bufsize += bp - ip->bufp;
-      extra += newlines;
+      extra += ip->lineno - lineno0;
       buffer = (U_CHAR *) xrealloc (buffer, bufsize + extra + 1);
       bcopy ((char *) ip->bufp, (char *) (buffer + bufsize - (bp - ip->bufp)),
             bp - ip->bufp);
       ip->bufp = bp;
-      ip->lineno += newlines;
     }
 
     /* Now, if arg is actually wanted, record its raw form,
@@ -8410,13 +8899,13 @@ macarg (argptr, rest_args)
       argptr->raw = buffer;
       argptr->raw_length = bufsize;
       argptr->free1 = buffer;
-      argptr->newlines = newlines;
-      if ((newlines || comments) && ip->fname != 0)
+      argptr->newlines = ip->lineno - lineno0;
+      if ((argptr->newlines || comments) && ip->fname != 0)
        argptr->raw_length
          = final_start +
            discard_comments (argptr->raw + final_start,
                              argptr->raw_length - final_start,
-                             newlines);
+                             argptr->newlines);
       argptr->raw[argptr->raw_length] = 0;
       if (argptr->raw_length > bufsize + extra)
        abort ();
@@ -8450,17 +8939,16 @@ macarg (argptr, rest_args)
        SKIP_ALL_WHITE_SPACE (buf);
       else
 #endif
-      if (c == '\"' || c == '\\') /* escape these chars */
+      if (c == '\"' || c == '\\' || c == '\n') /* escape these chars */
        totlen++;
-      else if (!isprint (c))
-       totlen += 3;
     }
-    argptr->stringified_length = totlen;
+    argptr->stringified_length_bound = totlen;
   }
   return result;
 }
 \f
 /* Scan text from START (inclusive) up to LIMIT (exclusive),
+   taken from the expansion of MACRO,
    counting parens in *DEPTHPTR,
    and return if reach LIMIT
    or before a `)' that would make *DEPTHPTR negative
@@ -8474,9 +8962,10 @@ macarg (argptr, rest_args)
    Set *COMMENTS to 1 if a comment is seen.  */
 
 static U_CHAR *
-macarg1 (start, limit, depthptr, newlines, comments, rest_args)
+macarg1 (start, limit, macro, depthptr, newlines, comments, rest_args)
      U_CHAR *start;
      register U_CHAR *limit;
+     struct hashnode *macro;
      int *depthptr, *newlines, *comments;
      int rest_args;
 {
@@ -8493,19 +8982,16 @@ macarg1 (start, limit, depthptr, newlines, comments, rest_args)
       break;
     case '\\':
       /* Traditionally, backslash makes following char not special.  */
-      if (bp + 1 < limit && traditional)
-       {
-         bp++;
-         /* But count source lines anyway.  */
-         if (*bp == '\n')
-           ++*newlines;
-       }
+      if (traditional && bp + 1 < limit && bp[1] != '\n')
+       bp++;
       break;
     case '\n':
       ++*newlines;
       break;
     case '/':
-      if (bp[1] == '\\' && bp[2] == '\n')
+      if (macro)
+       break;
+      if (bp[1] == '\\')
        newline_fix (bp + 1);
       if (bp[1] == '*') {
        *comments = 1;
@@ -8515,24 +9001,46 @@ macarg1 (start, limit, depthptr, newlines, comments, rest_args)
          else if (*bp == '*') {
            if (bp[-1] == '/' && warn_comments)
              warning ("`/*' within comment");
-           if (bp[1] == '\\' && bp[2] == '\n')
+           if (bp[1] == '\\')
              newline_fix (bp + 1);
            if (bp[1] == '/') {
              bp++;
              break;
            }
          }
+         else
+           {
+#ifdef MULTIBYTE_CHARS
+             int length;
+             length = local_mblen (bp, limit - bp);
+             if (length > 1)
+               bp += (length - 1);
+#endif
+           }
        }
       } else if (bp[1] == '/' && cplusplus_comments) {
        *comments = 1;
        for (bp += 2; bp < limit; bp++) {
          if (*bp == '\n') {
            ++*newlines;
-           if (bp[-1] != '\\')
-             break;
-           if (warn_comments)
-             warning ("multiline `//' comment");
+           break;
          }
+         if (*bp == '\\' && bp + 1 < limit && bp[1] == '\n')
+           {
+             ++*newlines;
+             if (warn_comments)
+               warning ("multiline `//' comment");
+             ++bp;
+           }
+         else
+           {
+#ifdef MULTIBYTE_CHARS
+             int length;
+             length = local_mblen (bp, limit - bp);
+             if (length > 1)
+               bp += (length - 1);
+#endif
+           }
        }
       }
       break;
@@ -8540,19 +9048,31 @@ macarg1 (start, limit, depthptr, newlines, comments, rest_args)
     case '\"':
       {
        int quotec;
-       for (quotec = *bp++; bp + 1 < limit && *bp != quotec; bp++) {
+       for (quotec = *bp++; bp < limit && *bp != quotec; bp++) {
          if (*bp == '\\') {
            bp++;
            if (*bp == '\n')
              ++*newlines;
            while (*bp == '\\' && bp[1] == '\n') {
              bp += 2;
+             ++*newlines;
            }
          } else if (*bp == '\n') {
+           if (warn_white_space && is_hor_space[bp[-1]] && ! macro)
+             warning ("white space at end of line in string");
            ++*newlines;
            if (quotec == '\'')
              break;
          }
+         else
+           {
+#ifdef MULTIBYTE_CHARS
+             int length;
+             length = local_mblen (bp, limit - bp);
+             if (length > 1)
+               bp += (length - 1);
+#endif
+           }
        }
       }
       break;
@@ -8623,15 +9143,29 @@ discard_comments (start, length, newlines)
       break;
 
     case '/':
-      if (*ibp == '\\' && ibp[1] == '\n')
+      if (*ibp == '\\')
        newline_fix (ibp);
       /* Delete any comment.  */
       if (cplusplus_comments && ibp[0] == '/') {
        /* Comments are equivalent to spaces.  */
        obp[-1] = ' ';
        ibp++;
-       while (ibp < limit && (*ibp != '\n' || ibp[-1] == '\\'))
-         ibp++;
+       while (ibp < limit)
+         {
+           if (*ibp == '\n')
+             break;
+           if (*ibp == '\\' && ibp + 1 < limit && ibp[1] == '\n')
+             ibp++;
+           else
+             {
+#ifdef MULTIBYTE_CHARS
+               int length = local_mblen (ibp, limit - ibp);
+               if (length > 1)
+                 ibp += (length - 1);
+#endif
+             }
+           ibp++;
+         }
        break;
       }
       if (ibp[0] != '*' || ibp + 1 >= limit)
@@ -8642,16 +9176,24 @@ discard_comments (start, length, newlines)
        obp--;
       else
        obp[-1] = ' ';
-      ibp++;
-      while (ibp + 1 < limit) {
-       if (ibp[0] == '*'
-           && ibp[1] == '\\' && ibp[2] == '\n')
-         newline_fix (ibp + 1);
-       if (ibp[0] == '*' && ibp[1] == '/')
-         break;
-       ibp++;
+      while (++ibp < limit) {
+       if (ibp[0] == '*') {
+         if (ibp[1] == '\\')
+           newline_fix (ibp + 1);
+         if (ibp[1] == '/') {
+           ibp += 2;
+           break;
+         }
+       }
+       else
+         {
+#ifdef MULTIBYTE_CHARS
+           int length = local_mblen (ibp, limit - ibp);
+           if (length > 1)
+             ibp += (length - 1);
+#endif
+         }
       }
-      ibp += 2;
       break;
 
     case '\'':
@@ -8665,13 +9207,39 @@ discard_comments (start, length, newlines)
          *obp++ = c = *ibp++;
          if (c == quotec)
            break;
-         if (c == '\n' && quotec == '\'')
-           break;
-         if (c == '\\' && ibp < limit) {
-           while (*ibp == '\\' && ibp[1] == '\n')
-             ibp += 2;
-           *obp++ = *ibp++;
+         if (c == '\n')
+           {
+             if (quotec == '\'')
+               break;
+           }
+         else if (c == '\\') {
+           if (ibp < limit && *ibp == '\n') {
+             ibp++;
+             obp--;
+           } else {
+             while (*ibp == '\\' && ibp[1] == '\n')
+               ibp += 2;
+             if (ibp < limit)
+               *obp++ = *ibp++;
+           }
          }
+         else
+           {
+#ifdef MULTIBYTE_CHARS
+             int length;
+             ibp--;
+             length = local_mblen (ibp, limit - ibp);
+             if (length > 1)
+               {
+                 obp--;
+                 bcopy (ibp, obp, length);
+                 ibp += length;
+                 obp += length;
+               }
+             else
+               ibp++;
+#endif
+           }
        }
       }
       break;
@@ -8681,15 +9249,16 @@ discard_comments (start, length, newlines)
   return obp - start;
 }
 \f
-/* Turn newlines to spaces in the string of length LENGTH at START,
-   except inside of string constants.
-   The string is copied into itself with its beginning staying fixed.  */
+/* Turn newlines to spaces in the macro argument ARG.
+   Remove backslash-newline from string constants,
+   and turn other newlines in string constants to backslash-'n'.  */
 
-static int
-change_newlines (start, length)
-     U_CHAR *start;
-     int length;
+static void
+change_newlines (arg)
+     struct argdata *arg;
 {
+  U_CHAR *start = arg->expanded;
+  int length = arg->expand_length;
   register U_CHAR *ibp;
   register U_CHAR *obp;
   register U_CHAR *limit;
@@ -8723,65 +9292,93 @@ change_newlines (start, length)
          *obp++ = c = *ibp++;
          if (c == quotec)
            break;
-         if (c == '\n' && quotec == '\'')
-           break;
+         else if (c == '\\' && ibp < limit && *ibp == '\n')
+           *obp++ = *ibp++;
+         else if (c == '\n')
+           {
+             if (quotec == '\'')
+               break;
+           }
+         else
+           {
+#ifdef MULTIBYTE_CHARS
+             int length;
+             ibp--;
+             length = local_mblen (ibp, limit - ibp);
+             if (length > 1)
+               {
+                 obp--;
+                 bcopy (ibp, obp, length);
+                 ibp += length;
+                 obp += length;
+               }
+             else
+               ibp++;
+#endif
+           }
        }
       }
       break;
     }
   }
 
-  return obp - start;
+  arg->expand_length = obp - arg->expanded;
+
+  if (start != arg->expanded)
+    free (start);
 }
 \f
-/* my_strerror - return the descriptive text associated with an
-   `errno' code.  */
+/* notice - output message to stderr */
 
-char *
-my_strerror (errnum)
-     int errnum;
+static void
+notice VPROTO ((const char * msgid, ...))
 {
-  char *result;
-
-#ifndef VMS
-#ifndef HAVE_STRERROR
-  result = (char *) ((errnum < sys_nerr) ? sys_errlist[errnum] : 0);
-#else
-  result = strerror (errnum);
-#endif
-#else  /* VMS */
-  /* VAXCRTL's strerror() takes an optional second argument, which only
-     matters when the first argument is EVMSERR.  However, it's simplest
-     just to pass it unconditionally.  `vaxc$errno' is declared in
-     <errno.h>, and maintained by the library in parallel with `errno'.
-     We assume that caller's `errnum' either matches the last setting of
-     `errno' by the library or else does not have the value `EVMSERR'.  */
-
-  result = strerror (errnum, vaxc$errno);
+#ifndef ANSI_PROTOTYPES
+  const char * msgid;
 #endif
+  va_list args;
 
-  if (!result)
-    result = "undocumented I/O error";
+  VA_START (args, msgid);
 
-  return result;
+#ifndef ANSI_PROTOTYPES
+  msgid = va_arg (args, const char *);
+#endif
+  vnotice (msgid, args);
+  va_end (args);
+}
+
+static void
+vnotice (msgid, args)
+     const char *msgid;
+     va_list args;
+{
+  vfprintf (stderr, _(msgid), args);
 }
 
 /* error - print error message and increment count of errors.  */
 
 void
-error (PRINTF_ALIST (msg))
-     PRINTF_DCL (msg)
+error VPROTO ((const char * msgid, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  const char * msgid;
+#endif
   va_list args;
 
-  VA_START (args, msg);
-  verror (msg, args);
+  VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+  msgid = va_arg (args, const char *);
+#endif
+  verror (msgid, args);
   va_end (args);
 }
 
-static void
-verror (msg, args)
-     char *msg;
+void
+verror (msgid, args)
+     const char *msgid;
      va_list args;
 {
   int i;
@@ -8795,9 +9392,12 @@ verror (msg, args)
       break;
     }
 
-  if (ip != NULL)
-    fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
-  vfprintf (stderr, msg, args);
+  if (ip != NULL) {
+    fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+           ip->nominal_fname_len, stderr);
+    fprintf (stderr, ":%d: ", ip->lineno);
+  }
+  vnotice (msgid, args);
   fprintf (stderr, "\n");
   errors++;
 }
@@ -8808,6 +9408,7 @@ static void
 error_from_errno (name)
      char *name;
 {
+  int e = errno;
   int i;
   FILE_BUF *ip = NULL;
 
@@ -8819,10 +9420,13 @@ error_from_errno (name)
       break;
     }
 
-  if (ip != NULL)
-    fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
+  if (ip != NULL) {
+    fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+           ip->nominal_fname_len, stderr);
+    fprintf (stderr, ":%d: ", ip->lineno);
+  }
 
-  fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
+  fprintf (stderr, "%s: %s\n", name, xstrerror (e));
 
   errors++;
 }
@@ -8830,19 +9434,26 @@ error_from_errno (name)
 /* Print error message but don't count it.  */
 
 void
-warning (PRINTF_ALIST (msg))
-     PRINTF_DCL (msg)
+warning VPROTO ((const char * msgid, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  const char * msgid;
+#endif
   va_list args;
 
-  VA_START (args, msg);
-  vwarning (msg, args);
+  VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+  msgid = va_arg (args, const char *);
+#endif
+
+  vwarning (msgid, args);
   va_end (args);
 }
 
 static void
-vwarning (msg, args)
-     char *msg;
+vwarning (msgid, args)
+     const char *msgid;
      va_list args;
 {
   int i;
@@ -8862,33 +9473,41 @@ vwarning (msg, args)
       break;
     }
 
-  if (ip != NULL)
-    fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
-  fprintf (stderr, "warning: ");
-  vfprintf (stderr, msg, args);
+  if (ip != NULL) {
+    fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+           ip->nominal_fname_len, stderr);
+    fprintf (stderr, ":%d: ", ip->lineno);
+  }
+  notice ("warning: ");
+  vnotice (msgid, args);
   fprintf (stderr, "\n");
 }
 
 static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-error_with_line (int line, PRINTF_ALIST (msg))
-#else
-error_with_line (line, PRINTF_ALIST (msg))
-     int line;
-     PRINTF_DCL (msg)
-#endif
+error_with_line VPROTO ((int line, const char * msgid, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  int line;
+  const char * msgid;
+#endif
   va_list args;
 
-  VA_START (args, msg);
-  verror_with_line (line, msg, args);
+  VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+  line = va_arg (args, int);
+  msgid = va_arg (args, const char *);
+#endif
+
+  verror_with_line (line, msgid, args);
   va_end (args);
 }
 
+
 static void
-verror_with_line (line, msg, args)
+verror_with_line (line, msgid, args)
      int line;
-     char *msg;
+     const char *msgid;
      va_list args;
 {
   int i;
@@ -8902,33 +9521,40 @@ verror_with_line (line, msg, args)
       break;
     }
 
-  if (ip != NULL)
-    fprintf (stderr, "%s:%d: ", ip->nominal_fname, line);
-  vfprintf (stderr, msg, args);
+  if (ip != NULL) {
+    fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+           ip->nominal_fname_len, stderr);
+    fprintf (stderr, ":%d: ", line);
+  }
+  vnotice (msgid, args);
   fprintf (stderr, "\n");
   errors++;
 }
 
 static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-warning_with_line (int line, PRINTF_ALIST (msg))
-#else
-warning_with_line (line, PRINTF_ALIST (msg))
-     int line;
-     PRINTF_DCL (msg)
-#endif
+warning_with_line VPROTO ((int line, const char * msgid, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  int line;
+  const char * msgid;
+#endif
   va_list args;
 
-  VA_START (args, msg);
-  vwarning_with_line (line, msg, args);
+  VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+  line = va_arg (args, int);
+  msgid = va_arg (args, const char *);
+#endif
+
+  vwarning_with_line (line, msgid, args);
   va_end (args);
 }
 
 static void
-vwarning_with_line (line, msg, args)
+vwarning_with_line (line, msgid, args)
      int line;
-     char *msg;
+     const char *msgid;
      va_list args;
 {
   int i;
@@ -8948,45 +9574,59 @@ vwarning_with_line (line, msg, args)
       break;
     }
 
-  if (ip != NULL)
-    fprintf (stderr, line ? "%s:%d: " : "%s: ", ip->nominal_fname, line);
-  fprintf (stderr, "warning: ");
-  vfprintf (stderr, msg, args);
+  if (ip != NULL) {
+    fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+           ip->nominal_fname_len, stderr);
+    fprintf (stderr, line ? ":%d: " : ": ", line);
+  }
+  notice ("warning: ");
+  vnotice (msgid, args);
   fprintf (stderr, "\n");
 }
 
 /* Print an error message and maybe count it.  */
 
 void
-pedwarn (PRINTF_ALIST (msg))
-     PRINTF_DCL (msg)
+pedwarn VPROTO ((const char * msgid, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  const char * msgid;
+#endif
   va_list args;
 
-  VA_START (args, msg);
+  VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+  msgid = va_arg (args, const char *);
+#endif
+
   if (pedantic_errors)
-    verror (msg, args);
+    verror (msgid, args);
   else
-    vwarning (msg, args);
+    vwarning (msgid, args);
   va_end (args);
 }
 
 void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-pedwarn_with_line (int line, PRINTF_ALIST (msg))
-#else
-pedwarn_with_line (line, PRINTF_ALIST (msg))
-     int line;
-     PRINTF_DCL (msg)
-#endif
+pedwarn_with_line VPROTO ((int line, const char * msgid, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  int line;
+  const char * msgid;
+#endif
   va_list args;
 
-  VA_START (args, msg);
+  VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+  line = va_arg (args, int);
+  msgid = va_arg (args, const char *);
+#endif
+
   if (pedantic_errors)
-    verror_with_line (line, msg, args);
+    verror_with_line (line, msgid, args);
   else
-    vwarning_with_line (line, msg, args);
+    vwarning_with_line (line, msgid, args);
   va_end (args);
 }
 
@@ -8994,30 +9634,54 @@ pedwarn_with_line (line, PRINTF_ALIST (msg))
    giving specified file name and line number, not current.  */
 
 static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-pedwarn_with_file_and_line (char *file, int line, PRINTF_ALIST (msg))
-#else
-pedwarn_with_file_and_line (file, line, PRINTF_ALIST (msg))
-     char *file;
-     int line;
-     PRINTF_DCL (msg)
-#endif
+pedwarn_with_file_and_line VPROTO ((const char *file, size_t file_len, int line,
+                                   const char * msgid, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  const char *file;
+  size_t file_len;
+  int line;
+  const char * msgid;
+#endif
   va_list args;
 
   if (!pedantic_errors && inhibit_warnings)
     return;
-  if (file != NULL)
-    fprintf (stderr, "%s:%d: ", file, line);
+
+  VA_START (args, msgid);
+#ifndef ANSI_PROTOTYPES
+  file = va_arg (args, const char *);
+  file_len = va_arg (args, size_t);
+  line = va_arg (args, int);
+  msgid = va_arg (args, const char *);
+#endif
+  if (file) {
+    fwrite (file, sizeof file[0], file_len, stderr);
+    fprintf (stderr, ":%d: ", line);
+  }
   if (pedantic_errors)
     errors++;
   if (!pedantic_errors)
-    fprintf (stderr, "warning: ");
-  VA_START (args, msg);
-  vfprintf (stderr, msg, args);
+    notice ("warning: ");
+  vnotice (msgid, args);
   va_end (args);
   fprintf (stderr, "\n");
 }
+
+static void
+pedwarn_strange_white_space (ch)
+     int ch;
+{
+  switch (ch)
+    {
+    case '\f': pedwarn ("formfeed in preprocessing directive"); break;
+    case '\r': pedwarn ("carriage return in preprocessing directive"); break;
+    case '\v': pedwarn ("vertical tab in preprocessing directive"); break;
+    default: abort ();
+    }
+}
 \f
 /* Print the file names and line numbers of the #include
    directives which led to the current file.  */
@@ -9050,12 +9714,14 @@ print_containing_files ()
       ip = &instack[i];
       if (first) {
        first = 0;
-       fprintf (stderr, "In file included");
+       notice (   "In file included from ");
       } else {
-       fprintf (stderr, ",\n                ");
+       notice (",\n                 from ");
       }
 
-      fprintf (stderr, " from %s:%d", ip->nominal_fname, ip->lineno);
+      fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+             ip->nominal_fname_len, stderr);
+      fprintf (stderr, ":%d", ip->lineno);
     }
   if (! first)
     fprintf (stderr, ":\n");
@@ -9122,8 +9788,7 @@ grow_outbuf (obuf, needed)
   if (minsize > obuf->length)
     obuf->length = minsize;
 
-  if ((p = (U_CHAR *) xrealloc (obuf->buf, obuf->length)) == NULL)
-    memory_full ();
+  p = (U_CHAR *) xrealloc (obuf->buf, obuf->length);
 
   obuf->bufp = p + (obuf->bufp - obuf->buf);
   obuf->buf = p;
@@ -9192,7 +9857,7 @@ install (name, len, type, value, hash)
 }
 
 /*
- * find the most recent hash node for name name (ending with first
+ * find the most recent hash node for name "name" (ending with first
  * non-identifier char) installed by install
  *
  * If LEN is >= 0, it is the length of the name.
@@ -9466,9 +10131,9 @@ initialize_char_syntax ()
    * refer to them.
    */
   for (i = 'a'; i <= 'z'; i++) {
-    is_idchar[i - 'a' + 'A'] = 1;
+    is_idchar[TOUPPER(i)] = 1;
     is_idchar[i] = 1;
-    is_idstart[i - 'a' + 'A'] = 1;
+    is_idstart[TOUPPER(i)] = 1;
     is_idstart[i] = 1;
   }
   for (i = '0'; i <= '9'; i++)
@@ -9491,10 +10156,6 @@ initialize_char_syntax ()
   is_space['\f'] = 1;
   is_space['\n'] = 1;
   is_space['\r'] = 1;
-
-  char_name['\v'] = "vertical tab";
-  char_name['\f'] = "formfeed";
-  char_name['\r'] = "carriage return";
 }
 
 /* Initialize the built-in macros.  */
@@ -9528,8 +10189,6 @@ initialize_builtins (inp, outp)
     install ((U_CHAR *) "__STDC__", -1, T_CONST, "1", -1);
     install ((U_CHAR *) "__STDC_VERSION__", -1, T_CONST, "199409L", -1);
   }
-  if (objc)
-    install ((U_CHAR *) "__OBJC__", -1, T_CONST, "1", -1);
 /*  This is supplied using a -D by the compiler driver
     so that it is present only when truly compiling with GNU C.  */
 /*  install ((U_CHAR *) "__GNUC__", -1, T_CONST, "2", -1);  */
@@ -9610,9 +10269,8 @@ initialize_builtins (inp, outp)
  */
 
 static void
-make_definition (str, op)
+make_definition (str)
      char *str;
-     FILE_BUF *op;
 {
   FILE_BUF *ip;
   struct directive *kt;
@@ -9655,11 +10313,18 @@ make_definition (str, op)
                                         NULL_PTR, NULL_PTR, &unterminated);
        if (unterminated)
          return;
-       while (p != p1)
+       while (p != p1) {
          if (*p == '\\' && p[1] == '\n')
            p += 2;
+         else if (*p == '\n')
+           {
+             *q++ = '\\';
+             *q++ = 'n';
+             p++;
+           }
          else
            *q++ = *p++;
+       }
       } else if (*p == '\\' && p[1] == '\n')
        p += 2;
       /* Change newline chars into newline-markers.  */
@@ -9677,6 +10342,7 @@ make_definition (str, op)
   
   ip = &instack[++indepth];
   ip->nominal_fname = ip->fname = "*Initialization*";
+  ip->nominal_fname_len = strlen (ip->nominal_fname);
 
   ip->buf = ip->bufp = buf;
   ip->length = strlen ((char *) buf);
@@ -9706,6 +10372,7 @@ make_undef (str, op)
 
   ip = &instack[++indepth];
   ip->nominal_fname = ip->fname = "*undef*";
+  ip->nominal_fname_len = strlen (ip->nominal_fname);
 
   ip->buf = ip->bufp = (U_CHAR *) str;
   ip->length = strlen (str);
@@ -9727,8 +10394,8 @@ make_undef (str, op)
 
 static void
 make_assertion (option, str)
-     char *option;
-     char *str;
+     const char *option;
+     const char *str;
 {
   FILE_BUF *ip;
   struct directive *kt;
@@ -9762,6 +10429,7 @@ make_assertion (option, str)
   
   ip = &instack[++indepth];
   ip->nominal_fname = ip->fname = "*Initialization*";
+  ip->nominal_fname_len = strlen (ip->nominal_fname);
 
   ip->buf = ip->bufp = buf;
   ip->length = strlen ((char *) buf);
@@ -9780,10 +10448,6 @@ make_assertion (option, str)
   --indepth;
 }
 \f
-#ifndef DIR_SEPARATOR
-#define DIR_SEPARATOR '/'
-#endif
-
 /* The previous include prefix, if any, is PREV_FILE_NAME.
    Translate any pathnames with COMPONENT.
    Allocate a new include prefix whose name is the
@@ -9795,9 +10459,9 @@ make_assertion (option, str)
 static struct file_name_list *
 new_include_prefix (prev_file_name, component, prefix, name)
      struct file_name_list *prev_file_name;
-     char *component;
-     char *prefix;
-     char *name;
+     const char *component;
+     const char *prefix;
+     const char *name;
 {
   if (name == 0)
     fatal ("Directory name missing after command line option");
@@ -9824,7 +10488,12 @@ new_include_prefix (prev_file_name, component, prefix, name)
       if (len == 1 && dir->fname[len - 1] == '.')
        len = 0;
       else
+#ifdef VMS
+       /* must be '/', hack_vms_include_specification triggers on it.  */
+       dir->fname[len++] = '/';
+#else
        dir->fname[len++] = DIR_SEPARATOR;
+#endif
       dir->fname[len] = 0;
     }
 
@@ -9917,9 +10586,9 @@ append_include_chain (first, last)
 static int
 quote_string_for_make (dst, src)
      char *dst;
-     char *src;
+     const char *src;
 {
-  char *p = src;
+  const char *p = src;
   int i = 0;
   for (;;)
     {
@@ -9936,7 +10605,7 @@ quote_string_for_make (dst, src)
               preceded by 2N backslashes represents N backslashes at
               the end of a file name; and backslashes in other
               contexts should not be doubled.  */
-           char *q;
+           const char *q;
            for (q = p - 1; src < q && q[-1] == '\\';  q--)
              {
                if (dst)
@@ -9979,7 +10648,7 @@ quote_string_for_make (dst, src)
 
 static void
 deps_output (string, spacer)
-     char *string;
+     const char *string;
      int spacer;
 {
   int size = quote_string_for_make ((char *) 0, string);
@@ -10017,15 +10686,21 @@ deps_output (string, spacer)
   deps_buffer[deps_size] = 0;
 }
 \f
-static void
-fatal (PRINTF_ALIST (msg))
-     PRINTF_DCL (msg)
+void
+fatal VPROTO ((const char * msgid, ...))
 {
+#ifndef ANSI_PROTOTYPES
+  const char * msgid;
+#endif
   va_list args;
 
   fprintf (stderr, "%s: ", progname);
-  VA_START (args, msg);
-  vfprintf (stderr, msg, args);
+  VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+  msgid = va_arg (args, const char *);
+#endif
+  vnotice (msgid, args);
   va_end (args);
   fprintf (stderr, "\n");
   exit (FATAL_EXIT_CODE);
@@ -10044,8 +10719,7 @@ static void
 perror_with_name (name)
      char *name;
 {
-  fprintf (stderr, "%s: ", progname);
-  fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
+  fprintf (stderr, "%s: %s: %s\n", progname, name, xstrerror (errno));
   errors++;
 }
 
@@ -10066,7 +10740,7 @@ pfatal_with_name (name)
 static void
 pipe_closed (signo)
      /* If this is missing, some compilers complain.  */
-     int signo;
+     int signo ATTRIBUTE_UNUSED;
 {
   fatal ("output pipe has been closed");
 }
@@ -10076,78 +10750,87 @@ memory_full ()
 {
   fatal ("Memory exhausted.");
 }
+\f
+#ifdef VMS
 
+/* Under VMS we need to fix up the "include" specification filename.
 
-GENERIC_PTR
-xmalloc (size)
-     size_t size;
-{
-  register GENERIC_PTR ptr = (GENERIC_PTR) malloc (size);
-  if (!ptr)
-    memory_full ();
-  return ptr;
-}
+   Rules for possible conversions
 
-static GENERIC_PTR
-xrealloc (old, size)
-     GENERIC_PTR old;
-     size_t size;
-{
-  register GENERIC_PTR ptr = (GENERIC_PTR) realloc (old, size);
-  if (!ptr)
-    memory_full ();
-  return ptr;
-}
+       fullname                tried paths
 
-static GENERIC_PTR
-xcalloc (number, size)
-     size_t number, size;
-{
-  register size_t total = number * size;
-  register GENERIC_PTR ptr = (GENERIC_PTR) malloc (total);
-  if (!ptr)
-    memory_full ();
-  bzero (ptr, total);
-  return ptr;
-}
+       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
 
-static char *
-savestring (input)
-     char *input;
-{
-  size_t size = strlen (input);
-  char *output = xmalloc (size + 1);
-  strcpy (output, input);
-  return output;
-}
-\f
-#ifdef VMS
+   The path:/name input is constructed when expanding <> includes.
 
-/* Under VMS we need to fix up the "include" specification filename so
-   that everything following the 1st slash is changed into its correct
-   VMS file specification.  */
+   return 1 if name was changed, 0 else.  */
 
-static void
-hack_vms_include_specification (fname, vaxc_include)
-     char *fname;
+static int
+hack_vms_include_specification (fullname, vaxc_include)
+     char *fullname;
      int vaxc_include;
 {
-  register char *cp, *cp1, *cp2;
-  int f, check_filename_before_returning;
+  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!!! */
 
-  cp = base_name (fname);
+  /* 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);
 
   /*
    * Check if we have a vax-c style '#include filename'
    * and add the missing .h
    */
-  if (vaxc_include && !index (cp,'.'))
-    strcat (cp, ".h");
 
-  cp2 = Local;                 /* initialize */
+  if (vaxc_include && !index (basename,'.'))
+    strcat (basename, ".h");
+
+  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
@@ -10160,112 +10843,195 @@ hack_vms_include_specification (fname, vaxc_include)
      If no device is specified, then the first directory name is taken to be
      a device name (or a rooted logical).  */
 
-  /* See if we found that 1st slash */
-  if (cp == 0) return;         /* Nothing to do!!! */
-  if (*cp != '/') return;      /* Nothing to do!!! */
-  /* Point to the UNIX filename part (which needs to be fixed!) */
-  cp1 = cp+1;
+  /* 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 (((cp - fname) > 1) && ((cp[-1] == ']') || (cp[-1] == '>'))) {
-    if (cp[-2] != '.') {
-      /*
-       * The VMS part ends in a `]', and the preceding character is not a `.'.
-       * 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.  */
-      cp -= 1;                 /* Strip "]" */
-      cp1--;                   /* 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 cp1, so that it points to a '/'.  This inhibits the
-       * generation of the 000000 root directory spec (which does not belong here
-       * in this case).
-       */
-      cp -= 2;                 /* Strip ".]" */
-      cp1--; };                        /* backspace */
-  } else {
+     the UNIX filename part and we are done.  */
 
-    /* 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 (cp[-1] != ':') *cp2++ = ':'; /* dev not in spec.  take first dir */
-    *cp2++ = '[';              /* Open the directory specification */
-  }
+  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 */
+     specified already.
 
-  /* If there are no other slashes then the filename will be
+     If there are no other slashes then the filename will be
      in the "root" directory.  Otherwise, we need to add
      directory specifications.  */
-  if (index (cp1, '/') == 0) {
-    /* Just add "000000]" as the directory string */
-    strcpy (cp2, "000000]");
-    cp2 += strlen (cp2);
-    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 (cp1, '/') != 0) {
-      /* If this token is "." we can ignore it */
-      if ((cp1[0] == '.') && (cp1[1] == '/')) {
-       cp1 += 2;
-       continue;
-      }
-      /* Add a subdirectory spec. Do not duplicate "." */
-      if (cp2[-1] != '.' && cp2[-1] != '[' && cp2[-1] != '<')
-       *cp2++ = '.';
-      /* If this is ".." then the spec becomes "-" */
-      if ((cp1[0] == '.') && (cp1[1] == '.') && (cp[2] == '/')) {
-       /* Add "-" and skip the ".." */
-       *cp2++ = '-';
-       cp1 += 3;
-       continue;
-      }
-      /* Copy the subdirectory */
-      while (*cp1 != '/') *cp2++= *cp1++;
-      cp1++;                   /* Skip the "/" */
+
+  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 */
+       }
     }
-    /* Close the directory specification */
-    if (cp2[-1] == '.')                /* no trailing periods */
-      cp2--;
-    *cp2++ = ']';
-  }
-  /* Now add the filename */
-  while (*cp1) *cp2++ = *cp1++;
-  *cp2 = 0;
+  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 (cp, Local);
+
+  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 (fname, O_RDONLY, 0666);
-    if (f >= 0) {
-      /* The file name is OK as it is, so return it as is.  */
-      close (f);
-      return;
+  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 */
+
     }
-    /* The filename did not work.  Try to remove the [000000] from the name,
-       and return it.  */
-    cp = index (fname, '[');
-    cp2 = index (fname, ']') + 1;
-    strcpy (cp, cp2);          /* this gets rid of it */
-  }
-  return;
+
+  return 1;
 }
 #endif /* VMS */
 \f
@@ -10398,4 +11164,25 @@ VMS_stat (name, statbuf)
 
   return result;
 }
+
+static size_t
+VMS_fwrite (ptr, size, nitems, stream)
+     void const *ptr;
+     size_t size;
+     size_t nitems;
+     FILE *stream;
+{
+  /* VMS fwrite has undesirable results
+     if STREAM happens to be a record oriented file.
+     Work around this problem by writing each character individually.  */
+  char const *p = ptr;
+  size_t bytes = size * nitems;
+  char *lim = p + bytes;
+
+  while (p < lim)
+    if (putc (*p++, stream) == EOF)
+      return 0;
+
+  return bytes;
+}
 #endif /* VMS */