* SDCPP synchronized with GCC CPP release version 3.4.6,
authorborutr <borutr@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Mon, 25 Dec 2006 21:10:07 +0000 (21:10 +0000)
committerborutr <borutr@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Mon, 25 Dec 2006 21:10:07 +0000 (21:10 +0000)
  the latest release before 4.x:
* support/cpp2/Makefile.in, support/cpp2/config.h,
  support/cpp2/configure, support/cpp2/configure.in,
  support/cpp2/cppdefault.c, support/cpp2/cppdefault.h,
  support/cpp2/cpperror.c, support/cpp2/cppexp.c,
  support/cpp2/cppfiles.c, support/cpp2/cpphash.c,
  support/cpp2/cpphash.h, support/cpp2/cppinit.c,
  support/cpp2/cpplex.c, support/cpp2/cpplib.c,
  support/cpp2/cpplib.h, support/cpp2/cppmacro.c,
  support/cpp2/cpptrad.c, support/cpp2/except.h,
  support/cpp2/hashtable.c, support/cpp2/hashtable.h,
  support/cpp2/hwint.h, support/cpp2/intl.h,
  support/cpp2/line-map.c, support/cpp2/line-map.h,
  support/cpp2/mkdeps.c, support/cpp2/mkdeps.h,
  support/cpp2/output.h, support/cpp2/prefix.c,
  support/cpp2/prefix.h, support/cpp2/sdcpp.dsp,
  support/cpp2/system.h, support/cpp2/version.c:
  modified
* support/cpp2/c-incpath.c, support/cpp2/c-incpath.h,
  support/cpp2/c-ppoutput.c, support/cpp2/c-pretty-print.c,
  support/cpp2/c-pretty-print.h, support/cpp2/cppcharset.c,
  support/cpp2/cppucnid.h, support/cpp2/diagnostic.c,
  support/cpp2/diagnostic.def, support/cpp2/diagnostic.h,
  support/cpp2/hashtab.c, support/cpp2/hashtab.h,
  support/cpp2/input.h, support/cpp2/libiberty/getpwd.c,
  support/cpp2/libiberty/vasprintf.c, support/cpp2/libiberty/xmemdup.c,
  support/cpp2/move-if-change, support/cpp2/opts.c,
  support/cpp2/opts.h, support/cpp2/opts.sh,
  support/cpp2/pretty-print.c, support/cpp2/pretty-print.h,
  support/cpp2/sdcpp.opt, support/cpp2/sdcpp-opts.c,
  support/cpp2/win32, support/cpp2/win32/dirent.c,
  support/cpp2/win32/dirent.h:
  added
* support/cpp2/sdcpp.c: renamed from sdcppmain.c
* support/cpp2/sdcpp.h: renamed from sdcc.h
* sdcppinit.c: deleted

git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@4524 4a8a32a2-be11-0410-ad9d-d568d2c75423

64 files changed:
ChangeLog
support/cpp2/Makefile.in
support/cpp2/c-incpath.c [new file with mode: 0644]
support/cpp2/c-incpath.h [new file with mode: 0644]
support/cpp2/c-ppoutput.c [new file with mode: 0644]
support/cpp2/c-pretty-print.c [new file with mode: 0644]
support/cpp2/c-pretty-print.h [new file with mode: 0644]
support/cpp2/config.h
support/cpp2/configure
support/cpp2/configure.in
support/cpp2/cppcharset.c [new file with mode: 0644]
support/cpp2/cppdefault.c
support/cpp2/cppdefault.h
support/cpp2/cpperror.c
support/cpp2/cppexp.c
support/cpp2/cppfiles.c
support/cpp2/cpphash.c
support/cpp2/cpphash.h
support/cpp2/cppinit.c
support/cpp2/cpplex.c
support/cpp2/cpplib.c
support/cpp2/cpplib.h
support/cpp2/cppmacro.c
support/cpp2/cpptrad.c
support/cpp2/cppucnid.h [new file with mode: 0644]
support/cpp2/diagnostic.c [new file with mode: 0644]
support/cpp2/diagnostic.def [new file with mode: 0644]
support/cpp2/diagnostic.h [new file with mode: 0644]
support/cpp2/except.h
support/cpp2/hashtab.c [new file with mode: 0644]
support/cpp2/hashtab.h [new file with mode: 0644]
support/cpp2/hashtable.c
support/cpp2/hashtable.h
support/cpp2/hwint.h
support/cpp2/input.h [new file with mode: 0644]
support/cpp2/intl.h
support/cpp2/libiberty/getpwd.c [new file with mode: 0644]
support/cpp2/libiberty/vasprintf.c [new file with mode: 0644]
support/cpp2/libiberty/xmemdup.c [new file with mode: 0644]
support/cpp2/line-map.c
support/cpp2/line-map.h
support/cpp2/mkdeps.c
support/cpp2/mkdeps.h
support/cpp2/move-if-change [new file with mode: 0644]
support/cpp2/opts.c [new file with mode: 0644]
support/cpp2/opts.h [new file with mode: 0644]
support/cpp2/opts.sh [new file with mode: 0755]
support/cpp2/output.h
support/cpp2/prefix.c
support/cpp2/prefix.h
support/cpp2/pretty-print.c [new file with mode: 0644]
support/cpp2/pretty-print.h [new file with mode: 0644]
support/cpp2/sdcc.h [deleted file]
support/cpp2/sdcpp-opts.c [new file with mode: 0644]
support/cpp2/sdcpp.c [new file with mode: 0644]
support/cpp2/sdcpp.dsp
support/cpp2/sdcpp.h [new file with mode: 0644]
support/cpp2/sdcpp.opt [new file with mode: 0644]
support/cpp2/sdcppinit.c [deleted file]
support/cpp2/sdcppmain.c [deleted file]
support/cpp2/system.h
support/cpp2/version.c
support/cpp2/win32/dirent.c [new file with mode: 0644]
support/cpp2/win32/dirent.h [new file with mode: 0644]

index 415324cd428c3b3ddf80ddb9f3907ff04a84b469..55e07d058c8454762d79a434e58e0a4499d35389 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,43 @@
+2006-12-25 Borut Razem <borut.razem AT siol.net>
+
+       * SDCPP synchronized with GCC CPP release version 3.4.6,
+         the latest release before 4.x:
+       * support/cpp2/Makefile.in, support/cpp2/config.h,
+         support/cpp2/configure, support/cpp2/configure.in,
+         support/cpp2/cppdefault.c, support/cpp2/cppdefault.h,
+         support/cpp2/cpperror.c, support/cpp2/cppexp.c,
+         support/cpp2/cppfiles.c, support/cpp2/cpphash.c,
+         support/cpp2/cpphash.h, support/cpp2/cppinit.c,
+         support/cpp2/cpplex.c, support/cpp2/cpplib.c,
+         support/cpp2/cpplib.h, support/cpp2/cppmacro.c,
+         support/cpp2/cpptrad.c, support/cpp2/except.h,
+         support/cpp2/hashtable.c, support/cpp2/hashtable.h,
+         support/cpp2/hwint.h, support/cpp2/intl.h,
+         support/cpp2/line-map.c, support/cpp2/line-map.h,
+         support/cpp2/mkdeps.c, support/cpp2/mkdeps.h,
+         support/cpp2/output.h, support/cpp2/prefix.c,
+         support/cpp2/prefix.h, support/cpp2/sdcpp.dsp,
+         support/cpp2/system.h, support/cpp2/version.c:
+         modified
+       * support/cpp2/c-incpath.c, support/cpp2/c-incpath.h,
+         support/cpp2/c-ppoutput.c, support/cpp2/c-pretty-print.c,
+         support/cpp2/c-pretty-print.h, support/cpp2/cppcharset.c,
+         support/cpp2/cppucnid.h, support/cpp2/diagnostic.c,
+         support/cpp2/diagnostic.def, support/cpp2/diagnostic.h,
+         support/cpp2/hashtab.c, support/cpp2/hashtab.h,
+         support/cpp2/input.h, support/cpp2/libiberty/getpwd.c,
+         support/cpp2/libiberty/vasprintf.c, support/cpp2/libiberty/xmemdup.c,
+         support/cpp2/move-if-change, support/cpp2/opts.c,
+         support/cpp2/opts.h, support/cpp2/opts.sh,
+         support/cpp2/pretty-print.c, support/cpp2/pretty-print.h,
+         support/cpp2/sdcpp.opt, support/cpp2/sdcpp-opts.c,
+         support/cpp2/win32, support/cpp2/win32/dirent.c,
+         support/cpp2/win32/dirent.h:
+         added
+       * support/cpp2/sdcpp.c: renamed from sdcppmain.c
+       * support/cpp2/sdcpp.h: renamed from sdcc.h
+       * sdcppinit.c: deleted
+
 2006-12-23 Borut Razem <borut.razem AT siol.net>
 
        * support/cpp2/cpphash.h, support/cpp2/cpplex.c,
index e456119899b296a17d1926d333b44fa37e234ba7..cb51ab78a2551e56c62b59b28e3061daf4a2f4b0 100644 (file)
@@ -92,6 +92,7 @@ includedir = $(local_prefix)/include
 exeext = @host_exeext@
 
 transform       = @program_transform_name@
+lang_opt_files=$(srcdir)/sdcpp.opt
 
 # Top build directory, relative to here.
 top_builddir = @top_builddir@
@@ -181,11 +182,20 @@ config.status: $(srcdir)/configure  version.c
          LANGUAGES="$(CONFIG_LANGUAGES)" $(SHELL) config.status --recheck; \
        fi
 
+options.c: $(lang_opt_files) $(srcdir)/opts.sh options.h intl.h
+
+options.h: $(lang_opt_files) $(srcdir)/opts.sh Makefile
+       AWK=awk $(SHELL) $(srcdir)/opts.sh \
+               '$(SHELL) $(srcdir)/move-if-change' \
+               options.c options.h $(lang_opt_files)
+
 version.o: version.c version.h
 
 hashtable.o: hashtable.c hashtable.h $(CONFIG_H) $(SYSTEM_H) $(OBSTACK_H)
 
-line-map.o: line-map.c line-map.h intl.h $(CONFIG_H) $(SYSTEM_H)
+hashtab.o: hashtab.c hashtab.h $(CONFIG_H)
+
+cppcharset.o: cppcharset.c $(CONFIG_H) $(SYSTEM_H)
 
 mbchar.o: mbchar.c mbchar.h $(CONFIG_H) $(SYSTEM_H)
 
@@ -206,10 +216,11 @@ PREPROCESSOR_DEFINES = \
   -DCROSS_INCLUDE_DIR=\"$(gcc_tooldir)/sys-include\" \
   -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\"
 
-LIBCPP_OBJS =  cppmain.o cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
+LIBCPP_OBJS =  c-ppoutput.o cppinit.o cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
                cpphash.o cpperror.o cppdefault.o \
                hashtable.o mkdeps.o prefix.o version.o mbchar.o \
-               line-map.o cpptrad.o
+               line-map.o cpptrad.o cppcharset.o hashtab.o \
+               opts.o options.o diagnostic.o pretty-print.o c-incpath.o
 
 LIBCPP_DEPS =  cpplib.h cpphash.h hashtable.h intl.h $(OBSTACK_H) $(SYSTEM_H)
 
@@ -222,18 +233,19 @@ libcpp.a: $(LIBCPP_OBJS)
 
 MY_LIBIBERTY_BITS = safe-ctype.o obstack.o splay-tree.o \
                    lbasename.o hex.o concat.o \
-                   xmalloc.o xstrdup.o xstrerror.o xexit.o
+                   xmalloc.o xmemdup.o xstrdup.o xstrerror.o xexit.o getpwd.o
 
-$(TARGET): sdcppmain.o sdcppinit.o $(MY_LIBIBERTY_BITS) libcpp.a $(LIBDEPS)
+$(TARGET): sdcpp.o sdcpp-opts.o $(MY_LIBIBERTY_BITS) libcpp.a $(LIBDEPS)
        mkdir -p $(dir $@)
-       $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ sdcppmain.o sdcppinit.o \
+       $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ sdcpp.o sdcpp-opts.o \
        $(MY_LIBIBERTY_BITS) libcpp.a $(LIBS)
 
-sdcppmain.o:  sdcppmain.c  $(CONFIG_H) cpplib.h $(SYSTEM_H)
-sdcppinit.o:  sdcppinit.c  $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \
-               mkdeps.h prefix.h output.h version.h
+sdcpp.o:      sdcpp.c  $(CONFIG_H) cpplib.h $(SYSTEM_H)
+sdcpp-opts.o: sdcpp-opts.c $(CONFIG_H) $(LIBCPP_DEPS)
 
-cppmain.o:  cppmain.c  $(CONFIG_H) cpplib.h intl.h $(SYSTEM_H)
+c-ppoutput.o:  c-ppoutput.c  $(CONFIG_H) cpplib.h intl.h $(SYSTEM_H)
+cppinit.o:  cppinit.c  $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \
+               mkdeps.h prefix.h output.h version.h
 cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS)
 cppexp.o:   cppexp.c   $(CONFIG_H) $(LIBCPP_DEPS)
 cpplex.o:   cpplex.c   $(CONFIG_H) $(LIBCPP_DEPS) mbchar.h
@@ -242,30 +254,52 @@ cpplib.o:   cpplib.c   $(CONFIG_H) $(LIBCPP_DEPS)
 cpphash.o:  cpphash.c  $(CONFIG_H) $(LIBCPP_DEPS)
 cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h
 cpptrad.o:  cpptrad.c  $(CONFIG_H) $(LIBCPP_DEPS)
+opts.o:     opts.c     $(CONFIG_H) $(LIBCPP_DEPS) options.h
+diagnostic.o: diagnostic.c $(CONFIG_H) $(LIBCPP_DEPS) diagnostic.h
+pretty-print.o: pretty-print.c $(CONFIG_H) $(LIBCPP_DEPS) pretty-print.h
+c-incpath.o: $(CONFIG_H) $(LIBCPP_DEPS) c-incpath.h
+
+cppdefault.o: cppdefault.c $(CONFIG_H) $(SYSTEM_H) cppdefault.h Makefile
+       $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+         $(PREPROCESSOR_DEFINES) \
+         -c $(srcdir)/cppdefault.c
+
+mkdeps.o: mkdeps.c $(CONFIG_H) $(SYSTEM_H) mkdeps.h
+
+# Libiberty
+
 safe-ctype.o: $(LIBIBERTY_DIR)/safe-ctype.c $(LIBIBERTY_DIR)/safe-ctype.h $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 obstack.o: $(LIBIBERTY_DIR)/obstack.c $(LIBIBERTY_DIR)/obstack.h $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 splay-tree.o: $(LIBIBERTY_DIR)/splay-tree.c $(LIBIBERTY_DIR)/splay-tree.h $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 lbasename.o: $(LIBIBERTY_DIR)/lbasename.c  $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 hex.o: $(LIBIBERTY_DIR)/hex.c  $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 concat.o: $(LIBIBERTY_DIR)/concat.c  $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 xmalloc.o: $(LIBIBERTY_DIR)/xmalloc.c  $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+xmemdup.o: $(LIBIBERTY_DIR)/xmemdup.c  $(CONFIG_H) $(LIBCPP_DEPS)
+       $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 xstrdup.o: $(LIBIBERTY_DIR)/xstrdup.c  $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 xexit.o: $(LIBIBERTY_DIR)/xexit.c  $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
 xstrerror.o: $(LIBIBERTY_DIR)/xstrerror.c  $(CONFIG_H) $(LIBCPP_DEPS)
        $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-cppdefault.o: cppdefault.c $(CONFIG_H) $(SYSTEM_H) cppdefault.h Makefile
-       $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-         $(PREPROCESSOR_DEFINES) \
-         -c $(srcdir)/cppdefault.c
-
-mkdeps.o: mkdeps.c $(CONFIG_H) $(SYSTEM_H) mkdeps.h
 
+getpwd.o: $(LIBIBERTY_DIR)/getpwd.c  $(CONFIG_H) $(LIBCPP_DEPS)
+       $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
diff --git a/support/cpp2/c-incpath.c b/support/cpp2/c-incpath.c
new file mode 100644 (file)
index 0000000..4b0bf54
--- /dev/null
@@ -0,0 +1,362 @@
+/* Set up combined include path chain for the preprocessor.\r
+   Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,\r
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.\r
+\r
+   Broken out of cppinit.c and cppfiles.c and rewritten Mar 2003.\r
+\r
+This program is free software; you can redistribute it and/or modify it\r
+under the terms of the GNU General Public License as published by the\r
+Free Software Foundation; either version 2, or (at your option) any\r
+later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */\r
+\r
+#include "config.h"\r
+#include "system.h"\r
+#include "cpplib.h"\r
+#include "prefix.h"\r
+#include "intl.h"\r
+#include "c-incpath.h"\r
+#include "cppdefault.h"\r
+\r
+/* Windows does not natively support inodes, and neither does MSDOS.\r
+   Cygwin's emulation can generate non-unique inodes, so don't use it.\r
+   VMS has non-numeric inodes.  */\r
+#ifdef VMS\r
+# define INO_T_EQ(A, B) (!memcmp (&(A), &(B), sizeof (A)))\r
+# define INO_T_COPY(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof (SRC))\r
+#else\r
+# if (defined _WIN32 && ! defined (_UWIN)) || defined __MSDOS__\r
+#  define INO_T_EQ(A, B) 0\r
+# else\r
+#  define INO_T_EQ(A, B) ((A) == (B))\r
+# endif\r
+# define INO_T_COPY(DEST, SRC) (DEST) = (SRC)\r
+#endif\r
+\r
+static void add_env_var_paths (const char *, int);\r
+static void add_standard_paths (const char *, const char *, int);\r
+static void free_path (struct cpp_dir *, int);\r
+static void merge_include_chains (cpp_reader *, int);\r
+static struct cpp_dir *remove_duplicates (cpp_reader *, struct cpp_dir *,\r
+                                          struct cpp_dir *,\r
+                                          struct cpp_dir *, int);\r
+\r
+/* Include chains heads and tails.  */\r
+static struct cpp_dir *heads[4];\r
+static struct cpp_dir *tails[4];\r
+static bool quote_ignores_source_dir;\r
+enum { REASON_QUIET = 0, REASON_NOENT, REASON_DUP, REASON_DUP_SYS };\r
+\r
+/* Free an element of the include chain, possibly giving a reason.  */\r
+static void\r
+free_path (struct cpp_dir *path, int reason)\r
+{\r
+  switch (reason)\r
+    {\r
+    case REASON_DUP:\r
+    case REASON_DUP_SYS:\r
+      fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), path->name);\r
+      if (reason == REASON_DUP_SYS)\r
+       fprintf (stderr,\r
+ _("  as it is a non-system directory that duplicates a system directory\n"));\r
+      break;\r
+\r
+    case REASON_NOENT:\r
+      fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"),\r
+              path->name);\r
+      break;\r
+\r
+    case REASON_QUIET:\r
+    default:\r
+      break;\r
+    }\r
+\r
+  free (path->name);\r
+  free (path);\r
+}\r
+\r
+/* Read ENV_VAR for a PATH_SEPARATOR-separated list of file names; and\r
+   append all the names to the search path CHAIN.  */\r
+static void\r
+add_env_var_paths (const char *env_var, int chain)\r
+{\r
+  char *p, *q, *path;\r
+\r
+  GET_ENVIRONMENT (q, env_var);\r
+\r
+  if (!q)\r
+    return;\r
+\r
+  for (p = q; *q; p = q + 1)\r
+    {\r
+      q = p;\r
+      while (*q != 0 && *q != PATH_SEPARATOR)\r
+       q++;\r
+\r
+      if (p == q)\r
+       path = xstrdup (".");\r
+      else\r
+       {\r
+         path = xmalloc (q - p + 1);\r
+         memcpy (path, p, q - p);\r
+         path[q - p] = '\0';\r
+       }\r
+\r
+      add_path (path, chain, chain == SYSTEM);\r
+    }\r
+}\r
+\r
+/* Append the standard include chain defined in cppdefault.c.  */\r
+static void\r
+add_standard_paths (const char *sysroot, const char *iprefix, int cxx_stdinc)\r
+{\r
+  const struct default_include *p;\r
+  size_t len;\r
+\r
+  if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0)\r
+    {\r
+      /* Look for directories that start with the standard prefix.\r
+        "Translate" them, ie. replace /usr/local/lib/gcc... with\r
+        IPREFIX and search them first.  */\r
+      for (p = cpp_include_defaults; p->fname; p++)\r
+       {\r
+         if (!p->cplusplus || cxx_stdinc)\r
+           {\r
+             /* Should we be translating sysrooted dirs too?  Assume\r
+                that iprefix and sysroot are mutually exclusive, for\r
+                now.  */\r
+             if (sysroot && p->add_sysroot)\r
+               continue;\r
+             if (!strncmp (p->fname, cpp_GCC_INCLUDE_DIR, len))\r
+               {\r
+                 char *str = concat (iprefix, p->fname + len, NULL);\r
+                 add_path (str, SYSTEM, p->cxx_aware);\r
+               }\r
+           }\r
+       }\r
+    }\r
+\r
+  for (p = cpp_include_defaults; p->fname; p++)\r
+    {\r
+      if (!p->cplusplus || cxx_stdinc)\r
+       {\r
+         char *str;\r
+\r
+         /* Should this directory start with the sysroot?  */\r
+         if (sysroot && p->add_sysroot)\r
+           str = concat (sysroot, p->fname, NULL);\r
+         else\r
+           str = update_path (p->fname, p->component);\r
+\r
+         add_path (str, SYSTEM, p->cxx_aware);\r
+       }\r
+    }\r
+}\r
+\r
+/* For each duplicate path in chain HEAD, keep just the first one.\r
+   Remove each path in chain HEAD that also exists in chain SYSTEM.\r
+   Set the NEXT pointer of the last path in the resulting chain to\r
+   JOIN, unless it duplicates JOIN in which case the last path is\r
+   removed.  Return the head of the resulting chain.  Any of HEAD,\r
+   JOIN and SYSTEM can be NULL.  */\r
+static struct cpp_dir *\r
+remove_duplicates (cpp_reader *pfile, struct cpp_dir *head,\r
+                  struct cpp_dir *system, struct cpp_dir *join,\r
+                  int verbose)\r
+{\r
+  struct cpp_dir **pcur, *tmp, *cur;\r
+  struct stat st;\r
+\r
+  for (pcur = &head; *pcur; )\r
+    {\r
+      int reason = REASON_QUIET;\r
+\r
+      cur = *pcur;\r
+\r
+      if (stat (cur->name, &st))\r
+       {\r
+         /* Dirs that don't exist are silently ignored, unless verbose.  */\r
+         if (errno != ENOENT)\r
+           cpp_errno (pfile, CPP_DL_ERROR, cur->name);\r
+         else\r
+           reason = REASON_NOENT;\r
+       }\r
+      else if (!S_ISDIR (st.st_mode))\r
+       cpp_error_with_line (pfile, CPP_DL_ERROR, 0, 0,\r
+                            "%s: not a directory", cur->name);\r
+      else\r
+       {\r
+         INO_T_COPY (cur->ino, st.st_ino);\r
+         cur->dev  = st.st_dev;\r
+\r
+         /* Remove this one if it is in the system chain.  */\r
+         reason = REASON_DUP_SYS;\r
+         for (tmp = system; tmp; tmp = tmp->next)\r
+           if (INO_T_EQ (tmp->ino, cur->ino) && tmp->dev == cur->dev)\r
+             break;\r
+\r
+         if (!tmp)\r
+           {\r
+             /* Duplicate of something earlier in the same chain?  */\r
+             reason = REASON_DUP;\r
+             for (tmp = head; tmp != cur; tmp = tmp->next)\r
+               if (INO_T_EQ (cur->ino, tmp->ino) && cur->dev == tmp->dev)\r
+                 break;\r
+\r
+             if (tmp == cur\r
+                 /* Last in the chain and duplicate of JOIN?  */\r
+                 && !(cur->next == NULL && join\r
+                      && INO_T_EQ (cur->ino, join->ino)\r
+                      && cur->dev == join->dev))\r
+               {\r
+                 /* Unique, so keep this directory.  */\r
+                 pcur = &cur->next;\r
+                 continue;\r
+               }\r
+           }\r
+       }\r
+\r
+      /* Remove this entry from the chain.  */\r
+      *pcur = cur->next;\r
+      free_path (cur, verbose ? reason: REASON_QUIET);\r
+    }\r
+\r
+  *pcur = join;\r
+  return head;\r
+}\r
+\r
+/* Merge the four include chains together in the order quote, bracket,\r
+   system, after.  Remove duplicate dirs (as determined by\r
+   INO_T_EQ()).\r
+\r
+   We can't just merge the lists and then uniquify them because then\r
+   we may lose directories from the <> search path that should be\r
+   there; consider -Ifoo -Ibar -I- -Ifoo -Iquux.  It is however safe\r
+   to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written -Ibar -I- -Ifoo\r
+   -Iquux.  */\r
+static void\r
+merge_include_chains (cpp_reader *pfile, int verbose)\r
+{\r
+  /* Join the SYSTEM and AFTER chains.  Remove duplicates in the\r
+     resulting SYSTEM chain.  */\r
+  if (heads[SYSTEM])\r
+    tails[SYSTEM]->next = heads[AFTER];\r
+  else\r
+    heads[SYSTEM] = heads[AFTER];\r
+  heads[SYSTEM] = remove_duplicates (pfile, heads[SYSTEM], 0, 0, verbose);\r
+\r
+  /* Remove duplicates from BRACKET that are in itself or SYSTEM, and\r
+     join it to SYSTEM.  */\r
+  heads[BRACKET] = remove_duplicates (pfile, heads[BRACKET], heads[SYSTEM],\r
+                                     heads[SYSTEM], verbose);\r
+\r
+  /* Remove duplicates from QUOTE that are in itself or SYSTEM, and\r
+     join it to BRACKET.  */\r
+  heads[QUOTE] = remove_duplicates (pfile, heads[QUOTE], heads[SYSTEM],\r
+                                   heads[BRACKET], verbose);\r
+\r
+  /* If verbose, print the list of dirs to search.  */\r
+  if (verbose)\r
+    {\r
+      struct cpp_dir *p;\r
+\r
+      fprintf (stderr, _("#include \"...\" search starts here:\n"));\r
+      for (p = heads[QUOTE];; p = p->next)\r
+       {\r
+         if (p == heads[BRACKET])\r
+           fprintf (stderr, _("#include <...> search starts here:\n"));\r
+         if (!p)\r
+           break;\r
+         fprintf (stderr, " %s\n", p->name);\r
+       }\r
+      fprintf (stderr, _("End of search list.\n"));\r
+    }\r
+}\r
+\r
+/* Use given -I paths for #include "..." but not #include <...>, and\r
+   don't search the directory of the present file for #include "...".\r
+   (Note that -I. -I- is not the same as the default setup; -I. uses\r
+   the compiler's working dir.)  */\r
+void\r
+split_quote_chain (void)\r
+{\r
+  heads[QUOTE] = heads[BRACKET];\r
+  tails[QUOTE] = tails[BRACKET];\r
+  heads[BRACKET] = NULL;\r
+  tails[BRACKET] = NULL;\r
+  /* This is NOT redundant.  */\r
+  quote_ignores_source_dir = true;\r
+}\r
+\r
+/* Add PATH to the include chain CHAIN. PATH must be malloc-ed and\r
+   NUL-terminated.  */\r
+void\r
+add_path (char *path, int chain, int cxx_aware)\r
+{\r
+  struct cpp_dir *p;\r
+\r
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)\r
+  /* Convert all backslashes to slashes.  The native CRT stat()\r
+     function does not recognise a directory that ends in a backslash\r
+     (unless it is a drive root dir, such "c:\").  Forward slashes,\r
+     trailing or otherwise, cause no problems for stat().  */\r
+  char* c;\r
+  for (c = path; *c; c++)\r
+    if (*c == '\\') *c = '/';\r
+#endif\r
+\r
+  p = xmalloc (sizeof (struct cpp_dir));\r
+  p->next = NULL;\r
+  p->name = path;\r
+  if (chain == SYSTEM || chain == AFTER)\r
+    p->sysp = 1 + !cxx_aware;\r
+  else\r
+    p->sysp = 0;\r
+\r
+  if (tails[chain])\r
+    tails[chain]->next = p;\r
+  else\r
+    heads[chain] = p;\r
+  tails[chain] = p;\r
+}\r
+\r
+/* Exported function to handle include chain merging, duplicate\r
+   removal, and registration with cpplib.  */\r
+void\r
+register_include_chains (cpp_reader *pfile, const char *sysroot,\r
+                        const char *iprefix, int stdinc, int cxx_stdinc,\r
+                        int verbose)\r
+{\r
+  static const char *const lang_env_vars[] =\r
+    { "C_INCLUDE_PATH", "CPLUS_INCLUDE_PATH",\r
+      "OBJC_INCLUDE_PATH", "OBJCPLUS_INCLUDE_PATH" };\r
+  cpp_options *cpp_opts = cpp_get_options (pfile);\r
+  size_t idx = (cpp_opts->objc ? 2: 0);\r
+\r
+  if (cpp_opts->cplusplus)\r
+    idx++;\r
+  else\r
+    cxx_stdinc = false;\r
+\r
+  /* CPATH and language-dependent environment variables may add to the\r
+     include chain.  */\r
+  add_env_var_paths ("CPATH", BRACKET);\r
+  add_env_var_paths (lang_env_vars[idx], SYSTEM);\r
+\r
+  /* Finally chain on the standard directories.  */\r
+  if (stdinc)\r
+    add_standard_paths (sysroot, iprefix, cxx_stdinc);\r
+\r
+  merge_include_chains (pfile, verbose);\r
+\r
+  cpp_set_include_chains (pfile, heads[QUOTE], heads[BRACKET],\r
+                         quote_ignores_source_dir);\r
+}\r
diff --git a/support/cpp2/c-incpath.h b/support/cpp2/c-incpath.h
new file mode 100644 (file)
index 0000000..31ed657
--- /dev/null
@@ -0,0 +1,23 @@
+/* Set up combined include path for the preprocessor.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+extern void split_quote_chain (void);
+extern void add_path (char *, int, int);
+extern void register_include_chains (cpp_reader *, const char *,
+                                    const char *, int, int, int);
+
+enum { QUOTE = 0, BRACKET, SYSTEM, AFTER };
diff --git a/support/cpp2/c-ppoutput.c b/support/cpp2/c-ppoutput.c
new file mode 100644 (file)
index 0000000..f564dfe
--- /dev/null
@@ -0,0 +1,410 @@
+/* Preprocess only, using cpplib.
+   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
+   Written by Per Bothner, 1994-95.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "cpphash.h"
+
+/* Encapsulates state used to convert a stream of tokens into a text
+   file.  */
+static struct
+{
+  FILE *outf;                  /* Stream to write to.  */
+  const struct line_map *map;  /* Logical to physical line mappings.  */
+  const cpp_token *prev;       /* Previous token.  */
+  const cpp_token *source;     /* Source token for spacing.  */
+  fileline line;               /* Line currently being written.  */
+  unsigned char printed;       /* Nonzero if something output at line.  */
+} print;
+
+/* General output routines.  */
+static void scan_translation_unit (cpp_reader *);
+static void scan_translation_unit_trad (cpp_reader *);
+static void account_for_newlines (const unsigned char *, size_t);
+static int dump_macro (cpp_reader *, cpp_hashnode *, void *);
+
+static void print_line (const struct line_map *, fileline, const char *);
+static void maybe_print_line (const struct line_map *, fileline);
+
+/* Callback routines for the parser.   Most of these are active only
+   in specific modes.  */
+static void cb_line_change (cpp_reader *, const cpp_token *, int);
+static void cb_define (cpp_reader *, fileline, cpp_hashnode *);
+static void cb_undef (cpp_reader *, fileline, cpp_hashnode *);
+static void cb_include (cpp_reader *, fileline, const unsigned char *,
+                       const char *, int);
+static void cb_ident (cpp_reader *, fileline, const cpp_string *);
+static void cb_def_pragma (cpp_reader *, fileline);
+
+/* Preprocess and output.  */
+void
+preprocess_file (cpp_reader *pfile)
+{
+  /* A successful cpp_read_main_file guarantees that we can call
+     cpp_scan_nooutput or cpp_get_token next.  */
+  if (flag_no_output)
+    {
+      /* Scan -included buffers, then the main file.  */
+      while (pfile->buffer->prev)
+       cpp_scan_nooutput (pfile);
+      cpp_scan_nooutput (pfile);
+    }
+  else if (cpp_get_options (pfile)->traditional)
+    scan_translation_unit_trad (pfile);
+  else
+    scan_translation_unit (pfile);
+
+  /* -dM command line option.  Should this be elsewhere?  */
+  if (flag_dump_macros == 'M')
+    cpp_forall_identifiers (pfile, dump_macro, NULL);
+
+  /* Flush any pending output.  */
+  if (print.printed)
+    putc ('\n', print.outf);
+}
+
+/* Set up the callbacks as appropriate.  */
+void
+init_pp_output (FILE *out_stream)
+{
+  cpp_callbacks *cb = cpp_get_callbacks (parse_in);
+
+  if (!flag_no_output)
+    {
+      cb->line_change = cb_line_change;
+      /* Don't emit #pragma or #ident directives if we are processing
+        assembly language; the assembler may choke on them.  */
+      if (cpp_get_options (parse_in)->lang != CLK_ASM)
+       {
+         cb->ident      = cb_ident;
+         cb->def_pragma = cb_def_pragma;
+       }
+    }
+
+  if (flag_dump_includes)
+    cb->include  = cb_include;
+
+  if (flag_dump_macros == 'N' || flag_dump_macros == 'D')
+    {
+      cb->define = cb_define;
+      cb->undef  = cb_undef;
+    }
+
+  /* Initialize the print structure.  Setting print.line to -1 here is
+     a trick to guarantee that the first token of the file will cause
+     a linemarker to be output by maybe_print_line.  */
+  print.line = (fileline) -1;
+  print.printed = 0;
+  print.prev = 0;
+  print.map = 0;
+  print.outf = out_stream;
+}
+
+/* Writes out the preprocessed file, handling spacing and paste
+   avoidance issues.  */
+static void
+scan_translation_unit (cpp_reader *pfile)
+{
+  bool avoid_paste = false;
+
+  print.source = NULL;
+  for (;;)
+    {
+      const cpp_token *token = cpp_get_token (pfile);
+
+      if (token->type == CPP_PADDING)
+       {
+         avoid_paste = true;
+         if (print.source == NULL
+             || (!(print.source->flags & PREV_WHITE)
+                 && token->val.source == NULL))
+           print.source = token->val.source;
+         continue;
+       }
+
+      if (token->type == CPP_EOF)
+       break;
+
+      /* Subtle logic to output a space if and only if necessary.  */
+      if (avoid_paste)
+       {
+         if (print.source == NULL)
+           print.source = token;
+         if (print.source->flags & PREV_WHITE
+             || (print.prev
+                 && cpp_avoid_paste (pfile, print.prev, token))
+             || (print.prev == NULL && token->type == CPP_HASH))
+           putc (' ', print.outf);
+       }
+      else if (token->flags & PREV_WHITE)
+       putc (' ', print.outf);
+
+      avoid_paste = false;
+      print.source = NULL;
+      print.prev = token;
+      cpp_output_token (token, print.outf);
+
+      if (token->type == CPP_COMMENT)
+       account_for_newlines (token->val.str.text, token->val.str.len);
+    }
+}
+
+/* Adjust print.line for newlines embedded in output.  */
+static void
+account_for_newlines (const unsigned char *str, size_t len)
+{
+  while (len--)
+    if (*str++ == '\n')
+      print.line++;
+}
+
+/* Writes out a traditionally preprocessed file.  */
+static void
+scan_translation_unit_trad (cpp_reader *pfile)
+{
+  while (_cpp_read_logical_line_trad (pfile))
+    {
+      size_t len = pfile->out.cur - pfile->out.base;
+      maybe_print_line (print.map, pfile->out.first_line);
+      fwrite (pfile->out.base, 1, len, print.outf);
+      print.printed = 1;
+      if (!CPP_OPTION (pfile, discard_comments))
+       account_for_newlines (pfile->out.base, len);
+    }
+}
+
+/* If the token read on logical line LINE needs to be output on a
+   different line to the current one, output the required newlines or
+   a line marker, and return 1.  Otherwise return 0.  */
+static void
+maybe_print_line (const struct line_map *map, fileline line)
+{
+  /* End the previous line of text.  */
+  if (print.printed)
+    {
+      putc ('\n', print.outf);
+      print.line++;
+      print.printed = 0;
+    }
+
+  if (line >= print.line && line < print.line + 8)
+    {
+      while (line > print.line)
+       {
+         putc ('\n', print.outf);
+         print.line++;
+       }
+    }
+  else
+    print_line (map, line, "");
+}
+
+/* Output a line marker for logical line LINE.  Special flags are "1"
+   or "2" indicating entering or leaving a file.  */
+static void
+print_line (const struct line_map *map, fileline line, const char *special_flags)
+{
+  /* End any previous line of text.  */
+  if (print.printed)
+    putc ('\n', print.outf);
+  print.printed = 0;
+
+  print.line = line;
+  if (!flag_no_line_commands)
+    {
+      size_t to_file_len = strlen (map->to_file);
+      unsigned char *to_file_quoted = alloca (to_file_len * 4 + 1);
+      unsigned char *p;
+
+      /* cpp_quote_string does not nul-terminate, so we have to do it
+        ourselves.  */
+      p = cpp_quote_string (to_file_quoted,
+                           (unsigned char *)map->to_file, to_file_len);
+      *p = '\0';
+      fprintf (print.outf, "# %u \"%s\"%s",
+              SOURCE_LINE (map, print.line),
+              to_file_quoted, special_flags);
+
+      if (map->sysp == 2)
+       fputs (" 3 4", print.outf);
+      else if (map->sysp == 1)
+       fputs (" 3", print.outf);
+
+      putc ('\n', print.outf);
+    }
+}
+
+/* Called when a line of output is started.  TOKEN is the first token
+   of the line, and at end of file will be CPP_EOF.  */
+static void
+cb_line_change (cpp_reader *pfile, const cpp_token *token,
+               int parsing_args)
+{
+  if (token->type == CPP_EOF || parsing_args)
+    return;
+
+  maybe_print_line (print.map, token->line);
+  print.prev = 0;
+  print.source = 0;
+
+  /* Supply enough spaces to put this token in its original column,
+     one space per column greater than 2, since scan_translation_unit
+     will provide a space if PREV_WHITE.  Don't bother trying to
+     reconstruct tabs; we can't get it right in general, and nothing
+     ought to care.  Some things do care; the fault lies with them.  */
+  if (!CPP_OPTION (pfile, traditional))
+    {
+      print.printed = 1;
+      if (token->col > 2)
+       {
+         unsigned int spaces = token->col - 2;
+
+         while (spaces--)
+           putc (' ', print.outf);
+       }
+    }
+}
+
+static void
+cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line,
+         const cpp_string *str)
+{
+  maybe_print_line (print.map, line);
+  fprintf (print.outf, "#ident %s\n", str->text);
+  print.line++;
+}
+
+static void
+cb_define (cpp_reader *pfile, fileline line, cpp_hashnode *node)
+{
+  maybe_print_line (print.map, line);
+  fputs ("#define ", print.outf);
+
+  /* 'D' is whole definition; 'N' is name only.  */
+  if (flag_dump_macros == 'D')
+    fputs ((const char *) cpp_macro_definition (pfile, node),
+          print.outf);
+  else
+    fputs ((const char *) NODE_NAME (node), print.outf);
+
+  putc ('\n', print.outf);
+  print.line++;
+}
+
+static void
+cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line,
+         cpp_hashnode *node)
+{
+  maybe_print_line (print.map, line);
+  fprintf (print.outf, "#undef %s\n", NODE_NAME (node));
+  print.line++;
+}
+
+static void
+cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line,
+           const unsigned char *dir, const char *header, int angle_brackets)
+{
+  maybe_print_line (print.map, line);
+  if (angle_brackets)
+    fprintf (print.outf, "#%s <%s>\n", dir, header);
+  else
+    fprintf (print.outf, "#%s \"%s\"\n", dir, header);
+  print.line++;
+}
+
+/* Callback called when -fworking-director and -E to emit working
+   diretory in cpp output file. */
+
+void
+pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir)
+{
+  size_t to_file_len = strlen (dir);
+  unsigned char *to_file_quoted = alloca (to_file_len * 4 + 1);
+  unsigned char *p;
+
+  /* cpp_quote_string does not nul-terminate, so we have to do it ourselves. */
+  p = cpp_quote_string (to_file_quoted, (unsigned char *) dir, to_file_len);
+  *p = '\0';
+  fprintf (print.outf, "# 1 \"%s//\"\n", to_file_quoted);
+}
+
+/* The file name, line number or system header flags have changed, as
+   described in MAP.  From this point on, the old print.map might be
+   pointing to freed memory, and so must not be dereferenced.  */
+
+void
+pp_file_change (const struct line_map *map)
+{
+  const char *flags = "";
+
+  if (flag_no_line_commands)
+    return;
+
+  if (map != NULL)
+    {
+      /* First time?  */
+      if (print.map == NULL)
+       {
+         /* Avoid printing foo.i when the main file is foo.c.  */
+         if (!cpp_get_options (parse_in)->preprocessed)
+           print_line (map, map->from_line, flags);
+       }
+      else
+       {
+         /* Bring current file to correct line when entering a new file.  */
+         if (map->reason == LC_ENTER)
+           maybe_print_line (map - 1, map->from_line - 1);
+
+         if (map->reason == LC_ENTER)
+           flags = " 1";
+         else if (map->reason == LC_LEAVE)
+           flags = " 2";
+         print_line (map, map->from_line, flags);
+       }
+    }
+
+  print.map = map;
+}
+
+/* Copy a #pragma directive to the preprocessed output.  */
+static void
+cb_def_pragma (cpp_reader *pfile, fileline line)
+{
+  maybe_print_line (print.map, line);
+  fputs ("#pragma ", print.outf);
+  cpp_output_line (pfile, print.outf);
+  print.line++;
+}
+
+/* Dump out the hash table.  */
+static int
+dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED)
+{
+  if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
+    {
+      fputs ("#define ", print.outf);
+      fputs ((const char *) cpp_macro_definition (pfile, node),
+            print.outf);
+      putc ('\n', print.outf);
+      print.line++;
+    }
+
+  return 1;
+}
diff --git a/support/cpp2/c-pretty-print.c b/support/cpp2/c-pretty-print.c
new file mode 100644 (file)
index 0000000..f4b744e
--- /dev/null
@@ -0,0 +1,2154 @@
+/* Subroutines common to both C and C++ pretty-printers.
+   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "c-pretty-print.h"
+
+/* The pretty-printer code is primarily designed to closely follow
+   (GNU) C and C++ grammars.  That is to be contrasted with spaghetti
+   codes we used to have in the past.  Following a structured
+   approach (preferably the official grammars) is believed to make it
+   much easier to add extensions and nifty pretty-printing effects that
+   takes expression or declaration contexts into account.  */
+
+
+#define pp_c_maybe_whitespace(PP)            \
+   do {                                      \
+     if (pp_base (PP)->padding == pp_before) \
+       pp_c_whitespace (PP);                 \
+   } while (0)
+
+#define pp_c_left_bracket(PP)         \
+  do {                                \
+    pp_left_bracket (PP);             \
+    pp_base (PP)->padding = pp_none;  \
+  } while (0)
+
+#define pp_c_right_bracket(PP)        \
+  do {                                \
+    pp_right_bracket (PP);            \
+    pp_base (PP)->padding = pp_none;  \
+  } while (0)
+
+#define pp_c_star(PP)                 \
+  do {                                \
+    pp_star (PP);                     \
+    pp_base (PP)->padding = pp_none;  \
+  } while (0)
+
+/* literal  */
+static void pp_c_char (c_pretty_printer *, int);
+
+/* postfix-expression  */
+static void pp_c_initializer_list (c_pretty_printer *, tree);
+static void pp_c_brace_enclosed_initializer_list (c_pretty_printer *, tree);
+
+static void pp_c_multiplicative_expression (c_pretty_printer *, tree);
+static void pp_c_additive_expression (c_pretty_printer *, tree);
+static void pp_c_shift_expression (c_pretty_printer *, tree);
+static void pp_c_relational_expression (c_pretty_printer *, tree);
+static void pp_c_equality_expression (c_pretty_printer *, tree);
+static void pp_c_and_expression (c_pretty_printer *, tree);
+static void pp_c_exclusive_or_expression (c_pretty_printer *, tree);
+static void pp_c_inclusive_or_expression (c_pretty_printer *, tree);
+static void pp_c_logical_and_expression (c_pretty_printer *, tree);
+static void pp_c_conditional_expression (c_pretty_printer *, tree);
+static void pp_c_assignment_expression (c_pretty_printer *, tree);
+
+/* declarations.  */
+
+\f
+/* Helper functions.  */
+
+void
+pp_c_whitespace (c_pretty_printer *pp)
+{
+  pp_space (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_left_paren (c_pretty_printer *pp)
+{
+  pp_left_paren (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_right_paren (c_pretty_printer *pp)
+{
+  pp_right_paren (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_left_brace (c_pretty_printer *pp)
+{
+  pp_left_brace (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_right_brace (c_pretty_printer *pp)
+{
+  pp_right_brace (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_dot (c_pretty_printer *pp)
+{
+  pp_dot (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_ampersand (c_pretty_printer *pp)
+{
+  pp_ampersand (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_arrow (c_pretty_printer *pp)
+{
+  pp_arrow (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_semicolon(c_pretty_printer *pp)
+{
+  pp_semicolon (pp);
+  pp_base (pp)->padding = pp_none;
+}
+
+static void
+pp_c_cv_qualifier (c_pretty_printer *pp, const char *cv)
+{
+  const char *p = pp_last_position_in_text (pp);
+  if (p != NULL && *p == '*')
+    pp_c_whitespace (pp);
+  pp_c_identifier (pp, cv);
+}
+
+/* Pretty-print T using the type-cast notation '( type-name )'.  */
+
+static void
+pp_c_type_cast (c_pretty_printer *pp, tree t)
+{
+  pp_c_left_paren (pp);
+  pp_type_id (pp, t);
+  pp_c_right_paren (pp);
+}
+
+void
+pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t)
+{
+  if (POINTER_TYPE_P (t))
+    {
+      tree pointee = strip_pointer_operator (TREE_TYPE (t));
+      if (TREE_CODE (pointee) != ARRAY_TYPE
+          && TREE_CODE (pointee) != FUNCTION_TYPE)
+        pp_c_whitespace (pp);
+    }
+}
+
+\f
+/* Declarations.  */
+
+/* C++ cv-qualifiers are called type-qualifiers in C.  Print out the
+   cv-qualifiers of T.  If T is a declaration then it is the cv-qualifier
+   of its type.  Take care of possible extensions.
+
+   type-qualifier-list:
+       type-qualifier
+       type-qualifier-list type-qualifier
+
+   type-qualifier:
+       const
+       restrict                              -- C99
+       __restrict__                          -- GNU C
+       volatile    */
+
+void
+pp_c_type_qualifier_list (c_pretty_printer *pp, tree t)
+{
+   int qualifiers;
+   
+  if (!TYPE_P (t))
+    t = TREE_TYPE (t);
+
+  qualifiers = TYPE_QUALS (t);
+  if (qualifiers & TYPE_QUAL_CONST)
+    pp_c_cv_qualifier (pp, "const");
+  if (qualifiers & TYPE_QUAL_VOLATILE)
+    pp_c_cv_qualifier (pp, "volatile");
+  if (qualifiers & TYPE_QUAL_RESTRICT)
+    pp_c_cv_qualifier (pp, flag_isoc99 ? "restrict" : "__restrict__");
+}
+
+/* pointer:
+      * type-qualifier-list(opt)
+      * type-qualifier-list(opt) pointer  */
+
+static void
+pp_c_pointer (c_pretty_printer *pp, tree t)
+{
+  if (!TYPE_P (t) && TREE_CODE (t) != TYPE_DECL)
+    t = TREE_TYPE (t);
+  switch (TREE_CODE (t))
+    {
+    case POINTER_TYPE:
+      /* It is easier to handle C++ reference types here.  */
+    case REFERENCE_TYPE:
+      if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
+        pp_c_pointer (pp, TREE_TYPE (t));
+      if (TREE_CODE (t) == POINTER_TYPE)
+        pp_c_star (pp);
+      else
+        pp_c_ampersand (pp);
+      pp_c_type_qualifier_list (pp, t);
+      break;
+
+    default:
+      pp_unsupported_tree (pp, t);
+    }
+}
+
+/* type-specifier:
+      void
+      char
+      short
+      int
+      long
+      float
+      double
+      signed
+      unsigned
+      _Bool                          -- C99
+      _Complex                       -- C99
+      _Imaginary                     -- C99
+      struct-or-union-specifier
+      enum-specifier
+      typedef-name.
+
+  GNU extensions.
+  simple-type-specifier:
+      __complex__
+      __vector__   */
+
+void
+pp_c_type_specifier (c_pretty_printer *pp, tree t)
+{
+  const enum tree_code code = TREE_CODE (t);
+  switch (code)
+    {
+    case ERROR_MARK:
+      pp_c_identifier (pp, "<type-error>");
+      break;
+
+    case IDENTIFIER_NODE:
+      pp_c_tree_identifier (pp, t);
+      break;
+
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+    case CHAR_TYPE:
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+      if (TYPE_NAME (t))
+        t = TYPE_NAME (t);
+      else
+        t = c_common_type_for_mode (TYPE_MODE (t), TREE_UNSIGNED (t));
+      pp_c_type_specifier (pp, t);
+      break;
+
+    case TYPE_DECL:
+      if (DECL_NAME (t))
+       pp_id_expression (pp, t);
+      else
+       pp_c_identifier (pp, "<typedef-error>");
+      break;
+
+    case UNION_TYPE:
+    case RECORD_TYPE:
+    case ENUMERAL_TYPE:
+      if (code == UNION_TYPE)
+       pp_c_identifier (pp, "union");
+      else if (code == RECORD_TYPE)
+       pp_c_identifier (pp, "struct");
+      else if (code == ENUMERAL_TYPE)
+       pp_c_identifier (pp, "enum");
+      else
+       pp_c_identifier (pp, "<tag-error>");
+
+      if (TYPE_NAME (t))
+       pp_id_expression (pp, TYPE_NAME (t));
+      else
+       pp_c_identifier (pp, "<anonymous>");
+      break;
+
+    default:
+      pp_unsupported_tree (pp, t);
+      break;
+    }
+}
+
+/* specifier-qualifier-list:
+      type-specifier specifier-qualifier-list-opt
+      type-qualifier specifier-qualifier-list-opt
+
+
+  Implementation note:  Because of the non-linearities in array or
+  function declarations, this routine prints not just the
+  specifier-qualifier-list of such entities or types of such entities,
+  but also the 'pointer' production part of their declarators.  The
+  remaining part is done by pp_declarator or pp_c_abstract_declarator.  */
+
+void
+pp_c_specifier_qualifier_list (c_pretty_printer *pp, tree t)
+{
+  const enum tree_code code = TREE_CODE (t);
+
+  if (TREE_CODE (t) != POINTER_TYPE)
+    pp_c_type_qualifier_list (pp, t);
+  switch (code)
+    {
+    case REFERENCE_TYPE:
+    case POINTER_TYPE:
+      {
+        /* Get the types-specifier of this type.  */
+        tree pointee = strip_pointer_operator (TREE_TYPE (t));
+        pp_c_specifier_qualifier_list (pp, pointee);
+        if (TREE_CODE (pointee) == ARRAY_TYPE
+            || TREE_CODE (pointee) == FUNCTION_TYPE)
+          {
+            pp_c_whitespace (pp);
+            pp_c_left_paren (pp);
+          }
+        pp_ptr_operator (pp, t);
+      }
+      break;
+
+    case FUNCTION_TYPE:
+    case ARRAY_TYPE:
+      pp_c_specifier_qualifier_list (pp, TREE_TYPE (t));
+      break;
+
+    case VECTOR_TYPE:
+    case COMPLEX_TYPE:
+      pp_c_specifier_qualifier_list (pp, TREE_TYPE (t));
+      if (code == COMPLEX_TYPE)
+        pp_c_identifier (pp, flag_isoc99 ? "_Complex" : "__complex__");
+      else if (code == VECTOR_TYPE)
+        pp_c_identifier (pp, "__vector__");
+      break;
+
+    default:
+      pp_simple_type_specifier (pp, t);
+      break;
+    }
+}
+
+/* parameter-type-list:
+      parameter-list
+      parameter-list , ...
+
+   parameter-list:
+      parameter-declaration
+      parameter-list , parameter-declaration
+
+   parameter-declaration:
+      declaration-specifiers declarator
+      declaration-specifiers abstract-declarator(opt)   */
+
+void
+pp_c_parameter_type_list (c_pretty_printer *pp, tree t)
+{
+  bool want_parm_decl = DECL_P (t) && !(pp->flags & pp_c_flag_abstract);
+  tree parms = want_parm_decl ? DECL_ARGUMENTS (t) :  TYPE_ARG_TYPES (t);
+  pp_c_left_paren (pp);
+  if (parms == void_list_node)
+    pp_c_identifier (pp, "void");
+  else
+    {
+      bool first = true;
+      for ( ; parms && parms != void_list_node; parms = TREE_CHAIN (parms))
+        {
+          if (!first)
+            pp_separate_with (pp, ',');
+          first = false;
+          pp_declaration_specifiers
+            (pp, want_parm_decl ? parms : TREE_VALUE (parms));
+          if (want_parm_decl)
+            pp_declarator (pp, parms);
+          else
+            pp_abstract_declarator (pp, TREE_VALUE (parms));
+        }
+    }
+  pp_c_right_paren (pp);
+}
+
+/* abstract-declarator:
+      pointer
+      pointer(opt) direct-abstract-declarator  */
+
+static void
+pp_c_abstract_declarator (c_pretty_printer *pp, tree t)
+{
+  if (TREE_CODE (t) == POINTER_TYPE)
+    {
+      if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
+          || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
+        pp_c_right_paren (pp);
+      t = TREE_TYPE (t);
+    }
+
+  pp_direct_abstract_declarator (pp, t);
+}
+
+/* direct-abstract-declarator:
+      ( abstract-declarator )
+      direct-abstract-declarator(opt) [ assignment-expression(opt) ]
+      direct-abstract-declarator(opt) [ * ]
+      direct-abstract-declarator(opt) ( parameter-type-list(opt) )  */
+
+void
+pp_c_direct_abstract_declarator (c_pretty_printer *pp, tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case POINTER_TYPE:
+      pp_abstract_declarator (pp, t);
+      break;
+      
+    case FUNCTION_TYPE:
+      pp_c_parameter_type_list (pp, t);
+      pp_direct_abstract_declarator (pp, TREE_TYPE (t));
+      break;
+
+    case ARRAY_TYPE:
+      pp_c_left_bracket (pp);
+      if (TYPE_DOMAIN (t))
+        pp_expression (pp, TYPE_MAX_VALUE (TYPE_DOMAIN (t)));
+      pp_c_right_bracket (pp);
+      pp_direct_abstract_declarator (pp, TREE_TYPE (t));
+      break;
+
+    case IDENTIFIER_NODE:
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case ENUMERAL_TYPE:
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case VECTOR_TYPE:
+    case COMPLEX_TYPE:
+    case TYPE_DECL:
+      break;
+      
+    default:
+      pp_unsupported_tree (pp, t);
+      break;
+    }
+}
+
+/* type-name:
+      specifier-qualifier-list  abstract-declarator(opt)  */
+
+void
+pp_c_type_id (c_pretty_printer *pp, tree t)
+{
+  pp_c_specifier_qualifier_list (pp, t);
+  pp_abstract_declarator (pp, t);
+}
+
+/* storage-class-specifier:
+      typedef
+      extern
+      static
+      auto
+      register  */
+
+void
+pp_c_storage_class_specifier (c_pretty_printer *pp, tree t)
+{
+  if (TREE_CODE (t) == TYPE_DECL)
+    pp_c_identifier (pp, "typedef");
+  else if (DECL_P (t))
+    {
+      if (DECL_REGISTER (t))
+        pp_c_identifier (pp, "register");
+      else if (TREE_STATIC (t) && TREE_CODE (t) == VAR_DECL)
+        pp_c_identifier (pp, "static");
+    }
+}
+
+/* function-specifier:
+      inline   */
+
+void
+pp_c_function_specifier (c_pretty_printer *pp, tree t)
+{
+  if (TREE_CODE (t) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (t))
+    pp_c_identifier (pp, "inline");
+}
+
+/* declaration-specifiers:
+      storage-class-specifier declaration-specifiers(opt)
+      type-specifier declaration-specifiers(opt)
+      type-qualifier declaration-specifiers(opt)
+      function-specifier declaration-specifiers(opt)  */
+
+void
+pp_c_declaration_specifiers (c_pretty_printer *pp, tree t)
+{
+  pp_storage_class_specifier (pp, t);
+  pp_function_specifier (pp, t);
+  pp_c_specifier_qualifier_list (pp, DECL_P (t) ?  TREE_TYPE (t) : t);
+}
+
+/* direct-declarator
+      identifier
+      ( declarator )
+      direct-declarator [ type-qualifier-list(opt) assignment-expression(opt) ]
+      direct-declarator [ static type-qualifier-list(opt) assignment-expression(opt)]
+      direct-declarator [ type-qualifier-list static assignment-expression ]
+      direct-declarator [ type-qualifier-list * ]
+      direct-declaratpr ( parameter-type-list )
+      direct-declarator ( identifier-list(opt) )  */
+
+void
+pp_c_direct_declarator (c_pretty_printer *pp, tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+    case TYPE_DECL:
+    case FIELD_DECL:
+    case LABEL_DECL:
+      if (DECL_NAME (t))
+        {
+          pp_c_space_for_pointer_operator (pp, TREE_TYPE (t));
+          pp_c_tree_identifier (pp, DECL_NAME (t));
+        }
+    case ARRAY_TYPE:
+    case POINTER_TYPE:
+      pp_abstract_declarator (pp, TREE_TYPE (t));
+      break;
+
+    case FUNCTION_TYPE:
+      pp_parameter_list (pp, t);
+      pp_abstract_declarator (pp, TREE_TYPE (t));
+      break;
+
+    case FUNCTION_DECL:
+      pp_c_space_for_pointer_operator (pp, TREE_TYPE (TREE_TYPE (t)));
+      pp_c_tree_identifier (pp, DECL_NAME (t));
+      if (pp_c_base (pp)->flags & pp_c_flag_abstract)
+        pp_abstract_declarator (pp, TREE_TYPE (t));
+      else
+        {
+          pp_parameter_list (pp, t);
+          pp_abstract_declarator (pp, TREE_TYPE (TREE_TYPE (t)));
+        }
+      break;
+
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case ENUMERAL_TYPE:
+    case UNION_TYPE:
+    case RECORD_TYPE:
+      break;
+
+    default:
+      pp_unsupported_tree (pp, t);
+      break;
+    }
+}
+
+
+/* declarator:
+      pointer(opt)  direct-declarator   */
+
+void
+pp_c_declarator (c_pretty_printer *pp, tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case ENUMERAL_TYPE:
+    case UNION_TYPE:
+    case RECORD_TYPE:
+      break;
+
+    case VAR_DECL:
+    case PARM_DECL:
+    case FIELD_DECL:
+    case ARRAY_TYPE:
+    case FUNCTION_TYPE:
+    case FUNCTION_DECL:
+    case TYPE_DECL:
+      pp_direct_declarator (pp, t);
+    break;
+
+    
+    default:
+      pp_unsupported_tree (pp, t);
+      break;
+    }
+}
+
+/* declaration:
+      declaration-specifiers init-declarator-list(opt) ;  */
+
+void
+pp_c_declaration (c_pretty_printer *pp, tree t)
+{
+  pp_declaration_specifiers (pp, t);
+  pp_c_init_declarator (pp, t);
+}
+
+/* Pretty-print ATTRIBUTES using GNU C extension syntax.  */
+
+void
+pp_c_attributes (c_pretty_printer *pp, tree attributes)
+{
+  if (attributes == NULL_TREE)
+    return;
+
+  pp_c_identifier (pp, "__attribute__");
+  pp_c_left_paren (pp);
+  pp_c_left_paren (pp);
+  for (; attributes != NULL_TREE; attributes = TREE_CHAIN (attributes))
+    {
+      pp_tree_identifier (pp, TREE_PURPOSE (attributes));
+      if (TREE_VALUE (attributes))
+        pp_c_call_argument_list (pp, TREE_VALUE (attributes));
+
+      if (TREE_CHAIN (attributes))
+       pp_separate_with (pp, ',');
+    }
+  pp_c_right_paren (pp);
+  pp_c_right_paren (pp);
+}
+
+/* function-definition:
+      declaration-specifiers declarator compound-statement  */
+
+void
+pp_c_function_definition (c_pretty_printer *pp, tree t)
+{
+  pp_declaration_specifiers (pp, t);
+  pp_declarator (pp, t);
+  pp_needs_newline (pp) = true;
+  pp_statement (pp, DECL_SAVED_TREE (t));
+  pp_newline (pp);
+  pp_flush (pp);
+}
+
+\f
+/* Expressions.  */
+
+/* Print out a c-char.  */
+
+static void
+pp_c_char (c_pretty_printer *pp, int c)
+{
+  switch (c)
+    {
+    case TARGET_NEWLINE:
+      pp_string (pp, "\\n");
+      break;
+    case TARGET_TAB:
+      pp_string (pp, "\\t");
+      break;
+    case TARGET_VT:
+      pp_string (pp, "\\v");
+      break;
+    case TARGET_BS:
+      pp_string (pp, "\\b");
+      break;
+    case TARGET_CR:
+      pp_string (pp, "\\r");
+      break;
+    case TARGET_FF:
+      pp_string (pp, "\\f");
+      break;
+    case TARGET_BELL:
+      pp_string (pp, "\\a");
+      break;
+    case '\\':
+      pp_string (pp, "\\\\");
+      break;
+    case '\'':
+      pp_string (pp, "\\'");
+      break;
+    case '\"':
+      pp_string (pp, "\\\"");
+      break;
+    default:
+      if (ISPRINT (c))
+       pp_character (pp, c);
+      else
+       pp_scalar (pp, "\\%03o", (unsigned) c);
+      break;
+    }
+}
+
+/* Print out a STRING literal.  */
+
+void
+pp_c_string_literal (c_pretty_printer *pp, tree s)
+{
+  const char *p = TREE_STRING_POINTER (s);
+  int n = TREE_STRING_LENGTH (s) - 1;
+  int i;
+  pp_doublequote (pp);
+  for (i = 0; i < n; ++i)
+    pp_c_char (pp, p[i]);
+  pp_doublequote (pp);
+}
+
+static void
+pp_c_integer_constant (c_pretty_printer *pp, tree i)
+{
+  tree type = TREE_TYPE (i);
+
+  if (TREE_INT_CST_HIGH (i) == 0)
+    pp_wide_integer (pp, TREE_INT_CST_LOW (i));
+  else
+    {
+      if (tree_int_cst_sgn (i) < 0)
+        {
+          pp_c_char (pp, '-');
+          i = build_int_2 (-TREE_INT_CST_LOW (i),
+                           ~TREE_INT_CST_HIGH (i) + !TREE_INT_CST_LOW (i));
+        }
+      sprintf (pp_buffer (pp)->digit_buffer,
+               HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+               TREE_INT_CST_HIGH (i), TREE_INT_CST_LOW (i));
+      pp_string (pp, pp_buffer (pp)->digit_buffer);
+    }
+  if (TREE_UNSIGNED (type))
+    pp_character (pp, 'u');
+  if (type == long_integer_type_node || type == long_unsigned_type_node)
+    pp_character (pp, 'l');
+  else if (type == long_long_integer_type_node
+           || type == long_long_unsigned_type_node)
+    pp_string (pp, "ll");
+}
+
+/* Print out a CHARACTER literal.  */
+
+static void
+pp_c_character_constant (c_pretty_printer *pp, tree c)
+{
+  tree type = TREE_TYPE (c);
+  if (type == wchar_type_node)
+    pp_character (pp, 'L'); 
+  pp_quote (pp);
+  if (host_integerp (c, TREE_UNSIGNED (type)))
+    pp_c_char (pp, tree_low_cst (c, TREE_UNSIGNED (type)));
+  else
+    pp_scalar (pp, "\\x%x", (unsigned) TREE_INT_CST_LOW (c));
+  pp_quote (pp);
+}
+
+/* Print out a BOOLEAN literal.  */
+
+static void
+pp_c_bool_constant (c_pretty_printer *pp, tree b)
+{
+  if (b == boolean_false_node)
+    {
+      if (c_dialect_cxx ())
+       pp_c_identifier (pp, "false");
+      else if (flag_isoc99)
+       pp_c_identifier (pp, "_False");
+      else
+       pp_unsupported_tree (pp, b);
+    }
+  else if (b == boolean_true_node)
+    {
+      if (c_dialect_cxx ())
+       pp_c_identifier (pp, "true");
+      else if (flag_isoc99)
+       pp_c_identifier (pp, "_True");
+      else
+       pp_unsupported_tree (pp, b);
+    }
+  else if (TREE_CODE (b) == INTEGER_CST)
+    pp_c_integer_constant (pp, b);
+  else
+    pp_unsupported_tree (pp, b);
+}
+
+/* Attempt to print out an ENUMERATOR.  Return true on success.  Else return
+   false; that means the value was obtained by a cast, in which case
+   print out the type-id part of the cast-expression -- the casted value
+   is then printed by pp_c_integer_literal.  */
+
+static bool
+pp_c_enumeration_constant (c_pretty_printer *pp, tree e)
+{
+  bool value_is_named = true;
+  tree type = TREE_TYPE (e);
+  tree value;
+
+  /* Find the name of this constant.  */
+  for (value = TYPE_VALUES (type);
+       value != NULL_TREE && !tree_int_cst_equal (TREE_VALUE (value), e);
+       value = TREE_CHAIN (value))
+    ;
+
+  if (value != NULL_TREE)
+    pp_id_expression (pp, TREE_PURPOSE (value));
+  else
+    {
+      /* Value must have been cast.  */
+      pp_c_type_cast (pp, type);
+      value_is_named = false;
+    }
+
+  return value_is_named;
+}
+
+/* Print out a REAL value as a decimal-floating-constant.  */
+
+static void
+pp_c_floating_constant (c_pretty_printer *pp, tree r)
+{
+  real_to_decimal (pp_buffer (pp)->digit_buffer, &TREE_REAL_CST (r),
+                  sizeof (pp_buffer (pp)->digit_buffer), 0, 1);
+  pp_string (pp, pp_buffer(pp)->digit_buffer);
+  if (TREE_TYPE (r) == float_type_node)
+    pp_character (pp, 'f');
+  else if (TREE_TYPE (r) == long_double_type_node)
+    pp_character (pp, 'l');
+}
+
+/* Pretty-print a compound literal expression.  GNU extensions include
+   vector constants.  */ 
+
+static void
+pp_c_compound_literal (c_pretty_printer *pp, tree e)
+{
+  tree type = TREE_TYPE (e);  
+  pp_c_type_cast (pp, type);
+
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case ARRAY_TYPE:
+    case VECTOR_TYPE:
+    case COMPLEX_TYPE:
+      pp_c_brace_enclosed_initializer_list (pp, e);
+      break;
+
+    default:
+      pp_unsupported_tree (pp, e);
+      break;
+    }
+}
+
+/* constant:
+      integer-constant
+      floating-constant
+      enumeration-constant
+      character-constant   */
+
+void
+pp_c_constant (c_pretty_printer *pp, tree e)
+{
+  const enum tree_code code = TREE_CODE (e);
+
+  switch (code)
+    {
+    case INTEGER_CST:
+      {
+        tree type = TREE_TYPE (e);
+        if (type == boolean_type_node)
+          pp_c_bool_constant (pp, e);
+        else if (type == char_type_node)
+          pp_c_character_constant (pp, e);
+        else if (TREE_CODE (type) == ENUMERAL_TYPE
+                 && pp_c_enumeration_constant (pp, e))
+          ; 
+        else 
+          pp_c_integer_constant (pp, e);
+      }
+      break;
+
+    case REAL_CST:
+      pp_c_floating_constant (pp, e);
+      break;
+
+    case STRING_CST:
+      pp_c_string_literal (pp, e);
+      break;
+
+    default:
+      pp_unsupported_tree (pp, e);
+      break;
+    }
+}
+
+void
+pp_c_identifier (c_pretty_printer *pp, const char *id)
+{
+  pp_c_maybe_whitespace (pp);            
+  pp_identifier (pp, id);  
+  pp_base (pp)->padding = pp_before;
+}
+
+/* Pretty-print a C primary-expression.
+   primary-expression:
+      identifier
+      constant
+      string-literal
+      ( expression )   */
+
+void
+pp_c_primary_expression (c_pretty_printer *pp, tree e)
+{
+  switch (TREE_CODE (e))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+    case FIELD_DECL:
+    case CONST_DECL:
+    case FUNCTION_DECL:
+    case LABEL_DECL:
+      e = DECL_NAME (e);
+      /* Fall through.  */
+    case IDENTIFIER_NODE:
+      pp_c_tree_identifier (pp, e);
+      break;
+
+    case ERROR_MARK:
+      pp_c_identifier (pp, "<erroneous-expression>");
+      break;
+
+    case RESULT_DECL:
+      pp_c_identifier (pp, "<return-value>");
+      break;
+
+    case INTEGER_CST:
+    case REAL_CST:
+    case STRING_CST:
+      pp_c_constant (pp, e);
+      break;
+
+    case STMT_EXPR:
+      pp_c_left_paren (pp);
+      pp_statement (pp, STMT_EXPR_STMT (e));
+      pp_c_right_paren (pp);
+      break;
+
+    default:
+      /* FIXME:  Make sure we won't get into an infinie loop.  */
+      pp_c_left_paren (pp);
+      pp_expression (pp, e);
+      pp_c_right_paren (pp);
+      break;
+    }
+}
+
+/* Print out a C initializer -- also support C compound-literals.
+   initializer:
+      assignment-expression:
+      { initializer-list }
+      { initializer-list , }   */
+
+static void
+pp_c_initializer (c_pretty_printer *pp, tree e)
+{
+  if (TREE_CODE (e) == CONSTRUCTOR)
+    {
+      enum tree_code code = TREE_CODE (TREE_TYPE (e));
+      if (code == RECORD_TYPE || code == UNION_TYPE || code == ARRAY_TYPE)
+        pp_c_brace_enclosed_initializer_list (pp, e);
+      else
+       pp_unsupported_tree (pp, TREE_OPERAND (e, 1));
+    }
+  else
+    pp_expression (pp, e);
+}
+
+/* init-declarator:
+      declarator:
+      declarator = initializer   */
+
+void
+pp_c_init_declarator (c_pretty_printer *pp, tree t)
+{
+  pp_declarator (pp, t);
+  if (DECL_INITIAL (t))
+    {
+      tree init = DECL_INITIAL (t);
+      /* This C++ bit is handled here because it is easier to do so.
+         In templates, the C++ parser builds a TREE_LIST for a
+         direct-initialization; the TREE_PURPOSE is the variable to
+         initialize and the TREE_VALUE is the initializer.  */
+      if (TREE_CODE (init) == TREE_LIST)
+        {
+          pp_c_left_paren (pp);
+          pp_expression (pp, TREE_VALUE (init));
+          pp_right_paren (pp);
+        }
+      else
+        {
+          pp_space (pp);
+          pp_equal (pp);
+          pp_space (pp);
+          pp_c_initializer (pp, init);
+        }
+    }
+}
+
+/* initializer-list:
+      designation(opt) initializer
+      initializer-list , designation(opt) initializer
+
+   designation:
+      designator-list =
+
+   designator-list:
+      designator
+      designator-list designator
+
+   designator:
+      [ constant-expression ]
+      identifier   */
+
+static void
+pp_c_initializer_list (c_pretty_printer *pp, tree e)
+{
+  tree type = TREE_TYPE (e);
+  const enum tree_code code = TREE_CODE (type);
+
+  switch (code)
+    {
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case ARRAY_TYPE:
+      {
+        tree init = TREE_OPERAND (e, 0);
+        for (; init != NULL_TREE; init = TREE_CHAIN (init))
+          {
+            if (code == RECORD_TYPE || code == UNION_TYPE)
+              {
+                pp_c_dot (pp);
+                pp_c_primary_expression (pp, TREE_PURPOSE (init));
+              }
+            else
+              {
+                pp_c_left_bracket (pp);
+                if (TREE_PURPOSE (init))
+                  pp_c_constant (pp, TREE_PURPOSE (init));
+                pp_c_right_bracket (pp);
+              }
+            pp_c_whitespace (pp);
+            pp_equal (pp);
+            pp_c_whitespace (pp);
+            pp_initializer (pp, TREE_VALUE (init));
+            if (TREE_CHAIN (init))
+              pp_separate_with (pp, ',');
+          }
+      }
+      break;
+
+    case VECTOR_TYPE:
+      pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e));
+      break;
+
+    case COMPLEX_TYPE:
+      {
+        const bool cst = TREE_CODE (e) == COMPLEX_CST;
+        pp_expression (pp, cst ? TREE_REALPART (e) : TREE_OPERAND (e, 0));
+        pp_separate_with (pp, ',');
+        pp_expression (pp, cst ? TREE_IMAGPART (e) : TREE_OPERAND (e, 1));
+      }
+      break;
+
+    default:
+      pp_unsupported_tree (pp, type);
+      break;
+    }
+}
+
+/* Pretty-print a brace-enclosed initializer-list.  */
+
+static void
+pp_c_brace_enclosed_initializer_list (c_pretty_printer *pp, tree l)
+{
+  pp_c_left_brace (pp);
+  pp_c_initializer_list (pp, l);
+  pp_c_right_brace (pp);
+}
+
+
+/*  This is a convenient function, used to bridge gap between C and C++
+    grammars.
+
+    id-expression:
+       identifier  */
+
+void
+pp_c_id_expression (c_pretty_printer *pp, tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+    case CONST_DECL:
+    case TYPE_DECL:
+    case FUNCTION_DECL:
+    case FIELD_DECL:
+    case LABEL_DECL:
+      t = DECL_NAME (t);
+    case IDENTIFIER_NODE:
+      pp_c_tree_identifier (pp, t);
+      break;
+
+    default:
+      pp_unsupported_tree (pp, t);
+      break;
+    }
+}
+
+/* postfix-expression:
+      primary-expression
+      postfix-expression [ expression ]
+      postfix-expression ( argument-expression-list(opt) )
+      postfix-expression . identifier
+      postfix-expression -> identifier
+      postfix-expression ++
+      postfix-expression --
+      ( type-name ) { initializer-list }
+      ( type-name ) { initializer-list , }  */
+
+void
+pp_c_postfix_expression (c_pretty_printer *pp, tree e)
+{
+  enum tree_code code = TREE_CODE (e);
+  switch (code)
+    {
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      pp_postfix_expression (pp, TREE_OPERAND (e, 0));
+      pp_identifier (pp, code == POSTINCREMENT_EXPR ? "++" : "--");
+      break;
+
+    case ARROW_EXPR:
+      pp_postfix_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_arrow (pp);
+      break;
+
+    case ARRAY_REF:
+      pp_postfix_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_left_bracket (pp);
+      pp_expression (pp, TREE_OPERAND (e, 1));
+      pp_c_right_bracket (pp);
+      break;
+
+    case CALL_EXPR:
+      pp_postfix_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_call_argument_list (pp, TREE_OPERAND (e, 1));
+      break;
+
+    case ABS_EXPR:
+      pp_c_identifier (pp, "__builtin_abs");
+      pp_c_left_paren (pp);
+      pp_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_right_paren (pp);
+      break;
+
+    case COMPONENT_REF:
+      {
+       tree object = TREE_OPERAND (e, 0);
+       if (TREE_CODE (object) == INDIRECT_REF)
+         {
+           pp_postfix_expression (pp, TREE_OPERAND (object, 0));
+           pp_c_arrow (pp);
+         }
+       else
+         {
+           pp_postfix_expression (pp, object);
+           pp_c_dot (pp);
+         }
+       pp_expression (pp, TREE_OPERAND (e, 1));
+      }
+      break;
+
+    case COMPLEX_CST:
+    case VECTOR_CST:
+    case COMPLEX_EXPR:
+      pp_c_compound_literal (pp, e);
+      break;
+
+    case COMPOUND_LITERAL_EXPR:
+      e = DECL_INITIAL (COMPOUND_LITERAL_EXPR_DECL (e));
+      /* Fall through.  */
+    case CONSTRUCTOR:
+      pp_initializer (pp, e);
+      break;
+
+    case VA_ARG_EXPR:
+      pp_c_identifier (pp, "__builtin_va_arg");
+      pp_c_left_paren (pp);
+      pp_assignment_expression (pp, TREE_OPERAND (e, 0));
+      pp_separate_with (pp, ',');
+      pp_type_id (pp, TREE_TYPE (e));
+      pp_c_right_paren (pp);
+      break;
+
+    case ADDR_EXPR:
+      if (TREE_CODE (TREE_OPERAND (e, 0)) == FUNCTION_DECL)
+        {
+          pp_c_id_expression (pp, TREE_OPERAND (e, 0));
+          break;
+        }
+      /* else fall through.  */
+
+    default:
+      pp_primary_expression (pp, e);
+      break;
+    }
+}
+
+/* Print out an expression-list; E is expected to be a TREE_LIST.  */
+
+void
+pp_c_expression_list (c_pretty_printer *pp, tree e)
+{
+  for (; e != NULL_TREE; e = TREE_CHAIN (e))
+    {
+      pp_expression (pp, TREE_VALUE (e));
+      if (TREE_CHAIN (e))
+       pp_separate_with (pp, ',');
+    }
+}
+
+/* Print out an expression-list in parens, as in a function call.  */
+
+void
+pp_c_call_argument_list (c_pretty_printer *pp, tree t)
+{
+  pp_c_left_paren (pp);
+  if (t && TREE_CODE (t) == TREE_LIST)
+    pp_c_expression_list (pp, t);
+  pp_c_right_paren (pp);
+}
+
+/* unary-expression:
+      postfix-expression
+      ++ cast-expression
+      -- cast-expression
+      unary-operator cast-expression
+      sizeof unary-expression
+      sizeof ( type-id )
+
+  unary-operator: one of
+      * &  + - ! ~
+      
+   GNU extensions.
+   unary-expression:
+      __alignof__ unary-expression
+      __alignof__ ( type-id )
+      __real__ unary-expression
+      __imag__ unary-expression  */
+
+void
+pp_c_unary_expression (c_pretty_printer *pp, tree e)
+{
+  enum tree_code code = TREE_CODE (e);
+  switch (code)
+    {
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+      pp_identifier (pp, code == PREINCREMENT_EXPR ? "++" : "--");
+      pp_c_unary_expression (pp, TREE_OPERAND (e, 0));
+      break;
+
+    case ADDR_EXPR:
+    case INDIRECT_REF:
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case CONJ_EXPR:
+      /* String literal are used by address.  */
+      if (code == ADDR_EXPR && TREE_CODE (TREE_OPERAND (e, 0)) != STRING_CST)
+       pp_ampersand (pp);
+      else if (code == INDIRECT_REF)
+       pp_c_star (pp);
+      else if (code == NEGATE_EXPR)
+       pp_minus (pp);
+      else if (code == BIT_NOT_EXPR || code == CONJ_EXPR)
+       pp_complement (pp);
+      else if (code == TRUTH_NOT_EXPR)
+       pp_exclamation (pp);
+      pp_c_cast_expression (pp, TREE_OPERAND (e, 0));
+      break;
+
+    case SIZEOF_EXPR:
+    case ALIGNOF_EXPR:
+      pp_c_identifier (pp, code == SIZEOF_EXPR ? "sizeof" : "__alignof__");
+      pp_c_whitespace (pp);
+      if (TYPE_P (TREE_OPERAND (e, 0)))
+        pp_c_type_cast (pp, TREE_OPERAND (e, 0));
+      else
+       pp_unary_expression (pp, TREE_OPERAND (e, 0));
+      break;
+
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+      pp_c_identifier (pp, code == REALPART_EXPR ? "__real__" : "__imag__");
+      pp_c_whitespace (pp);
+      pp_unary_expression (pp, TREE_OPERAND (e, 0));
+      break;
+
+    default:
+      pp_postfix_expression (pp, e);
+      break;
+    }
+}
+
+/* cast-expression:
+      unary-expression
+      ( type-name ) cast-expression  */
+
+void
+pp_c_cast_expression (c_pretty_printer *pp, tree e)
+{
+  switch (TREE_CODE (e))
+    {
+    case FLOAT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case CONVERT_EXPR:
+      pp_c_type_cast (pp, TREE_TYPE (e));
+      pp_c_cast_expression (pp, TREE_OPERAND (e, 0));
+      break;
+
+    default:
+      pp_unary_expression (pp, e);
+    }
+}
+
+/* multiplicative-expression:
+      cast-expression
+      multiplicative-expression * cast-expression
+      multiplicative-expression / cast-expression
+      multiplicative-expression % cast-expression   */
+
+static void
+pp_c_multiplicative_expression (c_pretty_printer *pp, tree e)
+{
+  enum tree_code code = TREE_CODE (e);
+  switch (code)
+    {
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+      pp_multiplicative_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      if (code == MULT_EXPR)
+       pp_c_star (pp);
+      else if (code == TRUNC_DIV_EXPR)
+       pp_slash (pp);
+      else
+       pp_modulo (pp);
+      pp_c_whitespace (pp);
+      pp_c_cast_expression (pp, TREE_OPERAND (e, 1));
+      break;
+
+    default:
+      pp_c_cast_expression (pp, e);
+      break;
+    }
+}
+
+/* additive-expression:
+      multiplicative-expression
+      additive-expression + multiplicative-expression
+      additive-expression - multiplicative-expression   */
+
+static void
+pp_c_additive_expression (c_pretty_printer *pp, tree e)
+{
+  enum tree_code code = TREE_CODE (e);
+  switch (code)
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      pp_c_additive_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      if (code == PLUS_EXPR)
+       pp_plus (pp);
+      else
+       pp_minus (pp);
+      pp_c_whitespace (pp);
+      pp_multiplicative_expression (pp, TREE_OPERAND (e, 1)); 
+      break;
+
+    default:
+      pp_multiplicative_expression (pp, e);
+      break;
+    }
+}
+
+/* additive-expression:
+      additive-expression
+      shift-expression << additive-expression
+      shift-expression >> additive-expression   */
+
+static void
+pp_c_shift_expression (c_pretty_printer *pp, tree e)
+{
+  enum tree_code code = TREE_CODE (e);
+  switch (code)
+    {
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+      pp_c_shift_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      pp_identifier (pp, code == LSHIFT_EXPR ? "<<" : ">>");
+      pp_c_whitespace (pp);
+      pp_c_additive_expression (pp, TREE_OPERAND (e, 1));
+      break;
+
+    default:
+      pp_c_additive_expression (pp, e);
+    }
+}
+
+/* relational-expression:
+      shift-expression
+      relational-expression < shift-expression
+      relational-expression > shift-expression
+      relational-expression <= shift-expression
+      relational-expression >= shift-expression   */
+
+static void
+pp_c_relational_expression (c_pretty_printer *pp, tree e)
+{
+  enum tree_code code = TREE_CODE (e);
+  switch (code)
+    {
+    case LT_EXPR:
+    case GT_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+      pp_c_relational_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      if (code == LT_EXPR)
+       pp_less (pp);
+      else if (code == GT_EXPR)
+       pp_greater (pp);
+      else if (code == LE_EXPR)
+       pp_identifier (pp, "<=");
+      else if (code == GE_EXPR)
+       pp_identifier (pp, ">=");
+      pp_c_whitespace (pp);
+      pp_c_shift_expression (pp, TREE_OPERAND (e, 1));
+      break;
+
+    default:
+      pp_c_shift_expression (pp, e);
+      break;
+    }
+}
+
+/* equality-expression:
+      relational-expression
+      equality-expression == relational-expression
+      equality-equality != relational-expression  */
+
+static void
+pp_c_equality_expression (c_pretty_printer *pp, tree e)
+{
+  enum tree_code code = TREE_CODE (e);
+  switch (code)
+    {
+    case EQ_EXPR:
+    case NE_EXPR:
+      pp_c_equality_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      pp_identifier (pp, code == EQ_EXPR ? "==" : "!=");
+      pp_c_whitespace (pp);
+      pp_c_relational_expression (pp, TREE_OPERAND (e, 1));
+      break;
+
+    default:
+      pp_c_relational_expression (pp, e);
+      break;
+    }
+}
+
+/* AND-expression:
+      equality-expression
+      AND-expression & equality-equality   */
+
+static void
+pp_c_and_expression (c_pretty_printer *pp, tree e)
+{
+  if (TREE_CODE (e) == BIT_AND_EXPR)
+    {
+      pp_c_and_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      pp_ampersand (pp);
+      pp_c_whitespace (pp);
+      pp_c_equality_expression (pp, TREE_OPERAND (e, 1));
+    }
+  else
+    pp_c_equality_expression (pp, e);
+}
+
+/* exclusive-OR-expression:
+     AND-expression
+     exclusive-OR-expression ^ AND-expression  */
+
+static void
+pp_c_exclusive_or_expression (c_pretty_printer *pp, tree e)
+{
+  if (TREE_CODE (e) == BIT_XOR_EXPR)
+    {
+      pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_maybe_whitespace (pp);
+      pp_carret (pp);
+      pp_c_whitespace (pp);
+      pp_c_and_expression (pp, TREE_OPERAND (e, 1));
+    }
+  else
+    pp_c_and_expression (pp, e);
+}
+
+/* inclusive-OR-expression:
+     exclusive-OR-expression
+     inclusive-OR-expression | exclusive-OR-expression  */
+
+static void
+pp_c_inclusive_or_expression (c_pretty_printer *pp, tree e)
+{
+  if (TREE_CODE (e) == BIT_IOR_EXPR)
+    {
+      pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      pp_bar (pp);
+      pp_c_whitespace (pp);
+      pp_c_exclusive_or_expression (pp, TREE_OPERAND (e, 1));
+    }
+  else
+    pp_c_exclusive_or_expression (pp, e);
+}
+
+/* logical-AND-expression:
+      inclusive-OR-expression
+      logical-AND-expression && inclusive-OR-expression  */
+
+static void
+pp_c_logical_and_expression (c_pretty_printer *pp, tree e)
+{
+  if (TREE_CODE (e) == TRUTH_ANDIF_EXPR)
+    {
+      pp_c_logical_and_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      pp_identifier (pp, "&&");
+      pp_c_whitespace (pp);
+      pp_c_inclusive_or_expression (pp, TREE_OPERAND (e, 1));
+    }
+  else
+    pp_c_inclusive_or_expression (pp, e);
+}
+
+/* logical-OR-expression:
+      logical-AND-expression
+      logical-OR-expression || logical-AND-expression  */
+
+void
+pp_c_logical_or_expression (c_pretty_printer *pp, tree e)
+{
+  if (TREE_CODE (e) == TRUTH_ORIF_EXPR)
+    {
+      pp_c_logical_or_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      pp_identifier (pp, "||");
+      pp_c_whitespace (pp);
+      pp_c_logical_and_expression (pp, TREE_OPERAND (e, 1));
+    }
+  else
+    pp_c_logical_and_expression (pp, e);
+}
+
+/* conditional-expression:
+      logical-OR-expression
+      logical-OR-expression ? expression : conditional-expression  */
+
+static void
+pp_c_conditional_expression (c_pretty_printer *pp, tree e)
+{
+  if (TREE_CODE (e) == COND_EXPR)
+    {
+      pp_c_logical_or_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      pp_question (pp);
+      pp_c_whitespace (pp);
+      pp_expression (pp, TREE_OPERAND (e, 1));
+      pp_c_whitespace (pp);
+      pp_colon (pp);
+      pp_c_whitespace (pp);
+      pp_c_conditional_expression (pp, TREE_OPERAND (e, 2));
+    }
+  else
+    pp_c_logical_or_expression (pp, e);
+}
+
+
+/* assignment-expression:
+      conditional-expression
+      unary-expression assignment-operator  assignment-expression 
+
+   assignment-expression: one of
+      =    *=    /=    %=    +=    -=    >>=    <<=    &=    ^=    |=  */
+
+static void
+pp_c_assignment_expression (c_pretty_printer *pp, tree e)
+{
+  if (TREE_CODE (e) == MODIFY_EXPR || TREE_CODE (e) == INIT_EXPR)
+    {
+      pp_c_unary_expression (pp, TREE_OPERAND (e, 0));
+      pp_c_whitespace (pp);
+      pp_equal (pp);
+      pp_space (pp);
+      pp_c_expression (pp, TREE_OPERAND (e, 1));
+    }
+  else
+    pp_c_conditional_expression (pp, e);
+}
+
+/* expression:
+       assignment-expression
+       expression , assignment-expression
+
+  Implementation note:  instead of going through the usual recursion
+  chain, I take the liberty of dispatching nodes to the appropriate
+  functions.  This makes some redundancy, but it worths it. That also
+  prevents a possible infinite recursion between pp_c_primary_expression ()
+  and pp_c_expression ().  */
+
+void
+pp_c_expression (c_pretty_printer *pp, tree e)
+{
+  switch (TREE_CODE (e))
+    {
+    case INTEGER_CST:
+      pp_c_integer_constant (pp, e);
+      break;
+
+    case REAL_CST:
+      pp_c_floating_constant (pp, e);
+      break;
+
+    case STRING_CST:
+      pp_c_string_literal (pp, e);
+      break;
+
+    case IDENTIFIER_NODE:
+    case FUNCTION_DECL:
+    case VAR_DECL:
+    case CONST_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case FIELD_DECL:
+    case LABEL_DECL:
+    case ERROR_MARK:
+    case STMT_EXPR:
+      pp_primary_expression (pp, e);
+      break;
+
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case ARROW_EXPR:
+    case ARRAY_REF:
+    case CALL_EXPR:
+    case COMPONENT_REF:
+    case COMPLEX_CST:
+    case COMPLEX_EXPR:
+    case VECTOR_CST:
+    case ABS_EXPR:
+    case CONSTRUCTOR:
+    case COMPOUND_LITERAL_EXPR:
+    case VA_ARG_EXPR:
+      pp_postfix_expression (pp, e);
+      break;
+
+    case CONJ_EXPR:
+    case ADDR_EXPR:
+    case INDIRECT_REF:
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case SIZEOF_EXPR:
+    case ALIGNOF_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+      pp_c_unary_expression (pp, e);
+      break;
+
+    case FLOAT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case CONVERT_EXPR:
+      pp_c_cast_expression (pp, e);
+      break;
+
+    case MULT_EXPR:
+    case TRUNC_MOD_EXPR:
+    case TRUNC_DIV_EXPR:
+      pp_multiplicative_expression (pp, e);
+      break;
+
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+      pp_c_shift_expression (pp, e);
+      break;
+
+    case LT_EXPR:
+    case GT_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+      pp_c_relational_expression (pp, e);
+      break;
+
+    case BIT_AND_EXPR:
+      pp_c_and_expression (pp, e);
+      break;
+
+    case BIT_XOR_EXPR:
+      pp_c_exclusive_or_expression (pp, e);
+      break;
+
+    case BIT_IOR_EXPR:
+      pp_c_inclusive_or_expression (pp, e);
+      break;
+
+    case TRUTH_ANDIF_EXPR:
+      pp_c_logical_and_expression (pp, e);
+      break;
+
+    case TRUTH_ORIF_EXPR:
+      pp_c_logical_or_expression (pp, e);
+      break;
+
+    case EQ_EXPR:
+    case NE_EXPR:
+      pp_c_equality_expression (pp, e);
+      break;
+      
+    case COND_EXPR:
+      pp_conditional_expression (pp, e);
+      break;
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      pp_c_additive_expression (pp, e);
+      break;
+
+    case MODIFY_EXPR:
+    case INIT_EXPR:
+      pp_assignment_expression (pp, e);
+      break;
+
+    case COMPOUND_EXPR:
+      pp_c_left_paren (pp);
+      pp_expression (pp, TREE_OPERAND (e, 0));
+      pp_separate_with (pp, ',');
+      pp_assignment_expression (pp, TREE_OPERAND (e, 1));
+      pp_c_right_paren (pp);
+      break;
+
+    case NOP_EXPR:
+    case NON_LVALUE_EXPR:
+    case SAVE_EXPR:
+    case UNSAVE_EXPR:
+      pp_expression (pp, TREE_OPERAND (e, 0));
+      break;
+
+    case TARGET_EXPR:
+      pp_postfix_expression (pp, TREE_OPERAND (e, 1));
+      break;
+      
+    default:
+      pp_unsupported_tree (pp, e);
+      break;
+    }
+}
+
+
+\f
+/* Statements.  */
+
+/* statement:
+      labeled-statement
+      compound-statement
+      expression-statement
+      selection-statement
+      iteration-statement
+      jump-statement   */
+
+void
+pp_c_statement (c_pretty_printer *pp, tree stmt)
+{
+  enum tree_code code;
+
+  if (stmt == NULL)
+    return;
+  
+  code = TREE_CODE (stmt);
+  switch (code)
+    {
+       /* labeled-statement:
+             identifier : statement
+             case constant-expression : statement
+             default : statement   */
+    case LABEL_STMT:
+    case CASE_LABEL:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, -3);
+      else
+        pp_indentation (pp) -= 3;
+      if (code == LABEL_STMT)
+       pp_tree_identifier (pp, DECL_NAME (LABEL_STMT_LABEL (stmt)));
+      else if (code == CASE_LABEL)
+       {
+         if (CASE_LOW (stmt) == NULL_TREE)
+           pp_identifier (pp, "default");
+         else
+           {
+             pp_c_identifier (pp, "case");
+             pp_c_whitespace (pp);
+             pp_conditional_expression (pp, CASE_LOW (stmt));
+             if (CASE_HIGH (stmt))
+               {
+                 pp_identifier (pp, "...");
+                 pp_conditional_expression (pp, CASE_HIGH (stmt));
+               }
+           }
+       }
+      pp_colon (pp);
+      pp_indentation (pp) += 3;
+      pp_needs_newline (pp) = true;
+      break;
+
+      /* compound-statement:
+            {  block-item-list(opt) }
+
+         block-item-list:
+            block-item
+            block-item-list block-item
+
+         block-item:
+            declaration
+            statement   */
+    case COMPOUND_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      pp_c_left_brace (pp);
+      pp_newline_and_indent (pp, 3);
+      for (stmt = COMPOUND_BODY (stmt); stmt; stmt = TREE_CHAIN (stmt))
+       pp_statement (pp, stmt);
+      pp_newline_and_indent (pp, -3);
+      pp_c_right_brace (pp);
+      pp_needs_newline (pp) = true;
+      break;
+
+      /* expression-statement:
+            expression(opt) ;  */
+    case EXPR_STMT:
+    case CLEANUP_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      {
+        tree e = code == EXPR_STMT
+          ? EXPR_STMT_EXPR (stmt)
+          : CLEANUP_EXPR (stmt);
+        if (e)
+          pp_expression (pp, e);
+      }
+      pp_c_semicolon (pp);
+      pp_needs_newline (pp) = true;
+      break;
+
+      /* selection-statement:
+            if ( expression ) statement
+            if ( expression ) statement else statement
+            switch ( expression ) statement   */
+    case IF_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      pp_c_identifier (pp, "if");
+      pp_c_whitespace (pp);
+      pp_c_left_paren (pp);
+      pp_expression (pp, IF_COND (stmt));
+      pp_c_right_paren (pp);
+      pp_newline_and_indent (pp, 3);
+      pp_statement (pp, THEN_CLAUSE (stmt));
+      pp_newline_and_indent (pp, -3);
+      if (ELSE_CLAUSE (stmt))
+       {
+         tree else_clause = ELSE_CLAUSE (stmt);
+         pp_c_identifier (pp, "else");
+         if (TREE_CODE (else_clause) == IF_STMT)
+           pp_c_whitespace (pp);
+         else
+           pp_newline_and_indent (pp, 3);
+         pp_statement (pp, else_clause);
+         if (TREE_CODE (else_clause) != IF_STMT)
+           pp_newline_and_indent (pp, -3);
+       }
+      break;
+
+    case SWITCH_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      pp_c_identifier (pp, "switch");
+      pp_space (pp);
+      pp_c_left_paren (pp);
+      pp_expression (pp, SWITCH_COND (stmt));
+      pp_c_right_paren (pp);
+      pp_indentation (pp) += 3;
+      pp_needs_newline (pp) = true;
+      pp_statement (pp, SWITCH_BODY (stmt));
+      pp_newline_and_indent (pp, -3);
+      break;
+
+      /* iteration-statement:
+            while ( expression ) statement
+            do statement while ( expression ) ;
+            for ( expression(opt) ; expression(opt) ; expression(opt) ) statement
+            for ( declaration expression(opt) ; expression(opt) ) statement  */
+    case WHILE_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      pp_c_identifier (pp, "while");
+      pp_space (pp);
+      pp_c_left_paren (pp);
+      pp_expression (pp, WHILE_COND (stmt));
+      pp_c_right_paren (pp);
+      pp_newline_and_indent (pp, 3);
+      pp_statement (pp, WHILE_BODY (stmt));
+      pp_indentation (pp) -= 3;
+      pp_needs_newline (pp) = true;
+      break;
+
+    case DO_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      pp_c_identifier (pp, "do");
+      pp_newline_and_indent (pp, 3);
+      pp_statement (pp, DO_BODY (stmt));
+      pp_newline_and_indent (pp, -3);
+      pp_c_identifier (pp, "while");
+      pp_space (pp);
+      pp_c_left_paren (pp);
+      pp_expression (pp, DO_COND (stmt));
+      pp_c_right_paren (pp);
+      pp_c_semicolon (pp);
+      pp_needs_newline (pp) = true;
+      break;
+
+    case FOR_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      pp_c_identifier (pp, "for");
+      pp_space (pp);
+      pp_c_left_paren (pp);
+      if (FOR_INIT_STMT (stmt))
+        pp_statement (pp, FOR_INIT_STMT (stmt));
+      else
+        pp_c_semicolon (pp);
+      pp_needs_newline (pp) = false;
+      pp_c_whitespace (pp);
+      if (FOR_COND (stmt))
+       pp_expression (pp, FOR_COND (stmt));
+      pp_c_semicolon (pp);
+      pp_needs_newline (pp) = false;
+      pp_c_whitespace (pp);
+      if (FOR_EXPR (stmt))
+       pp_expression (pp, FOR_EXPR (stmt));
+      pp_c_right_paren (pp);
+      pp_newline_and_indent (pp, 3);
+      pp_statement (pp, FOR_BODY (stmt));
+      pp_indentation (pp) -= 3;
+      pp_needs_newline (pp) = true;
+      break;
+
+      /* jump-statement:
+            goto identifier;
+            continue ;
+            return expression(opt) ;  */
+    case BREAK_STMT:
+    case CONTINUE_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      pp_identifier (pp, code == BREAK_STMT ? "break" : "continue");
+      pp_c_semicolon (pp);
+      pp_needs_newline (pp) = true;
+      break;
+
+    case RETURN_STMT:
+    case GOTO_STMT:
+      {
+       tree e = code == RETURN_STMT
+         ? RETURN_STMT_EXPR (stmt)
+         : GOTO_DESTINATION (stmt);
+        if (pp_needs_newline (pp))
+          pp_newline_and_indent (pp, 0);
+       pp_c_identifier (pp, code == RETURN_STMT ? "return" : "goto");
+        pp_c_whitespace (pp);
+       if (e)
+          {
+            if (TREE_CODE (e) == INIT_EXPR
+                && TREE_CODE (TREE_OPERAND (e, 0)) == RESULT_DECL)
+              e = TREE_OPERAND (e, 1);
+            pp_expression (pp, e);
+          }
+       pp_c_semicolon (pp);
+       pp_needs_newline (pp) = true;
+      }
+      break;
+
+    case SCOPE_STMT:
+      if (!SCOPE_NULLIFIED_P (stmt) && SCOPE_NO_CLEANUPS_P (stmt))
+        {
+          int i = 0;
+          if (pp_needs_newline (pp))
+            pp_newline_and_indent (pp, 0);
+          if (SCOPE_BEGIN_P (stmt))
+            {
+              pp_left_brace (pp);
+              i = 3;
+            }
+          else if (SCOPE_END_P (stmt))
+            {
+              pp_right_brace (pp);
+              i = -3;
+            }
+          pp_indentation (pp) += i;
+          pp_needs_newline (pp) = true;
+        }
+      break;
+
+    case DECL_STMT:
+      if (pp_needs_newline (pp))
+        pp_newline_and_indent (pp, 0);
+      pp_declaration (pp, DECL_STMT_DECL (stmt));
+      pp_needs_newline (pp) = true;
+      break;
+
+    case ASM_STMT:
+      {
+       bool has_volatile_p = ASM_VOLATILE_P (stmt);
+       bool is_extended = has_volatile_p || ASM_INPUTS (stmt)
+         || ASM_OUTPUTS (stmt) || ASM_CLOBBERS (stmt);
+       pp_c_identifier (pp, is_extended ? "__asm__" : "asm");
+       if (has_volatile_p)
+         pp_c_identifier (pp, "__volatile__");
+       pp_space (pp);
+       pp_c_left_paren (pp);
+       pp_c_string_literal (pp, ASM_STRING (stmt));
+       if (is_extended)
+         {
+           pp_space (pp);
+           pp_separate_with (pp, ':');
+           if (ASM_OUTPUTS (stmt))
+             pp_expression (pp, ASM_OUTPUTS (stmt));
+           pp_space (pp);
+           pp_separate_with (pp, ':');
+           if (ASM_INPUTS (stmt))
+             pp_expression (pp, ASM_INPUTS (stmt));
+           pp_space (pp);
+           pp_separate_with (pp, ':');
+           if (ASM_CLOBBERS (stmt))
+             pp_expression (pp, ASM_CLOBBERS (stmt));
+         }
+       pp_c_right_paren (pp);
+       pp_newline (pp);
+      }
+      break;
+
+    case FILE_STMT:
+      pp_c_identifier (pp, "__FILE__");
+      pp_space (pp);
+      pp_equal (pp);
+      pp_c_whitespace (pp);
+      pp_c_identifier (pp, FILE_STMT_FILENAME (stmt));
+      pp_c_semicolon (pp);
+      pp_needs_newline (pp) = true;
+      break;
+
+    default:
+      pp_unsupported_tree (pp, stmt);
+    }
+}
+
+\f
+/* Initialize the PRETTY-PRINTER for handling C codes.  */
+
+void
+pp_c_pretty_printer_init (c_pretty_printer *pp)
+{
+  pp->offset_list               = 0;
+
+  pp->declaration               = pp_c_declaration;
+  pp->declaration_specifiers    = pp_c_declaration_specifiers;
+  pp->declarator                = pp_c_declarator;
+  pp->direct_declarator         = pp_c_direct_declarator;
+  pp->type_specifier_seq        = pp_c_specifier_qualifier_list;
+  pp->abstract_declarator       = pp_c_abstract_declarator;
+  pp->direct_abstract_declarator = pp_c_direct_abstract_declarator;
+  pp->ptr_operator              = pp_c_pointer;
+  pp->parameter_list            = pp_c_parameter_type_list;
+  pp->type_id                   = pp_c_type_id;
+  pp->simple_type_specifier     = pp_c_type_specifier;
+  pp->function_specifier        = pp_c_function_specifier;
+  pp->storage_class_specifier   = pp_c_storage_class_specifier;
+
+  pp->statement                 = pp_c_statement;
+
+  pp->id_expression             = pp_c_id_expression;
+  pp->primary_expression        = pp_c_primary_expression;
+  pp->postfix_expression        = pp_c_postfix_expression;
+  pp->unary_expression          = pp_c_unary_expression;
+  pp->initializer               = pp_c_initializer;
+  pp->multiplicative_expression = pp_c_multiplicative_expression;
+  pp->conditional_expression    = pp_c_conditional_expression;
+  pp->assignment_expression     = pp_c_assignment_expression;
+  pp->expression                = pp_c_expression;
+}
diff --git a/support/cpp2/c-pretty-print.h b/support/cpp2/c-pretty-print.h
new file mode 100644 (file)
index 0000000..e9084b3
--- /dev/null
@@ -0,0 +1,198 @@
+/* Various declarations for the C and C++ pretty-printers.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef GCC_C_PRETTY_PRINTER
+#define GCC_C_PRETTY_PRINTER
+
+#include "pretty-print.h"
+
+
+typedef enum
+  {
+     pp_c_flag_abstract = 1 << 1,
+     pp_c_flag_last_bit = 2    
+  } pp_c_pretty_print_flags;
+
+
+/* The data type used to bundle information necessary for pretty-printing
+   a C or C++ entity.  */
+typedef struct c_pretty_print_info c_pretty_printer;
+
+/* The type of a C pretty-printer 'member' function.  */
+typedef void (*c_pretty_print_fn) (c_pretty_printer *, tree);
+
+/* The datatype that contains information necessary for pretty-printing
+   a tree that represents a C construct.  Any pretty-printer for a
+   language using C/c++ syntax can derive from this datatype and reuse
+   facilities provided here.  It can do so by having a subobject of type
+   c_pretty_printer and override the macro pp_c_base to return a pointer
+   to that subobject.  Such a pretty-printer has the responsibility to
+   initialize the pp_base() part, then call pp_c_pretty_printer_init
+   to set up the components that are specific to the C pretty-printer.
+   A derived pretty-printer can override any function listed in the
+   vtable below.  See cp/cxx-pretty-print.h and cp/cxx-pretty-print.c
+   for an example of derivation.  */
+struct c_pretty_print_info
+{
+  pretty_printer base;
+  /* Points to the first element of an array of offset-list.
+     Not used yet.  */
+  int *offset_list;
+
+  pp_flags flags;
+   
+  /* These must be overridden by each of the C and C++ front-end to
+     reflect their understanding of syntactic productions when they differ.  */
+  c_pretty_print_fn declaration;
+  c_pretty_print_fn declaration_specifiers;
+  c_pretty_print_fn declarator;
+  c_pretty_print_fn abstract_declarator;
+  c_pretty_print_fn direct_abstract_declarator;
+  c_pretty_print_fn type_specifier_seq;
+  c_pretty_print_fn direct_declarator;
+  c_pretty_print_fn ptr_operator;
+  c_pretty_print_fn parameter_list;
+  c_pretty_print_fn type_id;
+  c_pretty_print_fn simple_type_specifier;
+  c_pretty_print_fn function_specifier;
+  c_pretty_print_fn storage_class_specifier;
+  c_pretty_print_fn initializer;
+
+  c_pretty_print_fn statement;
+
+  c_pretty_print_fn id_expression;
+  c_pretty_print_fn primary_expression;
+  c_pretty_print_fn postfix_expression;
+  c_pretty_print_fn unary_expression;
+  c_pretty_print_fn multiplicative_expression;
+  c_pretty_print_fn conditional_expression;
+  c_pretty_print_fn assignment_expression;
+  c_pretty_print_fn expression;
+};
+
+/* Override the pp_base macro.  Derived pretty-printers should not
+   touch this macro.  Instead they should override pp_c_base instead.  */
+#undef pp_base
+#define pp_base(PP)  (&pp_c_base (PP)->base)
+
+     
+#define pp_c_tree_identifier(PPI, ID)              \
+   pp_c_identifier (PPI, IDENTIFIER_POINTER (ID))
+
+#define pp_declaration(PPI, T)                    \
+   pp_c_base (PPI)->declaration (pp_c_base (PPI), T)
+#define pp_declaration_specifiers(PPI, D)         \
+   pp_c_base (PPI)->declaration_specifiers (pp_c_base (PPI), D)
+#define pp_abstract_declarator(PP, D)             \
+   pp_c_base (PP)->abstract_declarator (pp_c_base (PP), D)
+#define pp_type_specifier_seq(PPI, D)             \
+   pp_c_base (PPI)->type_specifier_seq (pp_c_base (PPI), D)
+#define pp_declarator(PPI, D)                     \
+   pp_c_base (PPI)->declarator (pp_c_base (PPI), D)
+#define pp_direct_declarator(PPI, D)              \
+   pp_c_base (PPI)->direct_declarator (pp_c_base (PPI), D)
+#define pp_direct_abstract_declarator(PP, D)      \
+   pp_c_base (PP)->direct_abstract_declarator (pp_c_base (PP), D)
+#define pp_ptr_operator(PP, D)                    \
+   pp_c_base (PP)->ptr_operator (pp_c_base (PP), D)
+#define pp_parameter_list(PPI, T)                 \
+  pp_c_base (PPI)->parameter_list (pp_c_base (PPI), T)
+#define pp_type_id(PPI, D)                        \
+  pp_c_base (PPI)->type_id (pp_c_base (PPI), D)
+#define pp_simple_type_specifier(PP, T)           \
+  pp_c_base (PP)->simple_type_specifier (pp_c_base (PP), T)
+#define pp_function_specifier(PP, D)              \
+  pp_c_base (PP)->function_specifier (pp_c_base (PP), D)
+#define pp_storage_class_specifier(PP, D)         \
+  pp_c_base (PP)->storage_class_specifier (pp_c_base (PP), D);
+
+#define pp_statement(PPI, S)                      \
+  pp_c_base (PPI)->statement (pp_c_base (PPI), S)
+
+#define pp_id_expression(PP, E)  \
+  pp_c_base (PP)->id_expression (pp_c_base (PP), E)
+#define pp_primary_expression(PPI, E)             \
+  pp_c_base (PPI)->primary_expression (pp_c_base (PPI), E)
+#define pp_postfix_expression(PPI, E)             \
+  pp_c_base (PPI)->postfix_expression (pp_c_base (PPI), E)
+#define pp_unary_expression(PPI, E)               \
+  pp_c_base (PPI)->unary_expression (pp_c_base (PPI), E)
+#define pp_initializer(PPI, E)                    \
+  pp_c_base (PPI)->initializer (pp_c_base (PPI), E)
+#define pp_multiplicative_expression(PPI, E)      \
+  pp_c_base (PPI)->multiplicative_expression (pp_c_base (PPI), E)
+#define pp_conditional_expression(PPI, E)         \
+  pp_c_base (PPI)->conditional_expression (pp_c_base (PPI), E)
+#define pp_assignment_expression(PPI, E)          \
+   pp_c_base (PPI)->assignment_expression (pp_c_base (PPI), E)
+#define pp_expression(PP, E)                      \
+   pp_c_base (PP)->expression (pp_c_base (PP), E)
+
+
+/* Returns the c_pretty_printer base object of PRETTY-PRINTER.  This
+   macro must be overridden by any subclass of c_pretty_print_info.  */
+#define pp_c_base(PP)  (PP)
+
+extern void pp_c_pretty_printer_init (c_pretty_printer *);
+void pp_c_whitespace (c_pretty_printer *);
+void pp_c_left_paren (c_pretty_printer *);
+void pp_c_right_paren (c_pretty_printer *);
+void pp_c_left_brace (c_pretty_printer *);
+void pp_c_right_brace (c_pretty_printer *);
+void pp_c_dot (c_pretty_printer *);
+void pp_c_ampersand (c_pretty_printer *);
+void pp_c_arrow (c_pretty_printer *);
+void pp_c_semicolon (c_pretty_printer *);
+void pp_c_space_for_pointer_operator (c_pretty_printer *, tree);
+
+/* Declarations.  */
+void pp_c_function_definition (c_pretty_printer *, tree);
+void pp_c_attributes (c_pretty_printer *, tree);
+void pp_c_type_qualifier_list (c_pretty_printer *, tree);
+void pp_c_parameter_type_list (c_pretty_printer *, tree);
+void pp_c_declaration (c_pretty_printer *, tree);
+void pp_c_declaration_specifiers (c_pretty_printer *, tree);
+void pp_c_declarator (c_pretty_printer *, tree);
+void pp_c_direct_declarator (c_pretty_printer *, tree);
+void pp_c_specifier_qualifier_list (c_pretty_printer *, tree);
+void pp_c_function_specifier (c_pretty_printer *, tree);
+void pp_c_type_id (c_pretty_printer *, tree);
+void pp_c_direct_abstract_declarator (c_pretty_printer *, tree);
+void pp_c_type_specifier (c_pretty_printer *, tree);
+void pp_c_storage_class_specifier (c_pretty_printer *, tree);
+/* Statements.  */
+void pp_c_statement (c_pretty_printer *, tree);
+/* Expressions.  */
+void pp_c_expression (c_pretty_printer *, tree);
+void pp_c_logical_or_expression (c_pretty_printer *, tree);
+void pp_c_expression_list (c_pretty_printer *, tree);
+void pp_c_call_argument_list (c_pretty_printer *, tree);
+void pp_c_unary_expression (c_pretty_printer *, tree);
+void pp_c_cast_expression (c_pretty_printer *, tree);
+void pp_c_postfix_expression (c_pretty_printer *, tree);
+void pp_c_primary_expression (c_pretty_printer *, tree);
+void pp_c_init_declarator (c_pretty_printer *, tree);
+void pp_c_constant (c_pretty_printer *, tree);
+void pp_c_id_expression (c_pretty_printer *, tree);
+void pp_c_identifier (c_pretty_printer *, const char *);
+void pp_c_string_literal (c_pretty_printer *, tree);
+
+#endif /* GCC_C_PRETTY_PRINTER */
index 10c3c2a238c011d70c191672fbd3b2677937b635..c6bbaa20c63a0e08557a379c145994b9b6024c9d 100644 (file)
@@ -1,5 +1,4 @@
 #include "auto-host.h"
-#include "sdcc.h"
 /* Provide three core typedefs used by everything, if we are compiling
    GCC.  These used to be found in rtl.h and tree.h, but this is no
    longer practical.  Providing these here rather that system.h allows
index a747590c8f01a76e0b25faf20a1053e3db524b26..7897d5f54dcefcc09d3fa2ece23a9b17613c3f34 100755 (executable)
@@ -561,7 +561,7 @@ PACKAGE_VERSION=
 PACKAGE_STRING=
 PACKAGE_BUGREPORT=
 
-ac_unique_file="cppmain.c"
+ac_unique_file="sdcppmain.c"
 # Factoring default headers for most tests.
 ac_includes_default="\
 #include <stdio.h>
index 65a6d93ffd9d550ff8429a890b04e552d85fb2dc..1a2abb5bb7e18e437fdd51798467458bb721341d 100644 (file)
@@ -22,7 +22,7 @@
 
 # Initialization and defaults
 AC_PREREQ(2.13)
-AC_INIT(cppmain.c)
+AC_INIT(sdcpp.c)
 AC_CONFIG_HEADER(auto-host.h:config.in)
 
 remove=rm
diff --git a/support/cpp2/cppcharset.c b/support/cpp2/cppcharset.c
new file mode 100644 (file)
index 0000000..a6a65ed
--- /dev/null
@@ -0,0 +1,1411 @@
+/* CPP Library - charsets
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
+
+   Broken out of c-lex.c Apr 2003, adding valid C99 UCN ranges.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "cpphash.h"
+#include "cppucnid.h"
+
+/* Character set handling for C-family languages.
+
+   Terminological note: In what follows, "charset" or "character set"
+   will be taken to mean both an abstract set of characters and an
+   encoding for that set.
+
+   The C99 standard discusses two character sets: source and execution.
+   The source character set is used for internal processing in translation
+   phases 1 through 4; the execution character set is used thereafter.
+   Both are required by 5.2.1.2p1 to be multibyte encodings, not wide
+   character encodings (see 3.7.2, 3.7.3 for the standardese meanings
+   of these terms).  Furthermore, the "basic character set" (listed in
+   5.2.1p3) is to be encoded in each with values one byte wide, and is
+   to appear in the initial shift state.
+
+   It is not explicitly mentioned, but there is also a "wide execution
+   character set" used to encode wide character constants and wide
+   string literals; this is supposed to be the result of applying the
+   standard library function mbstowcs() to an equivalent narrow string
+   (6.4.5p5).  However, the behavior of hexadecimal and octal
+   \-escapes is at odds with this; they are supposed to be translated
+   directly to wchar_t values (6.4.4.4p5,6).
+
+   The source character set is not necessarily the character set used
+   to encode physical source files on disk; translation phase 1 converts
+   from whatever that encoding is to the source character set.
+
+   The presence of universal character names in C99 (6.4.3 et seq.)
+   forces the source character set to be isomorphic to ISO 10646,
+   that is, Unicode.  There is no such constraint on the execution
+   character set; note also that the conversion from source to
+   execution character set does not occur for identifiers (5.1.1.2p1#5).
+
+   For convenience of implementation, the source character set's
+   encoding of the basic character set should be identical to the
+   execution character set OF THE HOST SYSTEM's encoding of the basic
+   character set, and it should not be a state-dependent encoding.
+
+   cpplib uses UTF-8 or UTF-EBCDIC for the source character set,
+   depending on whether the host is based on ASCII or EBCDIC (see
+   respectively Unicode section 2.3/ISO10646 Amendment 2, and Unicode
+   Technical Report #16).  With limited exceptions, it relies on the
+   system library's iconv() primitive to do charset conversion
+   (specified in SUSv2).  */
+
+#if !HAVE_ICONV
+/* Make certain that the uses of iconv(), iconv_open(), iconv_close()
+   below, which are guarded only by if statements with compile-time
+   constant conditions, do not cause link errors.  */
+#define iconv_open(x, y) (errno = EINVAL, (iconv_t)-1)
+#define iconv(a,b,c,d,e) (errno = EINVAL, (size_t)-1)
+#define iconv_close(x)   (void)0
+#define ICONV_CONST
+#endif
+
+#if HOST_CHARSET == HOST_CHARSET_ASCII
+#define SOURCE_CHARSET "UTF-8"
+#elif HOST_CHARSET == HOST_CHARSET_EBCDIC
+#define SOURCE_CHARSET "UTF-EBCDIC"
+#else
+#error "Unrecognized basic host character set"
+#endif
+
+#ifndef EILSEQ
+#define EILSEQ EINVAL
+#endif
+
+/* This structure is used for a resizable string buffer throughout.  */
+/* Don't call it strbuf, as that conflicts with unistd.h on systems
+   such as DYNIX/ptx where unistd.h includes stropts.h.  */
+struct _cpp_strbuf
+{
+  uchar *text;
+  size_t asize;
+  size_t len;
+};
+
+/* This is enough to hold any string that fits on a single 80-column
+   line, even if iconv quadruples its size (e.g. conversion from
+   ASCII to UTF-32) rounded up to a power of two.  */
+#define OUTBUF_BLOCK_SIZE 256
+
+/* Conversions between UTF-8 and UTF-16/32 are implemented by custom
+   logic.  This is because a depressing number of systems lack iconv,
+   or have have iconv libraries that do not do these conversions, so
+   we need a fallback implementation for them.  To ensure the fallback
+   doesn't break due to neglect, it is used on all systems.
+
+   UTF-32 encoding is nice and simple: a four-byte binary number,
+   constrained to the range 00000000-7FFFFFFF to avoid questions of
+   signedness.  We do have to cope with big- and little-endian
+   variants.
+
+   UTF-16 encoding uses two-byte binary numbers, again in big- and
+   little-endian variants, for all values in the 00000000-0000FFFF
+   range.  Values in the 00010000-0010FFFF range are encoded as pairs
+   of two-byte numbers, called "surrogate pairs": given a number S in
+   this range, it is mapped to a pair (H, L) as follows:
+
+     H = (S - 0x10000) / 0x400 + 0xD800
+     L = (S - 0x10000) % 0x400 + 0xDC00
+
+   Two-byte values in the D800...DFFF range are ill-formed except as a
+   component of a surrogate pair.  Even if the encoding within a
+   two-byte value is little-endian, the H member of the surrogate pair
+   comes first.
+
+   There is no way to encode values in the 00110000-7FFFFFFF range,
+   which is not currently a problem as there are no assigned code
+   points in that range; however, the author expects that it will
+   eventually become necessary to abandon UTF-16 due to this
+   limitation.  Note also that, because of these pairs, UTF-16 does
+   not meet the requirements of the C standard for a wide character
+   encoding (see 3.7.3 and 6.4.4.4p11).
+
+   UTF-8 encoding looks like this:
+
+   value range        encoded as
+   00000000-0000007F   0xxxxxxx
+   00000080-000007FF   110xxxxx 10xxxxxx
+   00000800-0000FFFF   1110xxxx 10xxxxxx 10xxxxxx
+   00010000-001FFFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+   00200000-03FFFFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+   04000000-7FFFFFFF   1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+   Values in the 0000D800 ... 0000DFFF range (surrogates) are invalid,
+   which means that three-byte sequences ED xx yy, with A0 <= xx <= BF,
+   never occur.  Note also that any value that can be encoded by a
+   given row of the table can also be encoded by all successive rows,
+   but this is not done; only the shortest possible encoding for any
+   given value is valid.  For instance, the character 07C0 could be
+   encoded as any of DF 80, E0 9F 80, F0 80 9F 80, F8 80 80 9F 80, or
+   FC 80 80 80 9F 80.  Only the first is valid.
+
+   An implementation note: the transformation from UTF-16 to UTF-8, or
+   vice versa, is easiest done by using UTF-32 as an intermediary.  */
+
+/* Internal primitives which go from an UTF-8 byte stream to native-endian
+   UTF-32 in a cppchar_t, or vice versa; this avoids an extra marshal/unmarshal
+   operation in several places below.  */
+static inline int
+one_utf8_to_cppchar (const uchar **inbufp, size_t *inbytesleftp,
+                    cppchar_t *cp)
+{
+  static const uchar masks[6] = { 0x7F, 0x1F, 0x0F, 0x07, 0x02, 0x01 };
+  static const uchar patns[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+  cppchar_t c;
+  const uchar *inbuf = *inbufp;
+  size_t nbytes, i;
+
+  if (*inbytesleftp < 1)
+    return EINVAL;
+
+  c = *inbuf;
+  if (c < 0x80)
+    {
+      *cp = c;
+      *inbytesleftp -= 1;
+      *inbufp += 1;
+      return 0;
+    }
+
+  /* The number of leading 1-bits in the first byte indicates how many
+     bytes follow.  */
+  for (nbytes = 2; nbytes < 7; nbytes++)
+    if ((c & ~masks[nbytes-1]) == patns[nbytes-1])
+      goto found;
+  return EILSEQ;
+ found:
+
+  if (*inbytesleftp < nbytes)
+    return EINVAL;
+
+  c = (c & masks[nbytes-1]);
+  inbuf++;
+  for (i = 1; i < nbytes; i++)
+    {
+      cppchar_t n = *inbuf++;
+      if ((n & 0xC0) != 0x80)
+       return EILSEQ;
+      c = ((c << 6) + (n & 0x3F));
+    }
+
+  /* Make sure the shortest possible encoding was used.  */
+  if (c <=      0x7F && nbytes > 1) return EILSEQ;
+  if (c <=     0x7FF && nbytes > 2) return EILSEQ;
+  if (c <=    0xFFFF && nbytes > 3) return EILSEQ;
+  if (c <=  0x1FFFFF && nbytes > 4) return EILSEQ;
+  if (c <= 0x3FFFFFF && nbytes > 5) return EILSEQ;
+
+  /* Make sure the character is valid.  */
+  if (c > 0x7FFFFFFF || (c >= 0xD800 && c <= 0xDFFF)) return EILSEQ;
+
+  *cp = c;
+  *inbufp = inbuf;
+  *inbytesleftp -= nbytes;
+  return 0;
+}
+
+static inline int
+one_cppchar_to_utf8 (cppchar_t c, uchar **outbufp, size_t *outbytesleftp)
+{
+  static const uchar masks[6] =  { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+  static const uchar limits[6] = { 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
+  size_t nbytes;
+  uchar buf[6], *p = &buf[6];
+  uchar *outbuf = *outbufp;
+
+  nbytes = 1;
+  if (c < 0x80)
+    *--p = c;
+  else
+    {
+      do
+       {
+         *--p = ((c & 0x3F) | 0x80);
+         c >>= 6;
+         nbytes++;
+       }
+      while (c >= 0x3F || (c & limits[nbytes-1]));
+      *--p = (c | masks[nbytes-1]);
+    }
+
+  if (*outbytesleftp < nbytes)
+    return E2BIG;
+
+  while (p < &buf[6])
+    *outbuf++ = *p++;
+  *outbytesleftp -= nbytes;
+  *outbufp = outbuf;
+  return 0;
+}
+
+/* The following four functions transform one character between the two
+   encodings named in the function name.  All have the signature
+   int (*)(iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp,
+           uchar **outbufp, size_t *outbytesleftp)
+
+   BIGEND must have the value 0 or 1, coerced to (iconv_t); it is
+   interpreted as a boolean indicating whether big-endian or
+   little-endian encoding is to be used for the member of the pair
+   that is not UTF-8.
+
+   INBUFP, INBYTESLEFTP, OUTBUFP, OUTBYTESLEFTP work exactly as they
+   do for iconv.
+
+   The return value is either 0 for success, or an errno value for
+   failure, which may be E2BIG (need more space), EILSEQ (ill-formed
+   input sequence), ir EINVAL (incomplete input sequence).  */
+
+static inline int
+one_utf8_to_utf32 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp,
+                  uchar **outbufp, size_t *outbytesleftp)
+{
+  uchar *outbuf;
+  cppchar_t s = 0;
+  int rval;
+
+  /* Check for space first, since we know exactly how much we need.  */
+  if (*outbytesleftp < 4)
+    return E2BIG;
+
+  rval = one_utf8_to_cppchar (inbufp, inbytesleftp, &s);
+  if (rval)
+    return rval;
+
+  outbuf = *outbufp;
+  outbuf[bigend ? 3 : 0] = (s & 0x000000FF);
+  outbuf[bigend ? 2 : 1] = (s & 0x0000FF00) >> 8;
+  outbuf[bigend ? 1 : 2] = (s & 0x00FF0000) >> 16;
+  outbuf[bigend ? 0 : 3] = (s & 0xFF000000) >> 24;
+
+  *outbufp += 4;
+  *outbytesleftp -= 4;
+  return 0;
+}
+
+static inline int
+one_utf32_to_utf8 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp,
+                  uchar **outbufp, size_t *outbytesleftp)
+{
+  cppchar_t s;
+  int rval;
+  const uchar *inbuf;
+
+  if (*inbytesleftp < 4)
+    return EINVAL;
+
+  inbuf = *inbufp;
+
+  s  = inbuf[bigend ? 0 : 3] << 24;
+  s += inbuf[bigend ? 1 : 2] << 16;
+  s += inbuf[bigend ? 2 : 1] << 8;
+  s += inbuf[bigend ? 3 : 0];
+
+  if (s >= 0x7FFFFFFF || (s >= 0xD800 && s <= 0xDFFF))
+    return EILSEQ;
+
+  rval = one_cppchar_to_utf8 (s, outbufp, outbytesleftp);
+  if (rval)
+    return rval;
+
+  *inbufp += 4;
+  *inbytesleftp -= 4;
+  return 0;
+}
+
+static inline int
+one_utf8_to_utf16 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp,
+                  uchar **outbufp, size_t *outbytesleftp)
+{
+  int rval;
+  cppchar_t s = 0;
+  const uchar *save_inbuf = *inbufp;
+  size_t save_inbytesleft = *inbytesleftp;
+  uchar *outbuf = *outbufp;
+
+  rval = one_utf8_to_cppchar (inbufp, inbytesleftp, &s);
+  if (rval)
+    return rval;
+
+  if (s > 0x0010FFFF)
+    {
+      *inbufp = save_inbuf;
+      *inbytesleftp = save_inbytesleft;
+      return EILSEQ;
+    }
+
+  if (s < 0xFFFF)
+    {
+      if (*outbytesleftp < 2)
+       {
+         *inbufp = save_inbuf;
+         *inbytesleftp = save_inbytesleft;
+         return E2BIG;
+       }
+      outbuf[bigend ? 1 : 0] = (s & 0x00FF);
+      outbuf[bigend ? 0 : 1] = (s & 0xFF00) >> 8;
+
+      *outbufp += 2;
+      *outbytesleftp -= 2;
+      return 0;
+    }
+  else
+    {
+      cppchar_t hi, lo;
+
+      if (*outbytesleftp < 4)
+       {
+         *inbufp = save_inbuf;
+         *inbytesleftp = save_inbytesleft;
+         return E2BIG;
+       }
+
+      hi = (s - 0x10000) / 0x400 + 0xD800;
+      lo = (s - 0x10000) % 0x400 + 0xDC00;
+
+      /* Even if we are little-endian, put the high surrogate first.
+        ??? Matches practice?  */
+      outbuf[bigend ? 1 : 0] = (hi & 0x00FF);
+      outbuf[bigend ? 0 : 1] = (hi & 0xFF00) >> 8;
+      outbuf[bigend ? 3 : 2] = (lo & 0x00FF);
+      outbuf[bigend ? 2 : 3] = (lo & 0xFF00) >> 8;
+
+      *outbufp += 4;
+      *outbytesleftp -= 4;
+      return 0;
+    }
+}
+
+static inline int
+one_utf16_to_utf8 (iconv_t bigend, const uchar **inbufp, size_t *inbytesleftp,
+                  uchar **outbufp, size_t *outbytesleftp)
+{
+  cppchar_t s;
+  const uchar *inbuf = *inbufp;
+  int rval;
+
+  if (*inbytesleftp < 2)
+    return EINVAL;
+  s  = inbuf[bigend ? 0 : 1] << 8;
+  s += inbuf[bigend ? 1 : 0];
+
+  /* Low surrogate without immediately preceding high surrogate is invalid.  */
+  if (s >= 0xDC00 && s <= 0xDFFF)
+    return EILSEQ;
+  /* High surrogate must have a following low surrogate.  */
+  else if (s >= 0xD800 && s <= 0xDBFF)
+    {
+      cppchar_t hi = s, lo;
+      if (*inbytesleftp < 4)
+       return EINVAL;
+
+      lo  = inbuf[bigend ? 2 : 3] << 8;
+      lo += inbuf[bigend ? 3 : 2];
+
+      if (lo < 0xDC00 || lo > 0xDFFF)
+       return EILSEQ;
+
+      s = (hi - 0xD800) * 0x400 + (lo - 0xDC00) + 0x10000;
+    }
+
+  rval = one_cppchar_to_utf8 (s, outbufp, outbytesleftp);
+  if (rval)
+    return rval;
+
+  /* Success - update the input pointers (one_cppchar_to_utf8 has done
+     the output pointers for us).  */
+  if (s <= 0xFFFF)
+    {
+      *inbufp += 2;
+      *inbytesleftp -= 2;
+    }
+  else
+    {
+      *inbufp += 4;
+      *inbytesleftp -= 4;
+    }
+  return 0;
+}
+
+/* Helper routine for the next few functions.  The 'const' on
+   one_conversion means that we promise not to modify what function is
+   pointed to, which lets the inliner see through it.  */
+
+static inline bool
+conversion_loop (int (*const one_conversion)(iconv_t, const uchar **, size_t *,
+                                            uchar **, size_t *),
+                iconv_t cd, const uchar *from, size_t flen, struct _cpp_strbuf *to)
+{
+  const uchar *inbuf;
+  uchar *outbuf;
+  size_t inbytesleft, outbytesleft;
+  int rval;
+
+  inbuf = from;
+  inbytesleft = flen;
+  outbuf = to->text + to->len;
+  outbytesleft = to->asize - to->len;
+
+  for (;;)
+    {
+      do
+       rval = one_conversion (cd, &inbuf, &inbytesleft,
+                              &outbuf, &outbytesleft);
+      while (inbytesleft && !rval);
+
+      if (__builtin_expect (inbytesleft == 0, 1))
+       {
+         to->len = to->asize - outbytesleft;
+         return true;
+       }
+      if (rval != E2BIG)
+       {
+         errno = rval;
+         return false;
+       }
+
+      outbytesleft += OUTBUF_BLOCK_SIZE;
+      to->asize += OUTBUF_BLOCK_SIZE;
+      to->text = xrealloc (to->text, to->asize);
+      outbuf = to->text + to->asize - outbytesleft;
+    }
+}
+
+
+/* These functions convert entire strings between character sets.
+   They all have the signature
+
+   bool (*)(iconv_t cd, const uchar *from, size_t flen, struct _cpp_strbuf *to);
+
+   The input string FROM is converted as specified by the function
+   name plus the iconv descriptor CD (which may be fake), and the
+   result appended to TO.  On any error, false is returned, otherwise true.  */
+
+/* These four use the custom conversion code above.  */
+static bool
+convert_utf8_utf16 (iconv_t cd, const uchar *from, size_t flen,
+                   struct _cpp_strbuf *to)
+{
+  return conversion_loop (one_utf8_to_utf16, cd, from, flen, to);
+}
+
+static bool
+convert_utf8_utf32 (iconv_t cd, const uchar *from, size_t flen,
+                   struct _cpp_strbuf *to)
+{
+  return conversion_loop (one_utf8_to_utf32, cd, from, flen, to);
+}
+
+static bool
+convert_utf16_utf8 (iconv_t cd, const uchar *from, size_t flen,
+                   struct _cpp_strbuf *to)
+{
+  return conversion_loop (one_utf16_to_utf8, cd, from, flen, to);
+}
+
+static bool
+convert_utf32_utf8 (iconv_t cd, const uchar *from, size_t flen,
+                   struct _cpp_strbuf *to)
+{
+  return conversion_loop (one_utf32_to_utf8, cd, from, flen, to);
+}
+
+/* Identity conversion, used when we have no alternative.  */
+static bool
+convert_no_conversion (iconv_t cd ATTRIBUTE_UNUSED,
+                      const uchar *from, size_t flen, struct _cpp_strbuf *to)
+{
+  if (to->len + flen > to->asize)
+    {
+      to->asize = to->len + flen;
+      to->text = xrealloc (to->text, to->asize);
+    }
+  memcpy (to->text + to->len, from, flen);
+  to->len += flen;
+  return true;
+}
+
+/* And this one uses the system iconv primitive.  It's a little
+   different, since iconv's interface is a little different.  */
+#if HAVE_ICONV
+static bool
+convert_using_iconv (iconv_t cd, const uchar *from, size_t flen,
+                    struct _cpp_strbuf *to)
+{
+  ICONV_CONST char *inbuf;
+  char *outbuf;
+  size_t inbytesleft, outbytesleft;
+
+  /* Reset conversion descriptor and check that it is valid.  */
+  if (iconv (cd, 0, 0, 0, 0) == (size_t)-1)
+    return false;
+
+  inbuf = (ICONV_CONST char *)from;
+  inbytesleft = flen;
+  outbuf = (char *)to->text + to->len;
+  outbytesleft = to->asize - to->len;
+
+  for (;;)
+    {
+      iconv (cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
+      if (__builtin_expect (inbytesleft == 0, 1))
+       {
+         to->len = to->asize - outbytesleft;
+         return true;
+       }
+      if (errno != E2BIG)
+       return false;
+
+      outbytesleft += OUTBUF_BLOCK_SIZE;
+      to->asize += OUTBUF_BLOCK_SIZE;
+      to->text = xrealloc (to->text, to->asize);
+      outbuf = (char *)to->text + to->asize - outbytesleft;
+    }
+}
+#else
+#define convert_using_iconv 0 /* prevent undefined symbol error below */
+#endif
+
+/* Arrange for the above custom conversion logic to be used automatically
+   when conversion between a suitable pair of character sets is requested.  */
+
+#define APPLY_CONVERSION(CONVERTER, FROM, FLEN, TO) \
+   CONVERTER.func (CONVERTER.cd, FROM, FLEN, TO)
+
+struct conversion
+{
+  const char *pair;
+  convert_f func;
+  iconv_t fake_cd;
+};
+static const struct conversion conversion_tab[] = {
+  { "UTF-8/UTF-32LE", convert_utf8_utf32, (iconv_t)0 },
+  { "UTF-8/UTF-32BE", convert_utf8_utf32, (iconv_t)1 },
+  { "UTF-8/UTF-16LE", convert_utf8_utf16, (iconv_t)0 },
+  { "UTF-8/UTF-16BE", convert_utf8_utf16, (iconv_t)1 },
+  { "UTF-32LE/UTF-8", convert_utf32_utf8, (iconv_t)0 },
+  { "UTF-32BE/UTF-8", convert_utf32_utf8, (iconv_t)1 },
+  { "UTF-16LE/UTF-8", convert_utf16_utf8, (iconv_t)0 },
+  { "UTF-16BE/UTF-8", convert_utf16_utf8, (iconv_t)1 },
+};
+
+/* Subroutine of cpp_init_iconv: initialize and return a
+   cset_converter structure for conversion from FROM to TO.  If
+   iconv_open() fails, issue an error and return an identity
+   converter.  Silently return an identity converter if FROM and TO
+   are identical.  */
+static struct cset_converter
+init_iconv_desc (cpp_reader *pfile, const char *to, const char *from)
+{
+  struct cset_converter ret;
+  char *pair;
+  size_t i;
+
+  if (!strcasecmp (to, from))
+    {
+      ret.func = convert_no_conversion;
+      ret.cd = (iconv_t) -1;
+      return ret;
+    }
+
+  pair = alloca(strlen(to) + strlen(from) + 2);
+
+  strcpy(pair, from);
+  strcat(pair, "/");
+  strcat(pair, to);
+  for (i = 0; i < ARRAY_SIZE (conversion_tab); i++)
+    if (!strcasecmp (pair, conversion_tab[i].pair))
+      {
+       ret.func = conversion_tab[i].func;
+       ret.cd = conversion_tab[i].fake_cd;
+       return ret;
+      }
+
+  /* No custom converter - try iconv.  */
+  if (HAVE_ICONV)
+    {
+      ret.func = convert_using_iconv;
+      ret.cd = iconv_open (to, from);
+
+      if (ret.cd == (iconv_t) -1)
+       {
+         if (errno == EINVAL)
+           cpp_error (pfile, CPP_DL_ERROR, /* XXX should be DL_SORRY */
+                      "conversion from %s to %s not supported by iconv",
+                      from, to);
+         else
+           cpp_errno (pfile, CPP_DL_ERROR, "iconv_open");
+
+         ret.func = convert_no_conversion;
+       }
+    }
+  else
+    {
+      cpp_error (pfile, CPP_DL_ERROR, /* XXX should be DL_SORRY */
+                "no iconv implementation, cannot convert from %s to %s",
+                from, to);
+      ret.func = convert_no_conversion;
+      ret.cd = (iconv_t) -1;
+    }
+  return ret;
+}
+
+/* If charset conversion is requested, initialize iconv(3) descriptors
+   for conversion from the source character set to the execution
+   character sets.  If iconv is not present in the C library, and
+   conversion is requested, issue an error.  */
+
+void
+cpp_init_iconv (cpp_reader *pfile)
+{
+  const char *ncset = CPP_OPTION (pfile, narrow_charset);
+  const char *wcset = CPP_OPTION (pfile, wide_charset);
+  const char *default_wcset;
+
+  bool be = CPP_OPTION (pfile, bytes_big_endian);
+
+  if (CPP_OPTION (pfile, wchar_precision) >= 32)
+    default_wcset = be ? "UTF-32BE" : "UTF-32LE";
+  else if (CPP_OPTION (pfile, wchar_precision) >= 16)
+    default_wcset = be ? "UTF-16BE" : "UTF-16LE";
+  else
+    /* This effectively means that wide strings are not supported,
+       so don't do any conversion at all.  */
+   default_wcset = SOURCE_CHARSET;
+
+  if (!ncset)
+    ncset = SOURCE_CHARSET;
+  if (!wcset)
+    wcset = default_wcset;
+
+  pfile->narrow_cset_desc = init_iconv_desc (pfile, ncset, SOURCE_CHARSET);
+  pfile->wide_cset_desc = init_iconv_desc (pfile, wcset, SOURCE_CHARSET);
+}
+
+void
+_cpp_destroy_iconv (cpp_reader *pfile)
+{
+  if (HAVE_ICONV)
+    {
+      if (pfile->narrow_cset_desc.func == convert_using_iconv)
+       iconv_close (pfile->narrow_cset_desc.cd);
+      if (pfile->wide_cset_desc.func == convert_using_iconv)
+       iconv_close (pfile->wide_cset_desc.cd);
+    }
+}
+
+
+/* Utility routine that computes a mask of the form 0000...111... with
+   WIDTH 1-bits.  */
+static inline size_t
+width_to_mask (size_t width)
+{
+  width = MIN (width, BITS_PER_CPPCHAR_T);
+  if (width >= CHAR_BIT * sizeof (size_t))
+    return ~(size_t) 0;
+  else
+    return ((size_t) 1 << width) - 1;
+}
+
+\f
+
+/* Returns 1 if C is valid in an identifier, 2 if C is valid except at
+   the start of an identifier, and 0 if C is not valid in an
+   identifier.  We assume C has already gone through the checks of
+   _cpp_valid_ucn.  The algorithm is a simple binary search on the
+   table defined in cppucnid.h.  */
+
+static int
+ucn_valid_in_identifier (cpp_reader *pfile, cppchar_t c)
+{
+  int mn, mx, md;
+
+  mn = -1;
+  mx = ARRAY_SIZE (ucnranges);
+  while (mx - mn > 1)
+    {
+      md = (mn + mx) / 2;
+      if (c < ucnranges[md].lo)
+       mx = md;
+      else if (c > ucnranges[md].hi)
+       mn = md;
+      else
+       goto found;
+    }
+  return 0;
+
+ found:
+  /* When -pedantic, we require the character to have been listed by
+     the standard for the current language.  Otherwise, we accept the
+     union of the acceptable sets for C++98 and C99.  */
+  if (CPP_PEDANTIC (pfile)
+      && ((CPP_OPTION (pfile, c99) && !(ucnranges[md].flags & C99))
+         || (CPP_OPTION (pfile, cplusplus)
+             && !(ucnranges[md].flags & CXX))))
+    return 0;
+
+  /* In C99, UCN digits may not begin identifiers.  */
+  if (CPP_OPTION (pfile, c99) && (ucnranges[md].flags & DIG))
+    return 2;
+
+  return 1;
+}
+
+/* [lex.charset]: The character designated by the universal character
+   name \UNNNNNNNN is that character whose character short name in
+   ISO/IEC 10646 is NNNNNNNN; the character designated by the
+   universal character name \uNNNN is that character whose character
+   short name in ISO/IEC 10646 is 0000NNNN.  If the hexadecimal value
+   for a universal character name is less than 0x20 or in the range
+   0x7F-0x9F (inclusive), or if the universal character name
+   designates a character in the basic source character set, then the
+   program is ill-formed.
+
+   *PSTR must be preceded by "\u" or "\U"; it is assumed that the
+   buffer end is delimited by a non-hex digit.  Returns zero if UCNs
+   are not part of the relevant standard, or if the string beginning
+   at *PSTR doesn't syntactically match the form 'NNNN' or 'NNNNNNNN'.
+
+   Otherwise the nonzero value of the UCN, whether valid or invalid,
+   is returned.  Diagnostics are emitted for invalid values.  PSTR
+   is updated to point one beyond the UCN, or to the syntactically
+   invalid character.
+
+   IDENTIFIER_POS is 0 when not in an identifier, 1 for the start of
+   an identifier, or 2 otherwise.
+*/
+
+cppchar_t
+_cpp_valid_ucn (cpp_reader *pfile, const uchar **pstr,
+               const uchar *limit, int identifier_pos)
+{
+  cppchar_t result, c;
+  unsigned int length;
+  const uchar *str = *pstr;
+  const uchar *base = str - 2;
+
+  if (!CPP_OPTION (pfile, cplusplus) && !CPP_OPTION (pfile, c99))
+    cpp_error (pfile, CPP_DL_WARNING,
+              "universal character names are only valid in C++ and C99");
+  else if (CPP_WTRADITIONAL (pfile) && identifier_pos == 0)
+    cpp_error (pfile, CPP_DL_WARNING,
+              "the meaning of '\\%c' is different in traditional C",
+              (int) str[-1]);
+
+  if (str[-1] == 'u')
+    length = 4;
+  else if (str[-1] == 'U')
+    length = 8;
+  else
+    abort();
+
+  result = 0;
+  do
+    {
+      c = *str;
+      if (!ISXDIGIT (c))
+       break;
+      str++;
+      result = (result << 4) + hex_value (c);
+    }
+  while (--length && str < limit);
+
+  *pstr = str;
+  if (length)
+    {
+      /* We'll error when we try it out as the start of an identifier.  */
+      cpp_error (pfile, CPP_DL_ERROR,
+                "incomplete universal character name %.*s",
+                (int) (str - base), base);
+      result = 1;
+    }
+  /* The standard permits $, @ and ` to be specified as UCNs.  We use
+     hex escapes so that this also works with EBCDIC hosts.  */
+  else if ((result < 0xa0
+           && (result != 0x24 && result != 0x40 && result != 0x60))
+          || (result & 0x80000000)
+          || (result >= 0xD800 && result <= 0xDFFF))
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+                "%.*s is not a valid universal character",
+                (int) (str - base), base);
+      result = 1;
+    }
+  else if (identifier_pos)
+    {
+      int validity = ucn_valid_in_identifier (pfile, result);
+
+      if (validity == 0)
+       cpp_error (pfile, CPP_DL_ERROR,
+                  "universal character %.*s is not valid in an identifier",
+                  (int) (str - base), base);
+      else if (validity == 2 && identifier_pos == 1)
+       cpp_error (pfile, CPP_DL_ERROR,
+   "universal character %.*s is not valid at the start of an identifier",
+                  (int) (str - base), base);
+    }
+
+  if (result == 0)
+    result = 1;
+
+  return result;
+}
+
+/* Convert an UCN, pointed to by FROM, to UTF-8 encoding, then translate
+   it to the execution character set and write the result into TBUF.
+   An advanced pointer is returned.  Issues all relevant diagnostics.  */
+
+
+static const uchar *
+convert_ucn (cpp_reader *pfile, const uchar *from, const uchar *limit,
+            struct _cpp_strbuf *tbuf, bool wide)
+{
+  cppchar_t ucn;
+  uchar buf[6];
+  uchar *bufp = buf;
+  size_t bytesleft = 6;
+  int rval;
+  struct cset_converter cvt
+    = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc;
+
+  from++;  /* Skip u/U.  */
+  ucn = _cpp_valid_ucn (pfile, &from, limit, 0);
+
+  rval = one_cppchar_to_utf8 (ucn, &bufp, &bytesleft);
+  if (rval)
+    {
+      errno = rval;
+      cpp_errno (pfile, CPP_DL_ERROR,
+                "converting UCN to source character set");
+    }
+  else if (!APPLY_CONVERSION (cvt, buf, 6 - bytesleft, tbuf))
+    cpp_errno (pfile, CPP_DL_ERROR,
+              "converting UCN to execution character set");
+
+  return from;
+}
+
+static void
+emit_numeric_escape (cpp_reader *pfile, cppchar_t n,
+                    struct _cpp_strbuf *tbuf, bool wide)
+{
+  if (wide)
+    {
+      /* We have to render this into the target byte order, which may not
+        be our byte order.  */
+      bool bigend = CPP_OPTION (pfile, bytes_big_endian);
+      size_t width = CPP_OPTION (pfile, wchar_precision);
+      size_t cwidth = CPP_OPTION (pfile, char_precision);
+      size_t cmask = width_to_mask (cwidth);
+      size_t nbwc = width / cwidth;
+      size_t i;
+      size_t off = tbuf->len;
+      cppchar_t c;
+
+      if (tbuf->len + nbwc > tbuf->asize)
+       {
+         tbuf->asize += OUTBUF_BLOCK_SIZE;
+         tbuf->text = xrealloc (tbuf->text, tbuf->asize);
+       }
+
+      for (i = 0; i < nbwc; i++)
+       {
+         c = n & cmask;
+         n >>= cwidth;
+         tbuf->text[off + (bigend ? nbwc - i - 1 : i)] = c;
+       }
+      tbuf->len += nbwc;
+    }
+  else
+    {
+      if (tbuf->len + 1 > tbuf->asize)
+       {
+         tbuf->asize += OUTBUF_BLOCK_SIZE;
+         tbuf->text = xrealloc (tbuf->text, tbuf->asize);
+       }
+      tbuf->text[tbuf->len++] = n;
+    }
+}
+
+/* Convert a hexadecimal escape, pointed to by FROM, to the execution
+   character set and write it into the string buffer TBUF.  Returns an
+   advanced pointer, and issues diagnostics as necessary.
+   No character set translation occurs; this routine always produces the
+   execution-set character with numeric value equal to the given hex
+   number.  You can, e.g. generate surrogate pairs this way.  */
+static const uchar *
+convert_hex (cpp_reader *pfile, const uchar *from, const uchar *limit,
+            struct _cpp_strbuf *tbuf, bool wide)
+{
+  cppchar_t c, n = 0, overflow = 0;
+  int digits_found = 0;
+  size_t width = (wide ? CPP_OPTION (pfile, wchar_precision)
+                 : CPP_OPTION (pfile, char_precision));
+  size_t mask = width_to_mask (width);
+
+  if (CPP_WTRADITIONAL (pfile))
+    cpp_error (pfile, CPP_DL_WARNING,
+              "the meaning of '\\x' is different in traditional C");
+
+  from++;  /* Skip 'x'.  */
+  while (from < limit)
+    {
+      c = *from;
+      if (! hex_p (c))
+       break;
+      from++;
+      overflow |= n ^ (n << 4 >> 4);
+      n = (n << 4) + hex_value (c);
+      digits_found = 1;
+    }
+
+  if (!digits_found)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+                "\\x used with no following hex digits");
+      return from;
+    }
+
+  if (overflow | (n != (n & mask)))
+    {
+      cpp_error (pfile, CPP_DL_PEDWARN,
+                "hex escape sequence out of range");
+      n &= mask;
+    }
+
+  emit_numeric_escape (pfile, n, tbuf, wide);
+
+  return from;
+}
+
+/* Convert an octal escape, pointed to by FROM, to the execution
+   character set and write it into the string buffer TBUF.  Returns an
+   advanced pointer, and issues diagnostics as necessary.
+   No character set translation occurs; this routine always produces the
+   execution-set character with numeric value equal to the given octal
+   number.  */
+static const uchar *
+convert_oct (cpp_reader *pfile, const uchar *from, const uchar *limit,
+            struct _cpp_strbuf *tbuf, bool wide)
+{
+  size_t count = 0;
+  cppchar_t c, n = 0;
+  size_t width = (wide ? CPP_OPTION (pfile, wchar_precision)
+                 : CPP_OPTION (pfile, char_precision));
+  size_t mask = width_to_mask (width);
+  bool overflow = false;
+
+  while (from < limit && count++ < 3)
+    {
+      c = *from;
+      if (c < '0' || c > '7')
+       break;
+      from++;
+      overflow |= n ^ (n << 3 >> 3);
+      n = (n << 3) + c - '0';
+    }
+
+  if (n != (n & mask))
+    {
+      cpp_error (pfile, CPP_DL_PEDWARN,
+                "octal escape sequence out of range");
+      n &= mask;
+    }
+
+  emit_numeric_escape (pfile, n, tbuf, wide);
+
+  return from;
+}
+
+/* Convert an escape sequence (pointed to by FROM) to its value on
+   the target, and to the execution character set.  Do not scan past
+   LIMIT.  Write the converted value into TBUF.  Returns an advanced
+   pointer.  Handles all relevant diagnostics.  */
+static const uchar *
+convert_escape (cpp_reader *pfile, const uchar *from, const uchar *limit,
+               struct _cpp_strbuf *tbuf, bool wide)
+{
+  /* Values of \a \b \e \f \n \r \t \v respectively.  */
+#if HOST_CHARSET == HOST_CHARSET_ASCII
+  static const uchar charconsts[] = {  7,  8, 27, 12, 10, 13,  9, 11 };
+#elif HOST_CHARSET == HOST_CHARSET_EBCDIC
+  static const uchar charconsts[] = { 47, 22, 39, 12, 21, 13,  5, 11 };
+#else
+#error "unknown host character set"
+#endif
+
+  uchar c;
+  struct cset_converter cvt
+    = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc;
+
+  c = *from;
+  switch (c)
+    {
+      /* UCNs, hex escapes, and octal escapes are processed separately.  */
+    case 'u': case 'U':
+      return convert_ucn (pfile, from, limit, tbuf, wide);
+
+    case 'x':
+      return convert_hex (pfile, from, limit, tbuf, wide);
+      break;
+
+    case '0':  case '1':  case '2':  case '3':
+    case '4':  case '5':  case '6':  case '7':
+      return convert_oct (pfile, from, limit, tbuf, wide);
+
+      /* Various letter escapes.  Get the appropriate host-charset
+        value into C.  */
+    case '\\': case '\'': case '"': case '?': break;
+
+    case '(': case '{': case '[': case '%':
+      /* '\(', etc, can be used at the beginning of a line in a long
+        string split onto multiple lines with \-newline, to prevent
+        Emacs or other text editors from getting confused.  '\%' can
+        be used to prevent SCCS from mangling printf format strings.  */
+      if (CPP_PEDANTIC (pfile))
+       goto unknown;
+      break;
+
+    case 'b': c = charconsts[1];  break;
+    case 'f': c = charconsts[3];  break;
+    case 'n': c = charconsts[4];  break;
+    case 'r': c = charconsts[5];  break;
+    case 't': c = charconsts[6];  break;
+    case 'v': c = charconsts[7];  break;
+
+    case 'a':
+      if (CPP_WTRADITIONAL (pfile))
+       cpp_error (pfile, CPP_DL_WARNING,
+                  "the meaning of '\\a' is different in traditional C");
+      c = charconsts[0];
+      break;
+
+    case 'e': case 'E':
+      if (CPP_PEDANTIC (pfile))
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "non-ISO-standard escape sequence, '\\%c'", (int) c);
+      c = charconsts[2];
+      break;
+
+    default:
+    unknown:
+      if (ISGRAPH (c))
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "unknown escape sequence '\\%c'", (int) c);
+      else
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "unknown escape sequence: '\\%03o'", (int) c);
+    }
+
+  /* Now convert what we have to the execution character set.  */
+  if (!APPLY_CONVERSION (cvt, &c, 1, tbuf))
+    cpp_errno (pfile, CPP_DL_ERROR,
+              "converting escape sequence to execution character set");
+
+  return from + 1;
+}
+\f
+/* FROM is an array of cpp_string structures of length COUNT.  These
+   are to be converted from the source to the execution character set,
+   escape sequences translated, and finally all are to be
+   concatenated.  WIDE indicates whether or not to produce a wide
+   string.  The result is written into TO.  Returns true for success,
+   false for failure.  */
+bool
+cpp_interpret_string (cpp_reader *pfile, const cpp_string *from, size_t count,
+                     cpp_string *to, bool wide)
+{
+  struct _cpp_strbuf tbuf;
+  const uchar *p, *base, *limit;
+  size_t i;
+  struct cset_converter cvt
+    = wide ? pfile->wide_cset_desc : pfile->narrow_cset_desc;
+
+  tbuf.asize = MAX (OUTBUF_BLOCK_SIZE, from->len);
+  tbuf.text = xmalloc (tbuf.asize);
+  tbuf.len = 0;
+
+  for (i = 0; i < count; i++)
+    {
+      p = from[i].text;
+      if (*p == 'L') p++;
+      p++; /* Skip leading quote.  */
+      limit = from[i].text + from[i].len - 1; /* Skip trailing quote.  */
+
+      for (;;)
+       {
+         base = p;
+         while (p < limit && *p != '\\')
+           p++;
+         if (p > base)
+           {
+             /* We have a run of normal characters; these can be fed
+                directly to convert_cset.  */
+             if (!APPLY_CONVERSION (cvt, base, p - base, &tbuf))
+               goto fail;
+           }
+         if (p == limit)
+           break;
+
+         p = convert_escape (pfile, p + 1, limit, &tbuf, wide);
+       }
+    }
+  /* NUL-terminate the 'to' buffer and translate it to a cpp_string
+     structure.  */
+  emit_numeric_escape (pfile, 0, &tbuf, wide);
+  tbuf.text = xrealloc (tbuf.text, tbuf.len);
+  to->text = tbuf.text;
+  to->len = tbuf.len;
+  return true;
+
+ fail:
+  cpp_errno (pfile, CPP_DL_ERROR, "converting to execution character set");
+  free (tbuf.text);
+  return false;
+}
+
+/* Subroutine of do_line and do_linemarker.  Convert escape sequences
+   in a string, but do not perform character set conversion.  */
+bool
+_cpp_interpret_string_notranslate (cpp_reader *pfile, const cpp_string *in,
+                                  cpp_string *out)
+{
+  struct cset_converter save_narrow_cset_desc = pfile->narrow_cset_desc;
+  bool retval;
+
+  pfile->narrow_cset_desc.func = convert_no_conversion;
+  pfile->narrow_cset_desc.cd = (iconv_t) -1;
+
+  retval = cpp_interpret_string (pfile, in, 1, out, false);
+
+  pfile->narrow_cset_desc = save_narrow_cset_desc;
+  return retval;
+}
+
+\f
+/* Subroutine of cpp_interpret_charconst which performs the conversion
+   to a number, for narrow strings.  STR is the string structure returned
+   by cpp_interpret_string.  PCHARS_SEEN and UNSIGNEDP are as for
+   cpp_interpret_charconst.  */
+static cppchar_t
+narrow_str_to_charconst (cpp_reader *pfile, cpp_string str,
+                        unsigned int *pchars_seen, int *unsignedp)
+{
+  size_t width = CPP_OPTION (pfile, char_precision);
+  size_t max_chars = CPP_OPTION (pfile, int_precision) / width;
+  size_t mask = width_to_mask (width);
+  size_t i;
+  cppchar_t result, c;
+  bool unsigned_p;
+
+  /* The value of a multi-character character constant, or a
+     single-character character constant whose representation in the
+     execution character set is more than one byte long, is
+     implementation defined.  This implementation defines it to be the
+     number formed by interpreting the byte sequence in memory as a
+     big-endian binary number.  If overflow occurs, the high bytes are
+     lost, and a warning is issued.
+
+     We don't want to process the NUL terminator handed back by
+     cpp_interpret_string.  */
+  result = 0;
+  for (i = 0; i < str.len - 1; i++)
+    {
+      c = str.text[i] & mask;
+      if (width < BITS_PER_CPPCHAR_T)
+       result = (result << width) | c;
+      else
+       result = c;
+    }
+
+  if (i > max_chars)
+    {
+      i = max_chars;
+      cpp_error (pfile, CPP_DL_WARNING,
+                "character constant too long for its type");
+    }
+  else if (i > 1 && CPP_OPTION (pfile, warn_multichar))
+    cpp_error (pfile, CPP_DL_WARNING, "multi-character character constant");
+
+  /* Multichar constants are of type int and therefore signed.  */
+  if (i > 1)
+    unsigned_p = 0;
+  else
+    unsigned_p = CPP_OPTION (pfile, unsigned_char);
+
+  /* Truncate the constant to its natural width, and simultaneously
+     sign- or zero-extend to the full width of cppchar_t.
+     For single-character constants, the value is WIDTH bits wide.
+     For multi-character constants, the value is INT_PRECISION bits wide.  */
+  if (i > 1)
+    width = CPP_OPTION (pfile, int_precision);
+  if (width < BITS_PER_CPPCHAR_T)
+    {
+      mask = ((cppchar_t) 1 << width) - 1;
+      if (unsigned_p || !(result & (1 << (width - 1))))
+       result &= mask;
+      else
+       result |= ~mask;
+    }
+  *pchars_seen = i;
+  *unsignedp = unsigned_p;
+  return result;
+}
+
+/* Subroutine of cpp_interpret_charconst which performs the conversion
+   to a number, for wide strings.  STR is the string structure returned
+   by cpp_interpret_string.  PCHARS_SEEN and UNSIGNEDP are as for
+   cpp_interpret_charconst.  */
+static cppchar_t
+wide_str_to_charconst (cpp_reader *pfile, cpp_string str,
+                      unsigned int *pchars_seen, int *unsignedp)
+{
+  bool bigend = CPP_OPTION (pfile, bytes_big_endian);
+  size_t width = CPP_OPTION (pfile, wchar_precision);
+  size_t cwidth = CPP_OPTION (pfile, char_precision);
+  size_t mask = width_to_mask (width);
+  size_t cmask = width_to_mask (cwidth);
+  size_t nbwc = width / cwidth;
+  size_t off, i;
+  cppchar_t result = 0, c;
+
+  /* This is finicky because the string is in the target's byte order,
+     which may not be our byte order.  Only the last character, ignoring
+     the NUL terminator, is relevant.  */
+  off = str.len - (nbwc * 2);
+  result = 0;
+  for (i = 0; i < nbwc; i++)
+    {
+      c = bigend ? str.text[off + i] : str.text[off + nbwc - i - 1];
+      result = (result << cwidth) | (c & cmask);
+    }
+
+  /* Wide character constants have type wchar_t, and a single
+     character exactly fills a wchar_t, so a multi-character wide
+     character constant is guaranteed to overflow.  */
+  if (off > 0)
+    cpp_error (pfile, CPP_DL_WARNING,
+              "character constant too long for its type");
+
+  /* Truncate the constant to its natural width, and simultaneously
+     sign- or zero-extend to the full width of cppchar_t.  */
+  if (width < BITS_PER_CPPCHAR_T)
+    {
+      if (CPP_OPTION (pfile, unsigned_wchar) || !(result & (1 << (width - 1))))
+       result &= mask;
+      else
+       result |= ~mask;
+    }
+
+  *unsignedp = CPP_OPTION (pfile, unsigned_wchar);
+  *pchars_seen = 1;
+  return result;
+}
+
+/* Interpret a (possibly wide) character constant in TOKEN.
+   PCHARS_SEEN points to a variable that is filled in with the number
+   of characters seen, and UNSIGNEDP to a variable that indicates
+   whether the result has signed type.  */
+cppchar_t
+cpp_interpret_charconst (cpp_reader *pfile, const cpp_token *token,
+                        unsigned int *pchars_seen, int *unsignedp)
+{
+  cpp_string str = { 0, 0 };
+  bool wide = (token->type == CPP_WCHAR);
+  cppchar_t result;
+
+  /* an empty constant will appear as L'' or '' */
+  if (token->val.str.len == (size_t) (2 + wide))
+    {
+      cpp_error (pfile, CPP_DL_ERROR, "empty character constant");
+      return 0;
+    }
+  else if (!cpp_interpret_string (pfile, &token->val.str, 1, &str, wide))
+    return 0;
+
+  if (wide)
+    result = wide_str_to_charconst (pfile, str, pchars_seen, unsignedp);
+  else
+    result = narrow_str_to_charconst (pfile, str, pchars_seen, unsignedp);
+
+  if (str.text != token->val.str.text)
+    free ((void *)str.text);
+
+  return result;
+}
+
+uchar *
+_cpp_convert_input (cpp_reader *pfile, const char *input_charset,
+                   uchar *input, size_t size, size_t len, off_t *st_size)
+{
+  struct cset_converter input_cset;
+  struct _cpp_strbuf to;
+
+  input_cset = init_iconv_desc (pfile, SOURCE_CHARSET, input_charset);
+  if (input_cset.func == convert_no_conversion)
+    {
+      to.text = input;
+      to.asize = size;
+      to.len = len;
+    }
+  else
+    {
+      to.asize = MAX (65536, len);
+      to.text = xmalloc (to.asize);
+      to.len = 0;
+
+      if (!APPLY_CONVERSION (input_cset, input, len, &to))
+       cpp_error (pfile, CPP_DL_ERROR,
+                  "failure to convert %s to %s",
+                  CPP_OPTION (pfile, input_charset), SOURCE_CHARSET);
+
+      free (input);
+    }
+
+  /* Clean up the mess.  */
+  if (input_cset.func == convert_using_iconv)
+    iconv_close (input_cset.cd);
+
+  /* Resize buffer if we allocated substantially too much, or if we
+     haven't enough space for the \n-terminator.  */
+  if (to.len + 4096 < to.asize || to.len >= to.asize)
+    to.text = xrealloc (to.text, to.len + 1);
+
+  to.text[to.len] = '\n';
+  *st_size = to.len;
+  return to.text;
+}
+
+const char *
+_cpp_default_encoding (void)
+{
+  const char *current_encoding = NULL;
+
+#if defined (HAVE_LOCALE_H) && defined (HAVE_LANGINFO_CODESET)
+  setlocale (LC_CTYPE, "");
+  current_encoding = nl_langinfo (CODESET);
+#endif
+  if (current_encoding == NULL || *current_encoding == '\0')
+    current_encoding = SOURCE_CHARSET;
+
+  return current_encoding;
+}
index fd29add6833b8bb4a3d963511f98385c09af592d..60b215372a73b29bd7d12b02c8a3696033f1f7ea 100644 (file)
@@ -1,6 +1,6 @@
 /* CPP Library.
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2003 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -19,13 +19,26 @@ You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-/* This file contains data definitions shared between cpplib and
-   tradcpp.  */
-
 #include "config.h"
 #include "system.h"
 #include "cppdefault.h"
 
+#ifndef STANDARD_INCLUDE_DIR
+#define STANDARD_INCLUDE_DIR "/usr/include"
+#endif
+
+#ifndef STANDARD_INCLUDE_COMPONENT
+#define STANDARD_INCLUDE_COMPONENT 0
+#endif
+
+#if defined (CROSS_COMPILE) && !defined (TARGET_SYSTEM_ROOT)
+# undef LOCAL_INCLUDE_DIR
+# undef SYSTEM_INCLUDE_DIR
+# undef STANDARD_INCLUDE_DIR
+#else
+# undef CROSS_INCLUDE_DIR
+#endif
+
 const struct default_include cpp_include_defaults[]
 #ifdef INCLUDE_DEFAULTS
 = INCLUDE_DEFAULTS;
index c87e27d5deec1a5d9ecca0916fee9d0c3e0eb86a..368e082c79d9cd3756773a8db7d8df2e8ffb0749 100644 (file)
@@ -1,6 +1,6 @@
 /* CPP Library.
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2003 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -22,26 +22,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #ifndef GCC_CPPDEFAULT_H
 #define GCC_CPPDEFAULT_H
 
-/* This header contains declarations and/or #defines for all the
-   hard-wired defaults in cpp.  Note it's used by both cpplib and
-   tradcpp.  */
-
-#ifndef STANDARD_INCLUDE_DIR
-#define STANDARD_INCLUDE_DIR "/usr/include"
-#endif
-
-#ifndef STANDARD_INCLUDE_COMPONENT
-#define STANDARD_INCLUDE_COMPONENT 0
-#endif
-
-#if defined (CROSS_COMPILE) && !defined (TARGET_SYSTEM_ROOT)
-# undef LOCAL_INCLUDE_DIR
-# undef SYSTEM_INCLUDE_DIR
-# undef STANDARD_INCLUDE_DIR
-#else
-# undef CROSS_INCLUDE_DIR
-#endif
-
 /* This is the default list of directories to search for include files.
    It may be overridden by the various -I and -ixxx options.
 
@@ -57,11 +37,11 @@ struct default_include
   const char *const fname;     /* The name of the directory.  */
   const char *const component; /* The component containing the directory
                                   (see update_path in prefix.c) */
-  const int cplusplus;         /* Only look here if we're compiling C++.  */
-  const int cxx_aware;         /* Includes in this directory don't need to
+  const char cplusplus;                /* Only look here if we're compiling C++.  */
+  const char cxx_aware;                /* Includes in this directory don't need to
                                   be wrapped in extern "C" when compiling
                                   C++.  */
-  const int add_sysroot;       /* FNAME should be prefixed by
+  const char add_sysroot;      /* FNAME should be prefixed by
                                   cpp_SYSROOT.  */
 };
 
index 360bc8ccef36f2a34959a23f1f9874bcf0d6e22a..61763cc1826f7e53c14139c2f84f65a3b657d431 100644 (file)
@@ -29,36 +29,35 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #include "cpphash.h"
 #include "intl.h"
 
-static void print_location PARAMS ((cpp_reader *, unsigned int, unsigned int));
+static void print_location (cpp_reader *, fileline, unsigned int);
 
 /* Print the logical file location (LINE, COL) in preparation for a
    diagnostic.  Outputs the #include chain if it has changed.  A line
    of zero suppresses the include stack, and outputs the program name
    instead.  */
 static void
-print_location (pfile, line, col)
-     cpp_reader *pfile;
-     unsigned int line, col;
+print_location (cpp_reader *pfile, fileline line, unsigned int col)
 {
-  if (!pfile->buffer || line == 0)
+  if (line == 0)
     fprintf (stderr, "%s: ", progname);
   else
     {
       const struct line_map *map;
+      unsigned int lin;
 
-      map = lookup_line (&pfile->line_maps, line);
-      print_containing_files (&pfile->line_maps, map);
+      map = linemap_lookup (&pfile->line_maps, line);
+      linemap_print_containing_files (&pfile->line_maps, map);
 
-      line = SOURCE_LINE (map, line);
+      lin = SOURCE_LINE (map, line);
       if (col == 0)
        col = 1;
 
-      if (line == 0)
+      if (lin == 0)
        fprintf (stderr, "%s:", map->to_file);
       else if (CPP_OPTION (pfile, show_column) == 0)
-       fprintf (stderr, "%s:%u:", map->to_file, line);
+       fprintf (stderr, "%s:%u:", map->to_file, lin);
       else
-       fprintf (stderr, "%s:%u:%u:", map->to_file, line, col);
+       fprintf (stderr, "%s:%u:%u:", map->to_file, lin, col);
 
       fputc (' ', stderr);
     }
@@ -70,48 +69,46 @@ print_location (pfile, line, col)
    the correct place by default.  Returns 0 if the error has been
    suppressed.  */
 int
-_cpp_begin_message (pfile, code, line, column)
-     cpp_reader *pfile;
-     int code;
-     unsigned int line, column;
+_cpp_begin_message (cpp_reader *pfile, int code, fileline line,
+                   unsigned int column)
 {
-  int level = DL_EXTRACT (code);
+  int level = CPP_DL_EXTRACT (code);
 
   switch (level)
     {
-    case DL_WARNING:
-    case DL_PEDWARN:
+    case CPP_DL_WARNING:
+    case CPP_DL_PEDWARN:
       if (CPP_IN_SYSTEM_HEADER (pfile)
          && ! CPP_OPTION (pfile, warn_system_headers))
        return 0;
       /* Fall through.  */
 
-    case DL_WARNING_SYSHDR:
+    case CPP_DL_WARNING_SYSHDR:
       if (CPP_OPTION (pfile, warnings_are_errors)
-         || (level == DL_PEDWARN && CPP_OPTION (pfile, pedantic_errors)))
+         || (level == CPP_DL_PEDWARN && CPP_OPTION (pfile, pedantic_errors)))
        {
          if (CPP_OPTION (pfile, inhibit_errors))
            return 0;
-         level = DL_ERROR;
+         level = CPP_DL_ERROR;
          pfile->errors++;
        }
       else if (CPP_OPTION (pfile, inhibit_warnings))
        return 0;
       break;
 
-    case DL_ERROR:
+    case CPP_DL_ERROR:
       if (CPP_OPTION (pfile, inhibit_errors))
        return 0;
       /* ICEs cannot be inhibited.  */
-    case DL_ICE:
+    case CPP_DL_ICE:
       pfile->errors++;
       break;
     }
 
   print_location (pfile, line, column);
-  if (DL_WARNING_P (level))
+  if (CPP_DL_WARNING_P (level))
     fputs (_("warning: "), stderr);
-  else if (level == DL_ICE)
+  else if (level == CPP_DL_ICE)
     fputs (_("internal error: "), stderr);
 
   return 1;
@@ -126,64 +123,52 @@ _cpp_begin_message (pfile, code, line, column)
 
 /* Print an error at the location of the previously lexed token.  */
 void
-cpp_error VPARAMS ((cpp_reader * pfile, int level, const char *msgid, ...))
+cpp_error (cpp_reader * pfile, int level, const char *msgid, ...)
 {
-  unsigned int line, column;
+  fileline line;
+  unsigned int column;
+  va_list ap;
+  
+  va_start (ap, msgid);
 
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, int, level);
-  VA_FIXEDARG (ap, const char *, msgid);
-
-  if (pfile->buffer)
+  if (CPP_OPTION (pfile, traditional))
     {
-      if (CPP_OPTION (pfile, traditional))
-       {
-         if (pfile->state.in_directive)
-           line = pfile->directive_line;
-         else
-           line = pfile->line;
-         column = 0;
-       }
+      if (pfile->state.in_directive)
+       line = pfile->directive_line;
       else
-       {
-         line = pfile->cur_token[-1].line;
-         column = pfile->cur_token[-1].col;
-       }
+       line = pfile->line;
+      column = 0;
     }
   else
-    line = column = 0;
+    {
+      line = pfile->cur_token[-1].line;
+      column = pfile->cur_token[-1].col;
+    }
 
   if (_cpp_begin_message (pfile, level, line, column))
     v_message (msgid, ap);
 
-  VA_CLOSE (ap);
+  va_end (ap);
 }
 
 /* Print an error at a specific location.  */
 void
-cpp_error_with_line VPARAMS ((cpp_reader *pfile, int level,
-                             unsigned int line, unsigned int column,
-                             const char *msgid, ...))
+cpp_error_with_line (cpp_reader *pfile, int level,
+                    fileline line, unsigned int column,
+                    const char *msgid, ...)
 {
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, cpp_reader *, pfile);
-  VA_FIXEDARG (ap, int, level);
-  VA_FIXEDARG (ap, unsigned int, line);
-  VA_FIXEDARG (ap, unsigned int, column);
-  VA_FIXEDARG (ap, const char *, msgid);
+  va_list ap;
+  
+  va_start (ap, msgid);
 
   if (_cpp_begin_message (pfile, level, line, column))
     v_message (msgid, ap);
 
-  VA_CLOSE (ap);
+  va_end (ap);
 }
 
 void
-cpp_errno (pfile, level, msgid)
-     cpp_reader *pfile;
-     int level;
-     const char *msgid;
+cpp_errno (cpp_reader *pfile, int level, const char *msgid)
 {
   if (msgid[0] == '\0')
     msgid = _("stdout");
index 12919f6f88f14d4f5b5b8e50157715a1d04561d1..cb35b6c782fd3bdbda6a765ee8117d8427ebcbbe 100644 (file)
@@ -38,34 +38,31 @@ struct op
 /* Some simple utility routines on double integers.  */
 #define num_zerop(num) ((num.low | num.high) == 0)
 #define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
-static bool num_positive PARAMS ((cpp_num, size_t));
-static bool num_greater_eq PARAMS ((cpp_num, cpp_num, size_t));
-static cpp_num num_trim PARAMS ((cpp_num, size_t));
-static cpp_num num_part_mul PARAMS ((cpp_num_part, cpp_num_part));
-
-static cpp_num num_unary_op PARAMS ((cpp_reader *, cpp_num, enum cpp_ttype));
-static cpp_num num_binary_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
-                                     enum cpp_ttype));
-static cpp_num num_negate PARAMS ((cpp_num, size_t));
-static cpp_num num_bitwise_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
-                                      enum cpp_ttype));
-static cpp_num num_inequality_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
-                                         enum cpp_ttype));
-static cpp_num num_equality_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
-                                       enum cpp_ttype));
-static cpp_num num_mul PARAMS ((cpp_reader *, cpp_num, cpp_num));
-static cpp_num num_div_op PARAMS ((cpp_reader *, cpp_num, cpp_num,
-                                  enum cpp_ttype));
-static cpp_num num_lshift PARAMS ((cpp_num, size_t, size_t));
-static cpp_num num_rshift PARAMS ((cpp_num, size_t, size_t));
-
-static cpp_num append_digit PARAMS ((cpp_num, int, int, size_t));
-static cpp_num parse_defined PARAMS ((cpp_reader *));
-static cpp_num eval_token PARAMS ((cpp_reader *, const cpp_token *));
-static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype));
-static unsigned int interpret_float_suffix PARAMS ((const uchar *, size_t));
-static unsigned int interpret_int_suffix PARAMS ((const uchar *, size_t));
-static void check_promotion PARAMS ((cpp_reader *, const struct op *));
+static bool num_positive (cpp_num, size_t);
+static bool num_greater_eq (cpp_num, cpp_num, size_t);
+static cpp_num num_trim (cpp_num, size_t);
+static cpp_num num_part_mul (cpp_num_part, cpp_num_part);
+
+static cpp_num num_unary_op (cpp_reader *, cpp_num, enum cpp_ttype);
+static cpp_num num_binary_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_negate (cpp_num, size_t);
+static cpp_num num_bitwise_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num,
+                                 enum cpp_ttype);
+static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num,
+                               enum cpp_ttype);
+static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num);
+static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_lshift (cpp_num, size_t, size_t);
+static cpp_num num_rshift (cpp_num, size_t, size_t);
+
+static cpp_num append_digit (cpp_num, int, int, size_t);
+static cpp_num parse_defined (cpp_reader *);
+static cpp_num eval_token (cpp_reader *, const cpp_token *);
+static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype);
+static unsigned int interpret_float_suffix (const uchar *, size_t);
+static unsigned int interpret_int_suffix (const uchar *, size_t);
+static void check_promotion (cpp_reader *, const struct op *);
 
 /* Token type abuse to create unary plus and minus operators.  */
 #define CPP_UPLUS (CPP_LAST_CPP_OP + 1)
@@ -74,17 +71,16 @@ static void check_promotion PARAMS ((cpp_reader *, const struct op *));
 /* With -O2, gcc appears to produce nice code, moving the error
    message load and subsequent jump completely out of the main path.  */
 #define SYNTAX_ERROR(msgid) \
-  do { cpp_error (pfile, DL_ERROR, msgid); goto syntax_error; } while(0)
+  do { cpp_error (pfile, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)
 #define SYNTAX_ERROR2(msgid, arg) \
-  do { cpp_error (pfile, DL_ERROR, msgid, arg); goto syntax_error; } while(0)
+  do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \
+  while(0)
 
 /* Subroutine of cpp_classify_number.  S points to a float suffix of
    length LEN, possibly zero.  Returns 0 for an invalid suffix, or a
    flag vector describing the suffix.  */
 static unsigned int
-interpret_float_suffix (s, len)
-     const uchar *s;
-     size_t len;
+interpret_float_suffix (const uchar *s, size_t len)
 {
   size_t f = 0, l = 0, i = 0;
 
@@ -111,9 +107,7 @@ interpret_float_suffix (s, len)
    of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
    flag vector describing the suffix.  */
 static unsigned int
-interpret_int_suffix (s, len)
-     const uchar *s;
-     size_t len;
+interpret_int_suffix (const uchar *s, size_t len)
 {
   size_t u, l, i;
 
@@ -147,9 +141,7 @@ interpret_int_suffix (s, len)
    floating point, or invalid), radix (decimal, octal, hexadecimal),
    and type suffixes.  */
 unsigned int
-cpp_classify_number (pfile, token)
-     cpp_reader *pfile;
-     const cpp_token *token;
+cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
 {
   const uchar *str = token->val.str.text;
   const uchar *limit;
@@ -173,7 +165,8 @@ cpp_classify_number (pfile, token)
       str++;
 
       /* Require at least one hex digit to classify it as hex.  */
-      if ((*str == 'x' || *str == 'X') && ISXDIGIT (str[1]))
+      if ((*str == 'x' || *str == 'X')
+         && (str[1] == '.' || ISXDIGIT (str[1])))
        {
          radix = 16;
          str++;
@@ -221,7 +214,7 @@ cpp_classify_number (pfile, token)
   if (float_flag != NOT_FLOAT)
     {
       if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
-       cpp_error (pfile, DL_PEDWARN,
+       cpp_error (pfile, CPP_DL_PEDWARN,
                   "use of C99 hexadecimal floating constant");
 
       if (float_flag == AFTER_EXPON)
@@ -243,7 +236,7 @@ cpp_classify_number (pfile, token)
       result = interpret_float_suffix (str, limit - str);
       if (result == 0)
        {
-         cpp_error (pfile, DL_ERROR,
+         cpp_error (pfile, CPP_DL_ERROR,
                     "invalid suffix \"%.*s\" on floating constant",
                     (int) (limit - str), str);
          return CPP_N_INVALID;
@@ -253,7 +246,7 @@ cpp_classify_number (pfile, token)
       if (limit != str
          && CPP_WTRADITIONAL (pfile)
          && ! cpp_sys_macro_p (pfile))
-       cpp_error (pfile, DL_WARNING,
+       cpp_error (pfile, CPP_DL_WARNING,
                   "traditional C rejects the \"%.*s\" suffix",
                   (int) (limit - str), str);
 
@@ -264,7 +257,7 @@ cpp_classify_number (pfile, token)
       result = interpret_int_suffix (str, limit - str);
       if (result == 0)
        {
-         cpp_error (pfile, DL_ERROR,
+         cpp_error (pfile, CPP_DL_ERROR,
                     "invalid suffix \"%.*s\" on integer constant",
                     (int) (limit - str), str);
          return CPP_N_INVALID;
@@ -278,7 +271,7 @@ cpp_classify_number (pfile, token)
          int large = (result & CPP_N_WIDTH) == CPP_N_LARGE;
 
          if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long)))
-           cpp_error (pfile, DL_WARNING,
+           cpp_error (pfile, CPP_DL_WARNING,
                       "traditional C rejects the \"%.*s\" suffix",
                       (int) (limit - str), str);
        }
@@ -286,13 +279,15 @@ cpp_classify_number (pfile, token)
       if ((result & CPP_N_WIDTH) == CPP_N_LARGE
          && ! CPP_OPTION (pfile, c99)
          && CPP_OPTION (pfile, warn_long_long))
-       cpp_error (pfile, DL_PEDWARN, "use of C99 long long integer constant");
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "use of C99 long long integer constant");
 
       result |= CPP_N_INTEGER;
     }
 
   if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile))
-    cpp_error (pfile, DL_PEDWARN, "imaginary constants are a GCC extension");
+    cpp_error (pfile, CPP_DL_PEDWARN,
+              "imaginary constants are a GCC extension");
 
   if (radix == 10)
     result |= CPP_N_DECIMAL;
@@ -311,13 +306,11 @@ cpp_classify_number (pfile, token)
    of precision options->precision.
 
    We do not provide any interface for decimal->float conversion,
-   because the preprocessor doesn't need it and the floating point
-   handling in GCC proper is too ugly to speak of.  */
+   because the preprocessor doesn't need it and we don't want to
+   drag in GCC's floating point emulator.  */
 cpp_num
-cpp_interpret_integer (pfile, token, type)
-     cpp_reader *pfile;
-     const cpp_token *token;
-     unsigned int type;
+cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token,
+                      unsigned int type)
 {
   const uchar *p, *end;
   cpp_num result;
@@ -379,7 +372,7 @@ cpp_interpret_integer (pfile, token, type)
        }
 
       if (overflow)
-       cpp_error (pfile, DL_PEDWARN,
+       cpp_error (pfile, CPP_DL_PEDWARN,
                   "integer constant is too large for its type");
       /* If too big to be signed, consider it unsigned.  Only warn for
         decimal numbers.  Traditional numbers were always signed (but
@@ -391,7 +384,7 @@ cpp_interpret_integer (pfile, token, type)
               && !num_positive (result, precision))
        {
          if (base == 10)
-           cpp_error (pfile, DL_WARNING,
+           cpp_error (pfile, CPP_DL_WARNING,
                       "integer constant is so large that it is unsigned");
          result.unsignedp = true;
        }
@@ -400,13 +393,9 @@ cpp_interpret_integer (pfile, token, type)
   return result;
 }
 
-/* Append DIGIT to NUM, a number of PRECISION bits being read in base
-   BASE.  */
+/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE.  */
 static cpp_num
-append_digit (num, digit, base, precision)
-     cpp_num num;
-     int digit, base;
-     size_t precision;
+append_digit (cpp_num num, int digit, int base, size_t precision)
 {
   cpp_num result;
   unsigned int shift = 3 + (base == 16);
@@ -455,8 +444,7 @@ append_digit (num, digit, base, precision)
 
 /* Handle meeting "defined" in a preprocessor expression.  */
 static cpp_num
-parse_defined (pfile)
-     cpp_reader *pfile;
+parse_defined (cpp_reader *pfile)
 {
   cpp_num result;
   int paren = 0;
@@ -479,13 +467,13 @@ parse_defined (pfile)
       node = token->val.node;
       if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
        {
-         cpp_error (pfile, DL_ERROR, "missing ')' after \"defined\"");
+         cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\"");
          node = 0;
        }
     }
   else
     {
-      cpp_error (pfile, DL_ERROR,
+      cpp_error (pfile, CPP_DL_ERROR,
                 "operator \"defined\" requires an identifier");
       if (token->flags & NAMED_OP)
        {
@@ -493,7 +481,7 @@ parse_defined (pfile)
 
          op.flags = 0;
          op.type = token->type;
-         cpp_error (pfile, DL_ERROR,
+         cpp_error (pfile, CPP_DL_ERROR,
                     "(\"%s\" is an alternative token for \"%s\" in C++)",
                     cpp_token_as_text (pfile, token),
                     cpp_token_as_text (pfile, &op));
@@ -503,7 +491,7 @@ parse_defined (pfile)
   if (node)
     {
       if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
-       cpp_error (pfile, DL_WARNING,
+       cpp_error (pfile, CPP_DL_WARNING,
                   "this use of \"defined\" may not be portable");
 
       _cpp_mark_macro_used (node);
@@ -526,9 +514,7 @@ parse_defined (pfile)
    number or character constant, or the result of the "defined" or "#"
    operators).  */
 static cpp_num
-eval_token (pfile, token)
-     cpp_reader *pfile;
-     const cpp_token *token;
+eval_token (cpp_reader *pfile, const cpp_token *token)
 {
   cpp_num result;
   unsigned int temp;
@@ -541,13 +527,13 @@ eval_token (pfile, token)
       switch (temp & CPP_N_CATEGORY)
        {
        case CPP_N_FLOATING:
-         cpp_error (pfile, DL_ERROR,
+         cpp_error (pfile, CPP_DL_ERROR,
                     "floating constant in preprocessor expression");
          break;
        case CPP_N_INTEGER:
          if (!(temp & CPP_N_IMAGINARY))
            return cpp_interpret_integer (pfile, token, temp);
-         cpp_error (pfile, DL_ERROR,
+         cpp_error (pfile, CPP_DL_ERROR,
                     "imaginary number in preprocessor expression");
          break;
 
@@ -587,21 +573,13 @@ eval_token (pfile, token)
        {
          result.high = 0;
          result.low = (token->val.node == pfile->spec_nodes.n_true);
-
-         /* Warn about use of true or false in #if when pedantic
-            and stdbool.h has not been included.  */
-         if (CPP_PEDANTIC (pfile)
-             && ! cpp_defined (pfile, DSC("__bool_true_false_are_defined")))
-           cpp_error (pfile, DL_PEDWARN,
-                      "ISO C++ does not permit \"%s\" in #if",
-                      NODE_NAME (token->val.node));
        }
       else
        {
          result.high = 0;
          result.low = 0;
          if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
-           cpp_error (pfile, DL_WARNING, "\"%s\" is not defined",
+           cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined",
                       NODE_NAME (token->val.node));
        }
       break;
@@ -631,7 +609,7 @@ already on the stack.
 The remaining cases are '(' and ')'.  We handle '(' by skipping the
 reduction phase completely.  ')' is given lower priority than
 everything else, including '(', effectively forcing a reduction of the
-parenthesised expression.  If there is a matching '(', the routine
+parenthesized expression.  If there is a matching '(', the routine
 reduce() exits immediately.  If the normal exit route sees a ')', then
 there cannot have been a matching '(' and an error message is output.
 
@@ -700,8 +678,7 @@ static const struct operator
    stored in the 'value' field of the stack element of the operator
    that precedes it.  */
 bool
-_cpp_parse_expr (pfile)
-     cpp_reader *pfile;
+_cpp_parse_expr (cpp_reader *pfile)
 {
   struct op *top = pfile->op_stack;
   unsigned int lex_count;
@@ -751,12 +728,6 @@ _cpp_parse_expr (pfile)
          if (want_value)
            op.op = CPP_UMINUS;
          break;
-       case CPP_OTHER:
-         if (ISGRAPH (op.token->val.c))
-           SYNTAX_ERROR2 ("invalid character '%c' in #if", op.token->val.c);
-         else
-           SYNTAX_ERROR2 ("invalid character '\\%03o' in #if",
-                          op.token->val.c);
 
        default:
          if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
@@ -774,18 +745,22 @@ _cpp_parse_expr (pfile)
        }
       else if (want_value)
        {
-         /* Ordering here is subtle and intended to favor the
-            missing parenthesis diagnostics over alternatives.  */
-         if (op.op == CPP_CLOSE_PAREN)
-           {
-             if (top->op == CPP_OPEN_PAREN)
-               SYNTAX_ERROR ("void expression between '(' and ')'");
-           }
-         else if (top->op == CPP_EOF)
+         /* We want a number (or expression) and haven't got one.
+            Try to emit a specific diagnostic.  */
+         if (op.op == CPP_CLOSE_PAREN && top->op == CPP_OPEN_PAREN)
+           SYNTAX_ERROR ("missing expression between '(' and ')'");
+
+         if (op.op == CPP_EOF && top->op == CPP_EOF)
            SYNTAX_ERROR ("#if with no expression");
+
          if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN)
            SYNTAX_ERROR2 ("operator '%s' has no right operand",
                           cpp_token_as_text (pfile, top->token));
+         else if (op.op == CPP_CLOSE_PAREN || op.op == CPP_EOF)
+           /* Complain about missing paren during reduction.  */;
+         else
+           SYNTAX_ERROR2 ("operator '%s' has no left operand",
+                          cpp_token_as_text (pfile, op.token));
        }
 
       top = reduce (pfile, top, op.op);
@@ -837,7 +812,7 @@ _cpp_parse_expr (pfile)
 
   if (top != pfile->op_stack)
     {
-      cpp_error (pfile, DL_ICE, "unbalanced stack in #if");
+      cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in #if");
     syntax_error:
       return false;  /* Return false on syntax error.  */
     }
@@ -849,17 +824,14 @@ _cpp_parse_expr (pfile)
    pushing operator OP.  Returns NULL on error, otherwise the top of
    the stack.  */
 static struct op *
-reduce (pfile, top, op)
-     cpp_reader *pfile;
-     struct op *top;
-     enum cpp_ttype op;
+reduce (cpp_reader *pfile, struct op *top, enum cpp_ttype op)
 {
   unsigned int prio;
 
   if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2)
     {
     bad_op:
-      cpp_error (pfile, DL_ICE, "impossible operator '%u'", top->op);
+      cpp_error (pfile, CPP_DL_ICE, "impossible operator '%u'", top->op);
       return 0;
     }
 
@@ -951,7 +923,7 @@ reduce (pfile, top, op)
        case CPP_OPEN_PAREN:
          if (op != CPP_CLOSE_PAREN)
            {
-             cpp_error (pfile, DL_ERROR, "missing ')' in expression");
+             cpp_error (pfile, CPP_DL_ERROR, "missing ')' in expression");
              return 0;
            }
          top--;
@@ -972,7 +944,7 @@ reduce (pfile, top, op)
          continue;
 
        case CPP_QUERY:
-         cpp_error (pfile, DL_ERROR, "'?' without following ':'");
+         cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'");
          return 0;
 
        default:
@@ -981,13 +953,13 @@ reduce (pfile, top, op)
 
       top--;
       if (top->value.overflow && !pfile->state.skip_eval)
-       cpp_error (pfile, DL_PEDWARN,
+       cpp_error (pfile, CPP_DL_PEDWARN,
                   "integer overflow in preprocessor expression");
     }
 
   if (op == CPP_CLOSE_PAREN)
     {
-      cpp_error (pfile, DL_ERROR, "missing '(' in expression");
+      cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression");
       return 0;
     }
 
@@ -996,14 +968,12 @@ reduce (pfile, top, op)
 
 /* Returns the position of the old top of stack after expansion.  */
 struct op *
-_cpp_expand_op_stack (pfile)
-     cpp_reader *pfile;
+_cpp_expand_op_stack (cpp_reader *pfile)
 {
   size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack);
   size_t new_size = old_size * 2 + 20;
 
-  pfile->op_stack = (struct op *) xrealloc (pfile->op_stack,
-                                           new_size * sizeof (struct op));
+  pfile->op_stack = xrealloc (pfile->op_stack, new_size * sizeof (struct op));
   pfile->op_limit = pfile->op_stack + new_size;
 
   return pfile->op_stack + old_size;
@@ -1012,9 +982,7 @@ _cpp_expand_op_stack (pfile)
 /* Emits a warning if the effective sign of either operand of OP
    changes because of integer promotions.  */
 static void
-check_promotion (pfile, op)
-     cpp_reader *pfile;
-     const struct op *op;
+check_promotion (cpp_reader *pfile, const struct op *op)
 {
   if (op->value.unsignedp == op[-1].value.unsignedp)
     return;
@@ -1022,21 +990,19 @@ check_promotion (pfile, op)
   if (op->value.unsignedp)
     {
       if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision)))
-       cpp_error (pfile, DL_WARNING,
+       cpp_error (pfile, CPP_DL_WARNING,
                   "the left operand of \"%s\" changes sign when promoted",
                   cpp_token_as_text (pfile, op->token));
     }
   else if (!num_positive (op->value, CPP_OPTION (pfile, precision)))
-    cpp_error (pfile, DL_WARNING,
+    cpp_error (pfile, CPP_DL_WARNING,
               "the right operand of \"%s\" changes sign when promoted",
               cpp_token_as_text (pfile, op->token));
 }
 
 /* Clears the unused high order bits of the number pointed to by PNUM.  */
 static cpp_num
-num_trim (num, precision)
-     cpp_num num;
-     size_t precision;
+num_trim (cpp_num num, size_t precision)
 {
   if (precision > PART_PRECISION)
     {
@@ -1056,9 +1022,7 @@ num_trim (num, precision)
 
 /* True iff A (presumed signed) >= 0.  */
 static bool
-num_positive (num, precision)
-     cpp_num num;
-     size_t precision;
+num_positive (cpp_num num, size_t precision)
 {
   if (precision > PART_PRECISION)
     {
@@ -1072,9 +1036,7 @@ num_positive (num, precision)
 /* Sign extend a number, with PRECISION significant bits and all
    others assumed clear, to fill out a cpp_num structure.  */
 cpp_num
-cpp_num_sign_extend (num, precision)
-     cpp_num num;
-     size_t precision;
+cpp_num_sign_extend (cpp_num num, size_t precision)
 {
   if (!num.unsignedp)
     {
@@ -1098,9 +1060,7 @@ cpp_num_sign_extend (num, precision)
 
 /* Returns the negative of NUM.  */
 static cpp_num
-num_negate (num, precision)
-     cpp_num num;
-     size_t precision;
+num_negate (cpp_num num, size_t precision)
 {
   cpp_num copy;
 
@@ -1117,9 +1077,7 @@ num_negate (num, precision)
 
 /* Returns true if A >= B.  */
 static bool
-num_greater_eq (pa, pb, precision)
-     cpp_num pa, pb;
-     size_t precision;
+num_greater_eq (cpp_num pa, cpp_num pb, size_t precision)
 {
   bool unsignedp;
 
@@ -1142,10 +1100,8 @@ num_greater_eq (pa, pb, precision)
 
 /* Returns LHS OP RHS, where OP is a bit-wise operation.  */
 static cpp_num
-num_bitwise_op (pfile, lhs, rhs, op)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     cpp_num lhs, rhs;
-     enum cpp_ttype op;
+num_bitwise_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
+               cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
 {
   lhs.overflow = false;
   lhs.unsignedp = lhs.unsignedp || rhs.unsignedp;
@@ -1173,10 +1129,8 @@ num_bitwise_op (pfile, lhs, rhs, op)
 
 /* Returns LHS OP RHS, where OP is an inequality.  */
 static cpp_num
-num_inequality_op (pfile, lhs, rhs, op)
-     cpp_reader *pfile;
-     cpp_num lhs, rhs;
-     enum cpp_ttype op;
+num_inequality_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs,
+                  enum cpp_ttype op)
 {
   bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision));
 
@@ -1197,10 +1151,8 @@ num_inequality_op (pfile, lhs, rhs, op)
 
 /* Returns LHS OP RHS, where OP is == or !=.  */
 static cpp_num
-num_equality_op (pfile, lhs, rhs, op)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
-     cpp_num lhs, rhs;
-     enum cpp_ttype op;
+num_equality_op (cpp_reader *pfile ATTRIBUTE_UNUSED,
+                cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
 {
   /* Work around a 3.0.4 bug; see PR 6950.  */
   bool eq = num_eq (lhs, rhs);
@@ -1215,9 +1167,7 @@ num_equality_op (pfile, lhs, rhs, op)
 
 /* Shift NUM, of width PRECISION, right by N bits.  */
 static cpp_num
-num_rshift (num, precision, n)
-     cpp_num num;
-     size_t precision, n;
+num_rshift (cpp_num num, size_t precision, size_t n)
 {
   cpp_num_part sign_mask;
 
@@ -1257,9 +1207,7 @@ num_rshift (num, precision, n)
 
 /* Shift NUM, of width PRECISION, left by N bits.  */
 static cpp_num
-num_lshift (num, precision, n)
-     cpp_num num;
-     size_t precision, n;
+num_lshift (cpp_num num, size_t precision, size_t n)
 {
   if (n >= precision)
     {
@@ -1299,16 +1247,13 @@ num_lshift (num, precision, n)
 
 /* The four unary operators: +, -, ! and ~.  */
 static cpp_num
-num_unary_op (pfile, num, op)
-     cpp_reader *pfile;
-     cpp_num num;
-     enum cpp_ttype op;
+num_unary_op (cpp_reader *pfile, cpp_num num, enum cpp_ttype op)
 {
   switch (op)
     {
     case CPP_UPLUS:
       if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval)
-       cpp_error (pfile, DL_WARNING,
+       cpp_error (pfile, CPP_DL_WARNING,
                   "traditional C rejects the unary plus operator");
       num.overflow = false;
       break;
@@ -1337,10 +1282,7 @@ num_unary_op (pfile, num, op)
 
 /* The various binary operators.  */
 static cpp_num
-num_binary_op (pfile, lhs, rhs, op)
-     cpp_reader *pfile;
-     cpp_num lhs, rhs;
-     enum cpp_ttype op;
+num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
 {
   cpp_num result;
   size_t precision = CPP_OPTION (pfile, precision);
@@ -1409,8 +1351,9 @@ num_binary_op (pfile, lhs, rhs, op)
 
       /* Comma.  */
     default: /* case CPP_COMMA: */
-      if (CPP_PEDANTIC (pfile) && !pfile->state.skip_eval)
-       cpp_error (pfile, DL_PEDWARN,
+      if (CPP_PEDANTIC (pfile) && (!CPP_OPTION (pfile, c99)
+                                  || !pfile->state.skip_eval))
+       cpp_error (pfile, CPP_DL_PEDWARN,
                   "comma operator in operand of #if");
       lhs = rhs;
       break;
@@ -1422,8 +1365,7 @@ num_binary_op (pfile, lhs, rhs, op)
 /* Multiplies two unsigned cpp_num_parts to give a cpp_num.  This
    cannot overflow.  */
 static cpp_num
-num_part_mul (lhs, rhs)
-     cpp_num_part lhs, rhs;
+num_part_mul (cpp_num_part lhs, cpp_num_part rhs)
 {
   cpp_num result;
   cpp_num_part middle[2], temp;
@@ -1453,9 +1395,7 @@ num_part_mul (lhs, rhs)
 
 /* Multiply two preprocessing numbers.  */
 static cpp_num
-num_mul (pfile, lhs, rhs)
-     cpp_reader *pfile;
-     cpp_num lhs, rhs;
+num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs)
 {
   cpp_num result, temp;
   bool unsignedp = lhs.unsignedp || rhs.unsignedp;
@@ -1505,10 +1445,7 @@ num_mul (pfile, lhs, rhs)
 /* Divide two preprocessing numbers, returning the answer or the
    remainder depending upon OP.  */
 static cpp_num
-num_div_op (pfile, lhs, rhs, op)
-     cpp_reader *pfile;
-     cpp_num lhs, rhs;
-     enum cpp_ttype op;
+num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
 {
   cpp_num result, sub;
   cpp_num_part mask;
@@ -1548,7 +1485,7 @@ num_div_op (pfile, lhs, rhs, op)
   else
     {
       if (!pfile->state.skip_eval)
-       cpp_error (pfile, DL_ERROR, "division by zero in #if");
+       cpp_error (pfile, CPP_DL_ERROR, "division by zero in #if");
       return lhs;
     }
 
index 29365a035377deced40cbcd43a68ee10753ac439..e757a40d2f9373023a7f141d0d9a4ef3f773c446 100644 (file)
@@ -1,10 +1,11 @@
-/* Part of CPP library.  (include file handling)
+/* Part of CPP library.  File handling.
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Written by Per Bothner, 1994.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
    Split out of cpplib.c, Zack Weinberg, Oct 1998
+   Reimplemented, Neil Booth, Jul 2003
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -26,377 +27,441 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "cpphash.h"
 #include "intl.h"
 #include "mkdeps.h"
-#include "splay-tree.h"
-#ifdef ENABLE_VALGRIND_CHECKING
-#include <valgrind.h>
+#include "hashtab.h"
+#include <dirent.h>
+
+/* Variable length record files on VMS will have a stat size that includes
+   record control characters that won't be included in the read size.  */
+#ifdef VMS
+# define FAB_C_VAR 2 /* variable length records (see Starlet fabdef.h) */
+# define STAT_SIZE_RELIABLE(ST) ((ST).st_fab_rfm != FAB_C_VAR)
 #else
-/* Avoid #ifdef:s when we can help it.  */
-#define VALGRIND_DISCARD(x)
+# define STAT_SIZE_RELIABLE(ST) true
 #endif
 
-#ifdef HAVE_MMAP_FILE
-# include <sys/mman.h>
-# ifndef MMAP_THRESHOLD
-#  define MMAP_THRESHOLD 3 /* Minimum page count to mmap the file.  */
-# endif
-# if MMAP_THRESHOLD
-#  define TEST_THRESHOLD(size, pagesize) \
-     (size / pagesize >= MMAP_THRESHOLD && (size % pagesize) != 0)
-   /* Use mmap if the file is big enough to be worth it (controlled
-      by MMAP_THRESHOLD) and if we can safely count on there being
-      at least one readable NUL byte after the end of the file's
-      contents.  This is true for all tested operating systems when
-      the file size is not an exact multiple of the page size.  */
-#  ifndef __CYGWIN__
-#   define SHOULD_MMAP(size, pagesize) TEST_THRESHOLD (size, pagesize)
-#  else
-#   define WIN32_LEAN_AND_MEAN
-#   include <windows.h>
-    /* Cygwin can't correctly emulate mmap under Windows 9x style systems so
-       disallow use of mmap on those systems.  Windows 9x does not zero fill
-       memory at EOF and beyond, as required.  */
-#   define SHOULD_MMAP(size, pagesize) ((GetVersion() & 0x80000000) \
-                                       ? 0 : TEST_THRESHOLD (size, pagesize))
-#  endif
-# endif
-
-#else  /* No MMAP_FILE */
-#  undef MMAP_THRESHOLD
-#  define MMAP_THRESHOLD 0
+#ifdef __DJGPP__
+  /* For DJGPP redirected input is opened in text mode.  */
+#  define set_stdin_to_binary_mode() \
+     if (! isatty (0)) setmode (0, O_BINARY)
+#else
+#  define set_stdin_to_binary_mode() /* Nothing */
 #endif
 
 #ifndef O_BINARY
 # define O_BINARY 0
 #endif
 
-/* If errno is inspected immediately after a system call fails, it will be
-   nonzero, and no error number will ever be zero.  */
-#ifndef ENOENT
-# define ENOENT 0
-#endif
-#ifndef ENOTDIR
-# define ENOTDIR 0
-#endif
+/* This structure represents a file searched for by CPP, whether it
+   exists or not.  An instance may be pointed to by more than one
+   file_hash_entry; at present no reference count is kept.  */
+struct _cpp_file
+{
+  /* Filename as given to #include or command line switch.  */
+  const char *name;
 
-/* Suppress warning about function macros used w/o arguments in traditional
-   C.  It is unlikely that glibc's strcmp macro helps this file at all.  */
-#undef strcmp
-
-/* This structure is used for the table of all includes.  */
-struct include_file {
-  const char *name;            /* actual path name of file */
-  const cpp_hashnode *cmacro;  /* macro, if any, preventing reinclusion.  */
-  const struct search_path *foundhere;
-                               /* location in search path where file was
-                                  found, for #include_next and sysp.  */
-  const unsigned char *buffer; /* pointer to cached file contents */
-  struct stat st;              /* copy of stat(2) data for file */
-  int fd;                      /* fd open on file (short term storage only) */
-  int err_no;                  /* errno obtained if opening a file failed */
-  unsigned short include_count;        /* number of times file has been read */
-  unsigned short refcnt;       /* number of stacked buffers using this file */
-  unsigned char mapped;                /* file buffer is mmapped */
-};
+  /* The full path used to find the file.  */
+  const char *path;
 
-/* Variable length record files on VMS will have a stat size that includes
-   record control characters that won't be included in the read size.  */
-#ifdef VMS
-# define FAB_C_VAR 2 /* variable length records (see Starlet fabdef.h) */
-# define STAT_SIZE_TOO_BIG(ST) ((ST).st_fab_rfm == FAB_C_VAR)
-#else
-# define STAT_SIZE_TOO_BIG(ST) 0
-#endif
+  /* The full path of the pch file.  */
+  const char *pchname;
 
-/* The cmacro works like this: If it's NULL, the file is to be
-   included again.  If it's NEVER_REREAD, the file is never to be
-   included again.  Otherwise it is a macro hashnode, and the file is
-   to be included again if the macro is defined.  */
-#define NEVER_REREAD ((const cpp_hashnode *) -1)
-#define DO_NOT_REREAD(inc) \
-((inc)->cmacro && ((inc)->cmacro == NEVER_REREAD \
-                  || (inc)->cmacro->type == NT_MACRO))
-#define NO_INCLUDE_PATH ((struct include_file *) -1)
-
-static struct file_name_map *read_name_map
-                               PARAMS ((cpp_reader *, const char *));
-static char *read_filename_string PARAMS ((int, FILE *));
-static char *remap_filename    PARAMS ((cpp_reader *, char *,
-                                        struct search_path *));
-static struct search_path *search_from PARAMS ((cpp_reader *,
-                                               enum include_type));
-static struct include_file *
-       find_include_file PARAMS ((cpp_reader *, const cpp_token *,
-                                  enum include_type));
-static struct include_file *open_file PARAMS ((cpp_reader *, const char *));
-static int read_include_file   PARAMS ((cpp_reader *, struct include_file *));
-static bool stack_include_file PARAMS ((cpp_reader *, struct include_file *));
-static void purge_cache        PARAMS ((struct include_file *));
-static void destroy_node       PARAMS ((splay_tree_value));
-static int report_missing_guard                PARAMS ((splay_tree_node, void *));
-static splay_tree_node find_or_create_entry PARAMS ((cpp_reader *,
-                                                    const char *));
-static void handle_missing_header PARAMS ((cpp_reader *, const char *, int));
-static int remove_component_p  PARAMS ((const char *));
-
-/* Set up the splay tree we use to store information about all the
-   file names seen in this compilation.  We also have entries for each
-   file we tried to open but failed; this saves system calls since we
-   don't try to open it again in future.
-
-   The key of each node is the file name, after processing by
-   _cpp_simplify_pathname.  The path name may or may not be absolute.
-   The path string has been malloced, as is automatically freed by
-   registering free () as the splay tree key deletion function.
-
-   A node's value is a pointer to a struct include_file, and is never
-   NULL.  */
-void
-_cpp_init_includes (pfile)
-     cpp_reader *pfile;
-{
-  pfile->all_include_files
-    = splay_tree_new ((splay_tree_compare_fn) strcmp,
-                     (splay_tree_delete_key_fn) free,
-                     destroy_node);
-}
+  /* The file's path with the basename stripped.  NULL if it hasn't
+     been calculated yet.  */
+  const char *dir_name;
 
-/* Tear down the splay tree.  */
-void
-_cpp_cleanup_includes (pfile)
-     cpp_reader *pfile;
-{
-  splay_tree_delete (pfile->all_include_files);
-}
+  /* Chain through all files.  */
+  struct _cpp_file *next_file;
 
-/* Free a node.  The path string is automatically freed.  */
-static void
-destroy_node (v)
-     splay_tree_value v;
-{
-  struct include_file *f = (struct include_file *) v;
+  /* The contents of NAME after calling read_file().  */
+  const uchar *buffer;
 
-  if (f)
-    {
-      purge_cache (f);
-      free (f);
-    }
-}
+  /* The macro, if any, preventing re-inclusion.  */
+  const cpp_hashnode *cmacro;
 
-/* Mark a file to not be reread (e.g. #import, read failure).  */
-void
-_cpp_never_reread (file)
-     struct include_file *file;
-{
-  file->cmacro = NEVER_REREAD;
-}
+  /* The directory in the search path where FILE was found.  Used for
+     #include_next and determining whether a header is a system
+     header.  */
+  cpp_dir *dir;
 
-/* Lookup a filename, which is simplified after making a copy, and
-   create an entry if none exists.  errno is nonzero iff a (reported)
-   stat() error occurred during simplification.  */
-static splay_tree_node
-find_or_create_entry (pfile, fname)
-     cpp_reader *pfile;
-     const char *fname;
-{
-  splay_tree_node node;
-  struct include_file *file;
-  char *name = xstrdup (fname);
-
-  _cpp_simplify_pathname (name);
-  node = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name);
-  if (node)
-    free (name);
-  else
-    {
-      file = xcnew (struct include_file);
-      file->name = name;
-      file->err_no = errno;
-      node = splay_tree_insert (pfile->all_include_files,
-                               (splay_tree_key) file->name,
-                               (splay_tree_value) file);
-    }
-
-  return node;
-}
+  /* As filled in by stat(2) for the file.  */
+  struct stat st;
 
-/* Enter a file name in the splay tree, for the sake of cpp_included.  */
-void
-_cpp_fake_include (pfile, fname)
-     cpp_reader *pfile;
-     const char *fname;
-{
-  find_or_create_entry (pfile, fname);
-}
+  /* File descriptor.  Invalid if -1, otherwise open.  */
+  int fd;
 
-/* Given a file name, look it up in the cache; if there is no entry,
-   create one with a non-NULL value (regardless of success in opening
-   the file).  If the file doesn't exist or is inaccessible, this
-   entry is flagged so we don't attempt to open it again in the
-   future.  If the file isn't open, open it.  The empty string is
-   interpreted as stdin.
-
-   Returns an include_file structure with an open file descriptor on
-   success, or NULL on failure.  */
-static struct include_file *
-open_file (pfile, filename)
-     cpp_reader *pfile;
-     const char *filename;
-{
-  splay_tree_node nd = find_or_create_entry (pfile, filename);
-  struct include_file *file = (struct include_file *) nd->value;
+  /* Zero if this file was successfully opened and stat()-ed,
+     otherwise errno obtained from failure.  */
+  int err_no;
 
-  if (file->err_no)
-    {
-      /* Ugh.  handle_missing_header () needs errno to be set.  */
-      errno = file->err_no;
-      return 0;
-    }
+  /* Number of times the file has been stacked for preprocessing.  */
+  unsigned short stack_count;
 
-  /* Don't reopen an idempotent file.  */
-  if (DO_NOT_REREAD (file))
-    return file;
+  /* If opened with #import or contains #pragma once.  */
+  bool once_only;
 
-  /* Don't reopen one which is already loaded.  */
-  if (file->buffer != NULL)
-    return file;
+  /* If read() failed before.  */
+  bool dont_read;
 
-  /* We used to open files in nonblocking mode, but that caused more
-     problems than it solved.  Do take care not to acquire a
-     controlling terminal by mistake (this can't happen on sane
-     systems, but paranoia is a virtue).
+  /* If this file is the main file.  */
+  bool main_file;
 
-     Use the three-argument form of open even though we aren't
-     specifying O_CREAT, to defend against broken system headers.
+  /* If BUFFER above contains the true contents of the file.  */
+  bool buffer_valid;
 
-     O_BINARY tells some runtime libraries (notably DJGPP) not to do
-     newline translation; we can handle DOS line breaks just fine
-     ourselves.
+  /* 0: file not known to be a PCH.
+     1: file is a PCH (on return from find_include_file).
+     2: file is not and never will be a valid precompiled header.
+     3: file is always a valid precompiled header.  */
+  uchar pch;
+};
 
-     Special case: the empty string is translated to stdin.  */
+/* A singly-linked list for all searches for a given file name, with
+   its head pointed to by a slot in FILE_HASH.  The file name is what
+   appeared between the quotes in a #include directive; it can be
+   determined implicitly from the hash table location or explicitly
+   from FILE->name.
+
+   FILE is a structure containing details about the file that was
+   found with that search, or details of how the search failed.
+
+   START_DIR is the starting location of the search in the include
+   chain.  The current directories for "" includes are also hashed in
+   the hash table and therefore unique.  Files that are looked up
+   without using a search path, such as absolute filenames and file
+   names from the command line share a special starting directory so
+   they don't cause cache hits with normal include-chain lookups.
+
+   If START_DIR is NULL then the entry is for a directory, not a file,
+   and the directory is in DIR.  Since the starting point in a file
+   lookup chain is never NULL, this means that simple pointer
+   comparisons against START_DIR can be made to determine cache hits
+   in file lookups.
+
+   If a cache lookup fails because of e.g. an extra "./" in the path,
+   then nothing will break.  It is just less efficient as CPP will
+   have to do more work re-preprocessing the file, and/or comparing
+   its contents against earlier once-only files.
+*/
+struct file_hash_entry
+{
+  struct file_hash_entry *next;
+  cpp_dir *start_dir;
+  union
+  {
+    _cpp_file *file;
+    cpp_dir *dir;
+  } u;
+};
 
-  if (filename[0] == '\0')
+static bool open_file (_cpp_file *file);
+static bool pch_open_file (cpp_reader *pfile, _cpp_file *file,
+                          bool *invalid_pch);
+static bool find_file_in_dir (cpp_reader *pfile, _cpp_file *file,
+                             bool *invalid_pch);
+static bool read_file_guts (cpp_reader *pfile, _cpp_file *file);
+static bool read_file (cpp_reader *pfile, _cpp_file *file);
+static bool should_stack_file (cpp_reader *, _cpp_file *file, bool import);
+static struct cpp_dir *search_path_head (cpp_reader *, const char *fname,
+                                int angle_brackets, enum include_type);
+static const char *dir_name_of_file (_cpp_file *file);
+static void open_file_failed (cpp_reader *pfile, _cpp_file *file, int);
+static struct file_hash_entry *search_cache (struct file_hash_entry *head,
+                                            const cpp_dir *start_dir);
+static _cpp_file *make_cpp_file (cpp_reader *, cpp_dir *, const char *fname);
+static void destroy_cpp_file (_cpp_file *);
+static cpp_dir *make_cpp_dir (cpp_reader *, const char *dir_name, int sysp);
+static void allocate_file_hash_entries (cpp_reader *pfile);
+static struct file_hash_entry *new_file_hash_entry (cpp_reader *pfile);
+static int report_missing_guard (void **slot, void *b);
+static hashval_t file_hash_hash (const void *p);
+static int file_hash_eq (const void *p, const void *q);
+static char *read_filename_string (int ch, FILE *f);
+static void read_name_map (cpp_dir *dir);
+static char *remap_filename (cpp_reader *pfile, _cpp_file *file);
+static char *append_file_to_dir (const char *fname, cpp_dir *dir);
+static bool validate_pch (cpp_reader *, _cpp_file *file, const char *pchname);
+static bool include_pch_p (_cpp_file *file);
+
+/* Given a filename in FILE->PATH, with the empty string interpreted
+   as <stdin>, open it.
+
+   On success FILE contains an open file descriptor and stat
+   information for the file.  On failure the file descriptor is -1 and
+   the appropriate errno is also stored in FILE.  Returns TRUE iff
+   successful.
+
+   We used to open files in nonblocking mode, but that caused more
+   problems than it solved.  Do take care not to acquire a controlling
+   terminal by mistake (this can't happen on sane systems, but
+   paranoia is a virtue).
+
+   Use the three-argument form of open even though we aren't
+   specifying O_CREAT, to defend against broken system headers.
+
+   O_BINARY tells some runtime libraries (notably DJGPP) not to do
+   newline translation; we can handle DOS line breaks just fine
+   ourselves.  */
+static bool
+open_file (_cpp_file *file)
+{
+  if (file->path[0] == '\0')
     {
       file->fd = 0;
-#ifdef __DJGPP__
-      /* For DJGPP redirected input is opened in text mode. Change it
-         to binary mode.  */
-      if (! isatty (file->fd))
-       setmode (file->fd, O_BINARY);
-#endif
+      set_stdin_to_binary_mode ();
     }
   else
-    file->fd = open (file->name, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
+    file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
 
-  if (file->fd != -1 && fstat (file->fd, &file->st) == 0)
+  if (file->fd != -1)
     {
-      if (!S_ISDIR (file->st.st_mode))
-       return file;
+      if (fstat (file->fd, &file->st) == 0)
+       {
+         if (!S_ISDIR (file->st.st_mode))
+           {
+             file->err_no = 0;
+             return true;
+           }
+
+         /* Ignore a directory and continue the search.  The file we're
+            looking for may be elsewhere in the search path.  */
+         errno = ENOENT;
+       }
 
-      /* If it's a directory, we return null and continue the search
-        as the file we're looking for may appear elsewhere in the
-        search path.  */
-      errno = ENOENT;
       close (file->fd);
       file->fd = -1;
     }
+  else if (errno == ENOTDIR)
+    errno = ENOENT;
 
   file->err_no = errno;
-  return 0;
+
+  return false;
 }
 
-/* Place the file referenced by INC into a new buffer on the buffer
-   stack, unless there are errors, or the file is not re-included
-   because of e.g. multiple-include guards.  Returns true if a buffer
-   is stacked.  */
+/* Temporary PCH intercept of opening a file.  Try to find a PCH file
+   based on FILE->name and FILE->dir, and test those found for
+   validity using PFILE->cb.valid_pch.  Return true iff a valid file is
+   found.  Set *INVALID_PCH if a PCH file is found but wasn't valid.  */
+
 static bool
-stack_include_file (pfile, inc)
-     cpp_reader *pfile;
-     struct include_file *inc;
+pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
 {
-  cpp_buffer *fp;
-  int sysp;
-  const char *filename;
-
-  if (DO_NOT_REREAD (inc))
+  static const char extension[] = ".gch";
+  const char *path = file->path;
+  size_t len, flen;
+  char *pchname;
+  struct stat st;
+  bool valid = false;
+
+  /* No PCH on <stdin> or if not requested.  */
+  if (file->name[0] == '\0' || !pfile->cb.valid_pch)
     return false;
 
-  sysp = MAX ((pfile->map ? pfile->map->sysp : 0),
-             (inc->foundhere ? inc->foundhere->sysp : 0));
+  flen = strlen (path);
+  len = flen + sizeof (extension);
+  pchname = xmalloc (len);
+  memcpy (pchname, path, flen);
+  memcpy (pchname + flen, extension, sizeof (extension));
 
-  /* Add the file to the dependencies on its first inclusion.  */
-  if (CPP_OPTION (pfile, deps.style) > !!sysp && !inc->include_count)
+  if (stat (pchname, &st) == 0)
     {
-      if (pfile->buffer || CPP_OPTION (pfile, deps.ignore_main_file) == 0)
-       deps_add_dep (pfile->deps, inc->name);
-    }
+      DIR *pchdir;
+      struct dirent *d;
+      size_t dlen, plen = len;
 
-  /* Not in cache?  */
-  if (! inc->buffer)
-    {
-      if (read_include_file (pfile, inc))
+      if (!S_ISDIR (st.st_mode))
+       valid = validate_pch (pfile, file, pchname);
+      else if ((pchdir = opendir (pchname)) != NULL)
        {
-         /* If an error occurs, do not try to read this file again.  */
-         _cpp_never_reread (inc);
-         return false;
+         pchname[plen - 1] = '/';
+         while ((d = readdir (pchdir)) != NULL)
+           {
+             dlen = strlen (d->d_name) + 1;
+             if ((strcmp (d->d_name, ".") == 0)
+                 || (strcmp (d->d_name, "..") == 0))
+               continue;
+             if (dlen + plen > len)
+               {
+                 len += dlen + 64;
+                 pchname = xrealloc (pchname, len);
+               }
+             memcpy (pchname + plen, d->d_name, dlen);
+             valid = validate_pch (pfile, file, pchname);
+             if (valid)
+               break;
+           }
+         closedir (pchdir);
        }
-      /* Mark a regular, zero-length file never-reread.  We read it,
-        NUL-terminate it, and stack it once, so preprocessing a main
-        file of zero length does not raise an error.  */
-      if (S_ISREG (inc->st.st_mode) && inc->st.st_size == 0)
-       _cpp_never_reread (inc);
-      close (inc->fd);
-      inc->fd = -1;
+      if (valid)
+       file->pch = true;
+      else
+       *invalid_pch = true;
     }
 
-  if (pfile->buffer)
-    /* We don't want MI guard advice for the main file.  */
-    inc->include_count++;
+  if (valid)
+    file->pchname = pchname;
+  else
+    free (pchname);
 
-  /* Push a buffer.  */
-  fp = cpp_push_buffer (pfile, inc->buffer, inc->st.st_size,
-                       /* from_stage3 */ CPP_OPTION (pfile, preprocessed), 0);
-  fp->inc = inc;
-  fp->inc->refcnt++;
+  return valid;
+}
 
-  /* Initialize controlling macro state.  */
-  pfile->mi_valid = true;
-  pfile->mi_cmacro = 0;
+/* Try to open the path FILE->name appended to FILE->dir.  This is
+   where remap and PCH intercept the file lookup process.  Return true
+   if the file was found, whether or not the open was successful.
+   Set *INVALID_PCH to true if a PCH file is found but wasn't valid.  */
 
-  /* Generate the call back.  */
-  filename = inc->name;
-  if (*filename == '\0')
-    filename = "<stdin>";
-  _cpp_do_file_change (pfile, LC_ENTER, filename, 1, sysp);
+static bool
+find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
+{
+  char *path;
 
-  return true;
+  if (CPP_OPTION (pfile, remap) && (path = remap_filename (pfile, file)))
+    ;
+  else
+    path = append_file_to_dir (file->name, file->dir);
+
+  file->path = path;
+  if (pch_open_file (pfile, file, invalid_pch))
+    return true;
+
+  if (open_file (file))
+    return true;
+
+  if (file->err_no != ENOENT)
+    {
+      open_file_failed (pfile, file, 0);
+      return true;
+    }
+
+  free (path);
+  file->path = file->name;
+  return false;
+}
+
+bool
+_cpp_find_failed (_cpp_file *file)
+{
+  return file->err_no != 0;
 }
 
-/* Read the file referenced by INC into the file cache.
+/* Given a filename FNAME search for such a file in the include path
+   starting from START_DIR.  If FNAME is the empty string it is
+   interpreted as STDIN if START_DIR is PFILE->no_seach_path.
+
+   If the file is not found in the file cache fall back to the O/S and
+   add the result to our cache.
+
+   If the file was not found in the filesystem, or there was an error
+   opening it, then ERR_NO is nonzero and FD is -1.  If the file was
+   found, then ERR_NO is zero and FD could be -1 or an open file
+   descriptor.  FD can be -1 if the file was found in the cache and
+   had previously been closed.  To open it again pass the return value
+   to open_file().
+*/
+_cpp_file *
+_cpp_find_file (cpp_reader *pfile, const char *fname, cpp_dir *start_dir, bool fake, int angle_brackets)
+{
+  struct file_hash_entry *entry, **hash_slot;
+  _cpp_file *file;
+  bool invalid_pch = false;
+
+  /* Ensure we get no confusion between cached files and directories.  */
+  if (start_dir == NULL)
+    cpp_error (pfile, CPP_DL_ICE, "NULL directory in find_file");
+
+  hash_slot = (struct file_hash_entry **)
+    htab_find_slot_with_hash (pfile->file_hash, fname,
+                             htab_hash_string (fname),
+                             INSERT);
 
-   If fd points to a plain file, we might be able to mmap it; we can
-   definitely allocate the buffer all at once.  If fd is a pipe or
-   terminal, we can't do either.  If fd is something weird, like a
-   block device, we don't want to read it at all.
+  /* First check the cache before we resort to memory allocation.  */
+  entry = search_cache (*hash_slot, start_dir);
+  if (entry)
+    return entry->u.file;
 
-   Unfortunately, different systems use different st.st_mode values
-   for pipes: some have S_ISFIFO, some S_ISSOCK, some are buggy and
-   zero the entire struct stat except a couple fields.  Hence we don't
-   even try to figure out what something is, except for plain files
-   and block devices.
+  file = make_cpp_file (pfile, start_dir, fname);
+
+  /* Try each path in the include chain.  */
+  for (; !fake ;)
+    {
+      if (find_file_in_dir (pfile, file, &invalid_pch))
+       break;
+
+      file->dir = file->dir->next;
+      if (file->dir == NULL)
+       {
+         open_file_failed (pfile, file, angle_brackets);
+         if (invalid_pch)
+           {
+             cpp_error (pfile, CPP_DL_ERROR,
+              "one or more PCH files were found, but they were invalid");
+             if (!cpp_get_options (pfile)->warn_invalid_pch)
+               cpp_error (pfile, CPP_DL_ERROR,
+                          "use -Winvalid-pch for more information");
+           }
+         break;
+       }
+
+      /* Only check the cache for the starting location (done above)
+        and the quote and bracket chain heads because there are no
+        other possible starting points for searches.  */
+      if (file->dir != pfile->bracket_include
+         && file->dir != pfile->quote_include)
+       continue;
+
+      entry = search_cache (*hash_slot, file->dir);
+      if (entry)
+       break;
+    }
+
+  if (entry)
+    {
+      /* Cache for START_DIR too, sharing the _cpp_file structure.  */
+      free ((char *) file->name);
+      free (file);
+      file = entry->u.file;
+    }
+  else
+    {
+      /* This is a new file; put it in the list.  */
+      file->next_file = pfile->all_files;
+      pfile->all_files = file;
+    }
+
+  /* Store this new result in the hash table.  */
+  entry = new_file_hash_entry (pfile);
+  entry->next = *hash_slot;
+  entry->start_dir = start_dir;
+  entry->u.file = file;
+  *hash_slot = entry;
+
+  return file;
+}
+
+/* Read a file into FILE->buffer, returning true on success.
+
+   If FILE->fd is something weird, like a block device, we don't want
+   to read it at all.  Don't even try to figure out what something is,
+   except for plain files and block devices, since there is no
+   reliable portable way of doing this.
 
    FIXME: Flush file cache and try again if we run out of memory.  */
-static int
-read_include_file (pfile, inc)
-     cpp_reader *pfile;
-     struct include_file *inc;
+static bool
+read_file_guts (cpp_reader *pfile, _cpp_file *file)
 {
-  ssize_t size, offset, count;
+  ssize_t size, total, count;
   uchar *buf;
-#if MMAP_THRESHOLD
-  static int pagesize = -1;
-#endif
+  bool regular;
 
-  if (S_ISREG (inc->st.st_mode))
+  if (S_ISBLK (file->st.st_mode))
+    {
+      cpp_error (pfile, CPP_DL_ERROR, "%s is a block device", file->path);
+      return false;
+    }
+
+  regular = S_ISREG (file->st.st_mode);
+  if (regular)
     {
       /* off_t might have a wider range than ssize_t - in other words,
         the max size of a file might be bigger than the address
@@ -407,243 +472,502 @@ read_include_file (pfile, inc)
         type.  Use INTTYPE_MAXIMUM unconditionally to ensure this
         does not bite us.  */
 #ifndef __BORLANDC__
-      if (inc->st.st_size > INTTYPE_MAXIMUM (ssize_t))
+      if (file->st.st_size > INTTYPE_MAXIMUM (ssize_t))
        {
-         cpp_error (pfile, DL_ERROR, "%s is too large", inc->name);
-         goto fail;
+         cpp_error (pfile, CPP_DL_ERROR, "%s is too large", file->path);
+         return false;
        }
 #endif
-      size = inc->st.st_size;
 
-      inc->mapped = 0;
-#if MMAP_THRESHOLD
-      if (pagesize == -1)
-       pagesize = getpagesize ();
+      size = file->st.st_size;
+    }
+  else
+    /* 8 kilobytes is a sensible starting size.  It ought to be bigger
+       than the kernel pipe buffer, and it's definitely bigger than
+       the majority of C source files.  */
+    size = 8 * 1024;
+
+  buf = xmalloc (size + 1);
+  total = 0;
+  while ((count = read (file->fd, buf + total, size - total)) > 0)
+    {
+      total += count;
 
-      if (SHOULD_MMAP (size, pagesize))
+      if (total == size)
        {
-         buf = (uchar *) mmap (0, size, PROT_READ, MAP_PRIVATE, inc->fd, 0);
-         if (buf == (uchar *) -1)
-           goto perror_fail;
+         if (regular)
+           break;
+         size *= 2;
+         buf = xrealloc (buf, size + 1);
+       }
+    }
 
-         /* We must tell Valgrind that the byte at buf[size] is actually
-            readable.  Discard the handle to avoid handle leak.  */
-         VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (buf + size, 1));
+  if (count < 0)
+    {
+      cpp_errno (pfile, CPP_DL_ERROR, file->path);
+      return false;
+    }
 
-         inc->mapped = 1;
-       }
-      else
-#endif
-       {
-         buf = (uchar *) xmalloc (size + 1);
-         offset = 0;
-         while (offset < size)
-           {
-             count = read (inc->fd, buf + offset, size - offset);
-             if (count < 0)
-               goto perror_fail;
-             if (count == 0)
-               {
 #ifndef __BORLANDC__
-                 if (!STAT_SIZE_TOO_BIG (inc->st))
-                   {
-                     /* For some reason, even though we opened with O_BINARY,
-                      * Borland C++ seems to insist on doing CR/LF -> LF
-                      * translations for us, which results in the file appearing
-                      * shorter than stat told us it should be.
-                      *
-                      * This sucks, but don't bother throwing a warning.
-                      */
-                     cpp_error (pfile, DL_WARNING,
-                                "%s is shorter than expected", inc->name);
-                   }
+  /* For some reason, even though we opened with O_BINARY,
+   * Borland C++ seems to insist on doing CR/LF -> LF
+   * translations for us, which results in the file appearing
+   * shorter than stat told us it should be.
+   *
+   * This sucks, but don't bother throwing a warning.
+   */
+  if (regular && total != size && STAT_SIZE_RELIABLE (file->st))
+    cpp_error (pfile, CPP_DL_WARNING,
+              "%s is shorter than expected", file->path);
 #endif
-                 size = offset;
-                 buf = xrealloc (buf, size + 1);
-                 inc->st.st_size = size;
-                 break;
-               }
-             offset += count;
-           }
-         /* The lexer requires that the buffer be NUL-terminated.  */
-         buf[size] = '\0';
-       }
-    }
-  else if (S_ISBLK (inc->st.st_mode))
+
+  file->buffer = _cpp_convert_input (pfile, CPP_OPTION (pfile, input_charset),
+                                    buf, size, total, &file->st.st_size);
+  file->buffer_valid = true;
+
+  return true;
+}
+
+/* Convenience wrapper around read_file_guts that opens the file if
+   necessary and closes the file descriptor after reading.  FILE must
+   have been passed through find_file() at some stage.  */
+static bool
+read_file (cpp_reader *pfile, _cpp_file *file)
+{
+  /* If we already have its contents in memory, succeed immediately.  */
+  if (file->buffer_valid)
+    return true;
+
+  /* If an earlier read failed for some reason don't try again.  */
+  if (file->dont_read || file->err_no)
+    return false;
+
+  if (file->fd == -1 && !open_file (file))
     {
-      cpp_error (pfile, DL_ERROR, "%s is a block device", inc->name);
-      goto fail;
+      open_file_failed (pfile, file, 0);
+      return false;
     }
-  else
+
+  file->dont_read = !read_file_guts (pfile, file);
+  close (file->fd);
+  file->fd = -1;
+
+  return !file->dont_read;
+}
+
+/* Returns TRUE if FILE's contents have been successfully placed in
+   FILE->buffer and the file should be stacked, otherwise false.  */
+static bool
+should_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
+{
+  _cpp_file *f;
+
+  /* Skip once-only files.  */
+  if (file->once_only)
+    return false;
+
+  /* We must mark the file once-only if #import now, before header
+     guard checks.  Otherwise, undefining the header guard might
+     cause the file to be re-stacked.  */
+  if (import)
     {
-      /* 8 kilobytes is a sensible starting size.  It ought to be
-        bigger than the kernel pipe buffer, and it's definitely
-        bigger than the majority of C source files.  */
-      size = 8 * 1024;
-
-      buf = (uchar *) xmalloc (size + 1);
-      offset = 0;
-      while ((count = read (inc->fd, buf + offset, size - offset)) > 0)
-       {
-         offset += count;
-         if (offset == size)
-           {
-             size *= 2;
-             buf = xrealloc (buf, size + 1);
-           }
-       }
-      if (count < 0)
-       goto perror_fail;
+      _cpp_mark_file_once_only (pfile, file);
+
+      /* Don't stack files that have been stacked before.  */
+      if (file->stack_count)
+       return false;
+    }
 
-      if (offset + 1 < size)
-       buf = xrealloc (buf, offset + 1);
+  /* Skip if the file had a header guard and the macro is defined.
+     PCH relies on this appearing before the PCH handler below.  */
+  if (file->cmacro && file->cmacro->type == NT_MACRO)
+    return false;
 
-      /* The lexer requires that the buffer be NUL-terminated.  */
-      buf[offset] = '\0';
-      inc->st.st_size = offset;
+  /* Handle PCH files immediately; don't stack them.  */
+  if (include_pch_p (file))
+    {
+      pfile->cb.read_pch (pfile, file->path, file->fd, file->pchname);
+      close (file->fd);
+      file->fd = -1;
+      return false;
     }
 
-  inc->buffer = buf;
-  return 0;
+  if (!read_file (pfile, file))
+    return false;
 
- perror_fail:
-  cpp_errno (pfile, DL_ERROR, inc->name);
- fail:
-  return 1;
-}
+  /* Now we've read the file's contents, we can stack it if there
+     are no once-only files.  */
+  if (!pfile->seen_once_only)
+    return true;
 
-/* Drop INC's buffer from memory, if we are unlikely to need it again.  */
-static void
-purge_cache (inc)
-     struct include_file *inc;
-{
-  if (inc->buffer)
+  /* We may have read the file under a different name.  Look
+     for likely candidates and compare file contents to be sure.  */
+  for (f = pfile->all_files; f; f = f->next_file)
     {
-#if MMAP_THRESHOLD
-      if (inc->mapped)
+      if (f == file)
+       continue;
+
+      if ((import || f->once_only)
+         && f->err_no == 0
+         && f->st.st_mtime == file->st.st_mtime
+         && f->st.st_size == file->st.st_size)
        {
-         /* Undo the previous annotation for the
-            known-zero-byte-after-mmap.  Discard the handle to avoid
-            handle leak.  */
-         VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (inc->buffer
-                                                   + inc->st.st_size, 1));
-         munmap ((PTR) inc->buffer, inc->st.st_size);
+         _cpp_file *ref_file;
+         bool same_file_p = false;
+
+         if (f->buffer && !f->buffer_valid)
+           {
+             /* We already have a buffer but it is not valid, because
+                the file is still stacked.  Make a new one.  */
+             ref_file = make_cpp_file (pfile, f->dir, f->name);
+             ref_file->path = f->path;
+           }
+         else
+           /* The file is not stacked anymore.  We can reuse it.  */
+           ref_file = f;
+
+         same_file_p = read_file (pfile, ref_file)
+                       /* Size might have changed in read_file().  */
+                       && ref_file->st.st_size == file->st.st_size
+                       && !memcmp (ref_file->buffer,
+                                   file->buffer,
+                                   file->st.st_size);
+
+         if (f->buffer && !f->buffer_valid)
+           {
+             ref_file->path = 0;
+             destroy_cpp_file (ref_file);
+           }
+
+         if (same_file_p)
+           break;
        }
-      else
-#endif
-       free ((PTR) inc->buffer);
-      inc->buffer = NULL;
     }
+
+  return f == NULL;
 }
 
-/* Return 1 if the file named by FNAME has been included before in
-   any context, 0 otherwise.  */
-int
-cpp_included (pfile, fname)
-     cpp_reader *pfile;
-     const char *fname;
+/* Place the file referenced by FILE into a new buffer on the buffer
+   stack if possible.  IMPORT is true if this stacking attempt is
+   because of a #import directive.  Returns true if a buffer is
+   stacked.  */
+bool
+_cpp_stack_file (cpp_reader *pfile, _cpp_file *file, bool import)
 {
-  struct search_path *path;
-  char *name, *n;
-  splay_tree_node nd;
+  cpp_buffer *buffer;
+  int sysp;
+
+  if (!should_stack_file (pfile, file, import))
+      return false;
 
-  if (IS_ABSOLUTE_PATHNAME (fname))
+  sysp = MAX ((pfile->map ? pfile->map->sysp : 0),
+             (file->dir ? file->dir->sysp : 0));
+
+  /* Add the file to the dependencies on its first inclusion.  */
+  if (CPP_OPTION (pfile, deps.style) > !!sysp && !file->stack_count)
     {
-      /* Just look it up.  */
-      nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) fname);
-      return (nd && nd->value);
+      if (!file->main_file || !CPP_OPTION (pfile, deps.ignore_main_file))
+       deps_add_dep (pfile->deps, file->path);
     }
 
-  /* Search directory path for the file.  */
-  name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2);
-  for (path = CPP_OPTION (pfile, quote_include); path; path = path->next)
-    {
-      memcpy (name, path->name, path->len);
-      name[path->len] = '/';
-      strcpy (&name[path->len + 1], fname);
-      if (CPP_OPTION (pfile, remap))
-       n = remap_filename (pfile, name, path);
-      else
-       n = name;
+  /* Clear buffer_valid since _cpp_clean_line messes it up.  */
+  file->buffer_valid = false;
+  file->stack_count++;
 
-      nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) n);
-      if (nd && nd->value)
-       return 1;
-    }
-  return 0;
+  /* Stack the buffer.  */
+  buffer = cpp_push_buffer (pfile, file->buffer, file->st.st_size,
+                           CPP_OPTION (pfile, preprocessed));
+  buffer->file = file;
+
+  /* Initialize controlling macro state.  */
+  pfile->mi_valid = true;
+  pfile->mi_cmacro = 0;
+
+  /* Generate the call back.  */
+  _cpp_do_file_change (pfile, LC_ENTER, file->path, 1, sysp);
+
+  return true;
+}
+
+/* Mark FILE to be included once only.  */
+void
+_cpp_mark_file_once_only (cpp_reader *pfile, _cpp_file *file)
+{
+  pfile->seen_once_only = true;
+  file->once_only = true;
 }
 
-/* Search for HEADER.  Return 0 if there is no such file (or it's
-   un-openable), in which case an error code will be in errno.  If
-   there is no include path to use it returns NO_INCLUDE_PATH,
-   otherwise an include_file structure.  If this request originates
-   from a directive of TYPE #include_next, set INCLUDE_NEXT to true.  */
-static struct include_file *
-find_include_file (pfile, header, type)
-     cpp_reader *pfile;
-     const cpp_token *header;
-     enum include_type type;
+/* Return the directory from which searching for FNAME should start,
+   considering the directive TYPE and ANGLE_BRACKETS.  If there is
+   nothing left in the path, returns NULL.  */
+static struct cpp_dir *
+search_path_head (cpp_reader *pfile, const char *fname, int angle_brackets,
+                 enum include_type type)
 {
-  const char *fname = (const char *) header->val.str.text;
-  struct search_path *path;
-  struct include_file *file;
-  char *name, *n;
+  cpp_dir *dir;
+  _cpp_file *file;
+
+  if (IS_ABSOLUTE_PATH (fname))
+    return &pfile->no_search_path;
 
-  if (IS_ABSOLUTE_PATHNAME (fname))
-    return open_file (pfile, fname);
+  /* pfile->buffer is NULL when processing an -include command-line flag.  */
+  file = pfile->buffer == NULL ? pfile->main_file : pfile->buffer->file;
 
   /* For #include_next, skip in the search path past the dir in which
      the current file was found, but if it was found via an absolute
      path use the normal search logic.  */
-  if (type == IT_INCLUDE_NEXT && pfile->buffer->inc->foundhere)
-    path = pfile->buffer->inc->foundhere->next;
-  else if (header->type == CPP_HEADER_NAME)
-    path = CPP_OPTION (pfile, bracket_include);
+  if (type == IT_INCLUDE_NEXT && file->dir)
+    dir = file->dir->next;
+  else if (angle_brackets)
+    dir = pfile->bracket_include;
+  else if (type == IT_CMDLINE)
+    /* -include and -imacros use the #include "" chain with the
+       preprocessor's cwd prepended.  */
+    return make_cpp_dir (pfile, "./", false);
+  else if (pfile->quote_ignores_source_dir)
+    dir = pfile->quote_include;
   else
-    path = search_from (pfile, type);
+    return make_cpp_dir (pfile, dir_name_of_file (file), pfile->map->sysp);
+
+  if (dir == NULL)
+    cpp_error (pfile, CPP_DL_ERROR,
+              "no include path in which to search for %s", fname);
+
+  return dir;
+}
 
-  if (path == NULL)
+/* Strip the basename from the file's path.  It ends with a slash if
+   of nonzero length.  Note that this procedure also works for
+   <stdin>, which is represented by the empty string.  */
+static const char *
+dir_name_of_file (_cpp_file *file)
+{
+  if (!file->dir_name)
     {
-      cpp_error (pfile, DL_ERROR, "no include path in which to find %s",
-                fname);
-      return NO_INCLUDE_PATH;
+      size_t len = lbasename (file->path) - file->path;
+      char *dir_name = xmalloc (len + 1);
+
+      memcpy (dir_name, file->path, len);
+      dir_name[len] = '\0';
+      file->dir_name = dir_name;
     }
 
-  /* Search directory path for the file.  */
-  name = (char *) alloca (strlen (fname) + pfile->max_include_len + 2);
-  for (; path; path = path->next)
+  return file->dir_name;
+}
+
+/* Handles #include-family directives (distinguished by TYPE),
+   including HEADER, and the command line -imacros and -include.
+   Returns true if a buffer was stacked.  */
+bool
+_cpp_stack_include (cpp_reader *pfile, const char *fname, int angle_brackets,
+                   enum include_type type)
+{
+  struct cpp_dir *dir;
+
+  dir = search_path_head (pfile, fname, angle_brackets, type);
+  if (!dir)
+    return false;
+
+  return _cpp_stack_file (pfile, _cpp_find_file (pfile, fname, dir, false,
+                                                angle_brackets),
+                    type == IT_IMPORT);
+}
+
+/* Could not open FILE.  The complication is dependency output.  */
+static void
+open_file_failed (cpp_reader *pfile, _cpp_file *file, int angle_brackets)
+{
+  int sysp = pfile->map ? pfile->map->sysp: 0;
+  bool print_dep = CPP_OPTION (pfile, deps.style) > (angle_brackets || !!sysp);
+
+  errno = file->err_no;
+  if (print_dep && CPP_OPTION (pfile, deps.missing_files) && errno == ENOENT)
+    deps_add_dep (pfile->deps, file->name);
+  else
     {
-      int len = path->len;
-      memcpy (name, path->name, len);
-      /* Don't turn / into // or // into ///; // may be a namespace
-        escape.  */
-      if (name[len-1] == '/')
-       len--;
-      name[len] = '/';
-      strcpy (&name[len + 1], fname);
-      if (CPP_OPTION (pfile, remap))
-       n = remap_filename (pfile, name, path);
+      /* If we are outputting dependencies but not for this file then
+        don't error because we can still produce correct output.  */
+      if (CPP_OPTION (pfile, deps.style) && ! print_dep)
+       cpp_errno (pfile, CPP_DL_WARNING, file->path);
       else
-       n = name;
-
-      file = open_file (pfile, n);
-      if (file)
-       {
-         file->foundhere = path;
-         return file;
-       }
+       cpp_errno (pfile, CPP_DL_ERROR, file->path);
     }
+}
 
-  return 0;
+/* Search in the chain beginning at HEAD for a file whose search path
+   started at START_DIR != NULL.  */
+static struct file_hash_entry *
+search_cache (struct file_hash_entry *head, const cpp_dir *start_dir)
+{
+  while (head && head->start_dir != start_dir)
+    head = head->next;
+
+  return head;
+}
+
+/* Allocate a new _cpp_file structure.  */
+static _cpp_file *
+make_cpp_file (cpp_reader *pfile, cpp_dir *dir, const char *fname)
+{
+  _cpp_file *file;
+
+  file = xcalloc (1, sizeof (_cpp_file));
+  file->main_file = !pfile->buffer;
+  file->fd = -1;
+  file->dir = dir;
+  file->name = xstrdup (fname);
+
+  return file;
+}
+
+/* Release a _cpp_file structure.  */
+static void
+destroy_cpp_file (_cpp_file *file)
+{
+  if (file->buffer)
+    free ((void *) file->buffer);
+  free ((void *) file->name);
+  free (file);
+}
+
+/* A hash of directory names.  The directory names are the path names
+   of files which contain a #include "", the included file name is
+   appended to this directories.
+
+   To avoid duplicate entries we follow the convention that all
+   non-empty directory names should end in a '/'.  DIR_NAME must be
+   stored in permanently allocated memory.  */
+static cpp_dir *
+make_cpp_dir (cpp_reader *pfile, const char *dir_name, int sysp)
+{
+  struct file_hash_entry *entry, **hash_slot;
+  cpp_dir *dir;
+
+  hash_slot = (struct file_hash_entry **)
+    htab_find_slot_with_hash (pfile->dir_hash, dir_name,
+                             htab_hash_string (dir_name),
+                             INSERT);
+
+  /* Have we already hashed this directory?  */
+  for (entry = *hash_slot; entry; entry = entry->next)
+    if (entry->start_dir == NULL)
+      return entry->u.dir;
+
+  dir = xcalloc (1, sizeof (cpp_dir));
+  dir->next = pfile->quote_include;
+  dir->name = (char *) dir_name;
+  dir->len = strlen (dir_name);
+  dir->sysp = sysp;
+
+  /* Store this new result in the hash table.  */
+  entry = new_file_hash_entry (pfile);
+  entry->next = *hash_slot;
+  entry->start_dir = NULL;
+  entry->u.dir = dir;
+  *hash_slot = entry;
+
+  return dir;
+}
+
+/* Create a new block of memory for file hash entries.  */
+static void
+allocate_file_hash_entries (cpp_reader *pfile)
+{
+  pfile->file_hash_entries_used = 0;
+  pfile->file_hash_entries_allocated = 127;
+  pfile->file_hash_entries = xmalloc
+    (pfile->file_hash_entries_allocated * sizeof (struct file_hash_entry));
+}
+
+/* Return a new file hash entry.  */
+static struct file_hash_entry *
+new_file_hash_entry (cpp_reader *pfile)
+{
+  if (pfile->file_hash_entries_used == pfile->file_hash_entries_allocated)
+    allocate_file_hash_entries (pfile);
+
+  return &pfile->file_hash_entries[pfile->file_hash_entries_used++];
+}
+
+/* Returns TRUE if a file FNAME has ever been successfully opened.
+   This routine is not intended to correctly handle filenames aliased
+   by links or redundant . or .. traversals etc.  */
+bool
+cpp_included (cpp_reader *pfile, const char *fname)
+{
+  struct file_hash_entry *entry;
+
+  entry = htab_find_with_hash (pfile->file_hash, fname,
+                              htab_hash_string (fname));
+
+  while (entry && (entry->start_dir == NULL || entry->u.file->err_no))
+    entry = entry->next;
+
+  return entry != NULL;
+}
+
+/* Calculate the hash value of a file hash entry P.  */
+
+static hashval_t
+file_hash_hash (const void *p)
+{
+  struct file_hash_entry *entry = (struct file_hash_entry *) p;
+  const char *hname;
+  if (entry->start_dir)
+    hname = entry->u.file->name;
+  else
+    hname = entry->u.dir->name;
+
+  return htab_hash_string (hname);
+}
+
+/* Compare a string Q against a file hash entry P.  */
+static int
+file_hash_eq (const void *p, const void *q)
+{
+  struct file_hash_entry *entry = (struct file_hash_entry *) p;
+  const char *fname = (const char *) q;
+  const char *hname;
+
+  if (entry->start_dir)
+    hname = entry->u.file->name;
+  else
+    hname = entry->u.dir->name;
+
+  return strcmp (hname, fname) == 0;
+}
+
+/* Initialize everything in this source file.  */
+void
+_cpp_init_files (cpp_reader *pfile)
+{
+  pfile->file_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq,
+                                       NULL, xcalloc, free);
+  pfile->dir_hash = htab_create_alloc (127, file_hash_hash, file_hash_eq,
+                                       NULL, xcalloc, free);
+  allocate_file_hash_entries (pfile);
+}
+
+/* Finalize everything in this source file.  */
+void
+_cpp_cleanup_files (cpp_reader *pfile)
+{
+  htab_delete (pfile->file_hash);
+  htab_delete (pfile->dir_hash);
+}
+
+/* Enter a file name in the hash for the sake of cpp_included.  */
+void
+_cpp_fake_include (cpp_reader *pfile, const char *fname)
+{
+  _cpp_find_file (pfile, fname, pfile->buffer->file->dir, true, 0);
 }
 
 /* Not everyone who wants to set system-header-ness on a buffer can
    see the details of a buffer.  This is an exported interface because
    fix-header needs it.  */
 void
-cpp_make_system_header (pfile, syshdr, externc)
-     cpp_reader *pfile;
-     int syshdr, externc;
+cpp_make_system_header (cpp_reader *pfile, int syshdr, int externc)
 {
   int flags = 0;
 
@@ -654,226 +978,159 @@ cpp_make_system_header (pfile, syshdr, externc)
                       SOURCE_LINE (pfile->map, pfile->line), flags);
 }
 
-/* Report on all files that might benefit from a multiple include guard.
-   Triggered by -H.  */
+/* Allow the client to change the current file.  Used by the front end
+   to achieve pseudo-file names like <built-in>.
+   If REASON is LC_LEAVE, then NEW_NAME must be NULL.  */
 void
-_cpp_report_missing_guards (pfile)
-     cpp_reader *pfile;
+cpp_change_file (cpp_reader *pfile, enum lc_reason reason,
+                const char *new_name)
 {
-  int banner = 0;
-  splay_tree_foreach (pfile->all_include_files, report_missing_guard,
-                     (PTR) &banner);
+  _cpp_do_file_change (pfile, reason, new_name, 1, 0);
 }
 
-/* Callback function for splay_tree_foreach().  */
+/* Callback function for htab_traverse.  */
 static int
-report_missing_guard (n, b)
-     splay_tree_node n;
-     void *b;
+report_missing_guard (void **slot, void *b)
 {
-  struct include_file *f = (struct include_file *) n->value;
+  struct file_hash_entry *entry = (struct file_hash_entry *) *slot;
   int *bannerp = (int *) b;
 
-  if (f && f->cmacro == 0 && f->include_count == 1)
+  /* Skip directories.  */
+  if (entry->start_dir != NULL)
     {
-      if (*bannerp == 0)
+      _cpp_file *file = entry->u.file;
+
+      /* We don't want MI guard advice for the main file.  */
+      if (file->cmacro == NULL && file->stack_count == 1 && !file->main_file)
        {
-         fputs (_("Multiple include guards may be useful for:\n"), stderr);
-         *bannerp = 1;
+         if (*bannerp == 0)
+           {
+             fputs (_("Multiple include guards may be useful for:\n"),
+                    stderr);
+             *bannerp = 1;
+           }
+
+         fputs (entry->u.file->path, stderr);
+         putc ('\n', stderr);
        }
-      fputs (f->name, stderr);
-      putc ('\n', stderr);
     }
-  return 0;
-}
 
-/* Create a dependency for file FNAME, or issue an error message as
-   appropriate.  ANGLE_BRACKETS is nonzero if the file was bracketed
-   like <..>.  */
-static void
-handle_missing_header (pfile, fname, angle_brackets)
-     cpp_reader *pfile;
-     const char *fname;
-     int angle_brackets;
-{
-  bool print_dep
-    = CPP_OPTION (pfile, deps.style) > (angle_brackets || pfile->map->sysp);
-
-  if (CPP_OPTION (pfile, deps.missing_files) && print_dep)
-    deps_add_dep (pfile->deps, fname);
-  /* If -M was specified, then don't count this as an error, because
-     we can still produce correct output.  Otherwise, we can't produce
-     correct output, because there may be dependencies we need inside
-     the missing file, and we don't know what directory this missing
-     file exists in.  */
-  else
-    cpp_errno (pfile, CPP_OPTION (pfile, deps.style) && ! print_dep
-              ? DL_WARNING: DL_ERROR, fname);
+  return 0;
 }
 
-/* Handles #include-family directives (distinguished by TYPE),
-   including HEADER, and the command line -imacros and -include.
-   Returns true if a buffer was stacked.  */
-bool
-_cpp_execute_include (pfile, header, type)
-     cpp_reader *pfile;
-     const cpp_token *header;
-     enum include_type type;
+/* Report on all files that might benefit from a multiple include guard.
+   Triggered by -H.  */
+void
+_cpp_report_missing_guards (cpp_reader *pfile)
 {
-  bool stacked = false;
-  struct include_file *inc = find_include_file (pfile, header, type);
-
-  if (inc == 0)
-    handle_missing_header (pfile, (const char *) header->val.str.text,
-                          header->type == CPP_HEADER_NAME);
-  else if (inc != NO_INCLUDE_PATH)
-    {
-      stacked = stack_include_file (pfile, inc);
-
-      if (type == IT_IMPORT)
-       _cpp_never_reread (inc);
-    }
+  int banner = 0;
 
-  return stacked;
+  htab_traverse (pfile->file_hash, report_missing_guard, &banner);
 }
 
 /* Locate HEADER, and determine whether it is newer than the current
-   file.  If it cannot be located or dated, return -1, if it is newer
+   file.  If it cannot be located or dated, return -1, if it is
    newer, return 1, otherwise 0.  */
 int
-_cpp_compare_file_date (pfile, header)
-     cpp_reader *pfile;
-     const cpp_token *header;
+_cpp_compare_file_date (cpp_reader *pfile, const char *fname,
+                       int angle_brackets)
 {
-  struct include_file *inc = find_include_file (pfile, header, 0);
+  _cpp_file *file;
+  struct cpp_dir *dir;
 
-  if (inc == NULL || inc == NO_INCLUDE_PATH)
+  dir = search_path_head (pfile, fname, angle_brackets, IT_INCLUDE);
+  if (!dir)
     return -1;
 
-  if (inc->fd > 0)
+  file = _cpp_find_file (pfile, fname, dir, false, angle_brackets);
+  if (file->err_no)
+    return -1;
+
+  if (file->fd != -1)
     {
-      close (inc->fd);
-      inc->fd = -1;
+      close (file->fd);
+      file->fd = -1;
     }
 
-  return inc->st.st_mtime > pfile->buffer->inc->st.st_mtime;
+  return file->st.st_mtime > pfile->buffer->file->st.st_mtime;
 }
 
-
-/* Push an input buffer and load it up with the contents of FNAME.  If
-   FNAME is "", read standard input.  Return true if a buffer was
-   stacked.  */
+/* Pushes the given file onto the buffer stack.  Returns nonzero if
+   successful.  */
 bool
-_cpp_read_file (pfile, fname)
-     cpp_reader *pfile;
-     const char *fname;
+cpp_push_include (cpp_reader *pfile, const char *fname)
 {
-  struct include_file *f = open_file (pfile, fname);
-
-  if (f == NULL)
-    {
-      cpp_errno (pfile, DL_ERROR, fname);
-      return false;
-    }
-
-  return stack_include_file (pfile, f);
+  /* Make the command line directive take up a line.  */
+  pfile->line++;
+  return _cpp_stack_include (pfile, fname, false, IT_CMDLINE);
 }
 
 /* Do appropriate cleanup when a file INC's buffer is popped off the
    input stack.  */
 void
-_cpp_pop_file_buffer (pfile, inc)
-     cpp_reader *pfile;
-     struct include_file *inc;
+_cpp_pop_file_buffer (cpp_reader *pfile, _cpp_file *file)
 {
   /* Record the inclusion-preventing macro, which could be NULL
      meaning no controlling macro.  */
-  if (pfile->mi_valid && inc->cmacro == NULL)
-    inc->cmacro = pfile->mi_cmacro;
+  if (pfile->mi_valid && file->cmacro == NULL)
+    file->cmacro = pfile->mi_cmacro;
 
   /* Invalidate control macros in the #including file.  */
   pfile->mi_valid = false;
 
-  inc->refcnt--;
-  if (inc->refcnt == 0 && DO_NOT_REREAD (inc))
-    purge_cache (inc);
+  if (file->buffer)
+    {
+      free ((void *) file->buffer);
+      file->buffer = NULL;
+      file->buffer_valid = false;
+    }
 }
 
-/* Returns the first place in the include chain to start searching for
-   "" includes.  This involves stripping away the basename of the
-   current file, unless -I- was specified.
+/* Set the include chain for "" to QUOTE, for <> to BRACKET.  If
+   QUOTE_IGNORES_SOURCE_DIR, then "" includes do not look in the
+   directory of the including file.
 
-   If we're handling -include or -imacros, use the "" chain, but with
-   the preprocessor's cwd prepended.  */
-static struct search_path *
-search_from (pfile, type)
-     cpp_reader *pfile;
-     enum include_type type;
+   If BRACKET does not lie in the QUOTE chain, it is set to QUOTE.  */
+void
+cpp_set_include_chains (cpp_reader *pfile, cpp_dir *quote, cpp_dir *bracket,
+                       int quote_ignores_source_dir)
 {
-  cpp_buffer *buffer = pfile->buffer;
-  unsigned int dlen;
+  pfile->quote_include = quote;
+  pfile->bracket_include = quote;
+  pfile->quote_ignores_source_dir = quote_ignores_source_dir;
 
-  /* Command line uses the cwd, and does not cache the result.  */
-  if (type == IT_CMDLINE)
-    goto use_cwd;
-
-  /* Ignore the current file's directory if -I- was given.  */
-  if (CPP_OPTION (pfile, ignore_srcdir))
-    return CPP_OPTION (pfile, quote_include);
-
-  if (! buffer->search_cached)
+  for (; quote; quote = quote->next)
     {
-      buffer->search_cached = 1;
-
-      dlen = lbasename (buffer->inc->name) - buffer->inc->name;
-
-      if (dlen)
-       {
-         /* We don't guarantee NAME is null-terminated.  This saves
-            allocating and freeing memory.  Drop a trailing '/'.  */
-         buffer->dir.name = buffer->inc->name;
-         if (dlen > 1)
-           dlen--;
-       }
-      else
-       {
-       use_cwd:
-         buffer->dir.name = ".";
-         dlen = 1;
-       }
-
-      if (dlen > pfile->max_include_len)
-       pfile->max_include_len = dlen;
-
-      buffer->dir.len = dlen;
-      buffer->dir.next = CPP_OPTION (pfile, quote_include);
-      buffer->dir.sysp = pfile->map->sysp;
+      quote->name_map = NULL;
+      quote->len = strlen (quote->name);
+      if (quote == bracket)
+       pfile->bracket_include = bracket;
     }
-
-  return &buffer->dir;
 }
 
-/* The file_name_map structure holds a mapping of file names for a
-   particular directory.  This mapping is read from the file named
-   FILE_NAME_MAP_FILE in that directory.  Such a file can be used to
-   map filenames on a file system with severe filename restrictions,
-   such as DOS.  The format of the file name map file is just a series
-   of lines with two tokens on each line.  The first token is the name
-   to map, and the second token is the actual name to use.  */
-struct file_name_map {
-  struct file_name_map *map_next;
-  char *map_from;
-  char *map_to;
-};
+/* Append the file name to the directory to create the path, but don't
+   turn / into // or // into ///; // may be a namespace escape.  */
+static char *
+append_file_to_dir (const char *fname, cpp_dir *dir)
+{
+  size_t dlen, flen;
+  char *path;
 
-#define FILE_NAME_MAP_FILE "header.gcc"
+  dlen = dir->len;
+  flen = strlen (fname);
+  path = xmalloc (dlen + 1 + flen + 1);
+  memcpy (path, dir->name, dlen);
+  if (dlen && path[dlen - 1] != '/')
+    path[dlen++] = '/';
+  memcpy (&path[dlen], fname, flen + 1);
+
+  return path;
+}
 
 /* Read a space delimited string of unlimited length from a stdio
    file F.  */
 static char *
-read_filename_string (ch, f)
-     int ch;
-     FILE *f;
+read_filename_string (int ch, FILE *f)
 {
   char *alloc, *set;
   int len;
@@ -899,43 +1156,25 @@ read_filename_string (ch, f)
   return alloc;
 }
 
-/* This structure holds a linked list of file name maps, one per directory.  */
-struct file_name_map_list {
-  struct file_name_map_list *map_list_next;
-  char *map_list_name;
-  struct file_name_map *map_list_map;
-};
-
-/* Read the file name map file for DIRNAME.  */
-static struct file_name_map *
-read_name_map (pfile, dirname)
-     cpp_reader *pfile;
-     const char *dirname;
+/* Read the file name map file for DIR.  */
+static void
+read_name_map (cpp_dir *dir)
 {
-  struct file_name_map_list *map_list_ptr;
+  static const char FILE_NAME_MAP_FILE[] = "header.gcc";
   char *name;
   FILE *f;
-
-  /* Check the cache of directories, and mappings in their remap file.  */
-  for (map_list_ptr = CPP_OPTION (pfile, map_list); map_list_ptr;
-       map_list_ptr = map_list_ptr->map_list_next)
-    if (! strcmp (map_list_ptr->map_list_name, dirname))
-      return map_list_ptr->map_list_map;
-
-  map_list_ptr = ((struct file_name_map_list *)
-                 xmalloc (sizeof (struct file_name_map_list)));
-  map_list_ptr->map_list_name = xstrdup (dirname);
-
-  /* The end of the list ends in NULL.  */
-  map_list_ptr->map_list_map = NULL;
-
-  name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
-  strcpy (name, dirname);
-  if (*dirname)
-    strcat (name, "/");
-  strcat (name, FILE_NAME_MAP_FILE);
+  size_t len, count = 0, room = 9;
+
+  len = dir->len;
+  name = alloca (len + sizeof (FILE_NAME_MAP_FILE) + 1);
+  memcpy (name, dir->name, len);
+  if (len && name[len - 1] != '/')
+    name[len++] = '/';
+  strcpy (name + len, FILE_NAME_MAP_FILE);
   f = fopen (name, "r");
 
+  dir->name_map = xmalloc (room * sizeof (char *));
+
   /* Silently return NULL if we cannot open.  */
   if (f)
     {
@@ -943,253 +1182,116 @@ read_name_map (pfile, dirname)
 
       while ((ch = getc (f)) != EOF)
        {
-         char *from, *to;
-         struct file_name_map *ptr;
+         char *to;
 
          if (is_space (ch))
            continue;
-         from = read_filename_string (ch, f);
+
+         if (count + 2 > room)
+           {
+             room += 8;
+             dir->name_map = xrealloc (dir->name_map, room * sizeof (char *));
+           }
+
+         dir->name_map[count] = read_filename_string (ch, f);
          while ((ch = getc (f)) != EOF && is_hspace (ch))
            ;
-         to = read_filename_string (ch, f);
-
-         ptr = ((struct file_name_map *)
-                xmalloc (sizeof (struct file_name_map)));
-         ptr->map_from = from;
 
-         /* Make the real filename absolute.  */
-         if (IS_ABSOLUTE_PATHNAME (to))
-           ptr->map_to = to;
+         to = read_filename_string (ch, f);
+         if (IS_ABSOLUTE_PATH (to))
+           dir->name_map[count + 1] = to;
          else
            {
-             ptr->map_to = concat (dirname, "/", to, NULL);
+             dir->name_map[count + 1] = append_file_to_dir (to, dir);
              free (to);
            }
 
-         ptr->map_next = map_list_ptr->map_list_map;
-         map_list_ptr->map_list_map = ptr;
-
+         count += 2;
          while ((ch = getc (f)) != '\n')
            if (ch == EOF)
              break;
        }
+
       fclose (f);
     }
 
-  /* Add this information to the cache.  */
-  map_list_ptr->map_list_next = CPP_OPTION (pfile, map_list);
-  CPP_OPTION (pfile, map_list) = map_list_ptr;
-
-  return map_list_ptr->map_list_map;
+  /* Terminate the list of maps.  */
+  dir->name_map[count] = NULL;
 }
 
-/* Remap an unsimplified path NAME based on the file_name_map (if any)
-   for LOC.  */
+/* Remap a FILE's name based on the file_name_map, if any, for
+   FILE->dir.  If the file name has any directory separators,
+   recursively check those directories too.  */
 static char *
-remap_filename (pfile, name, loc)
-     cpp_reader *pfile;
-     char *name;
-     struct search_path *loc;
+remap_filename (cpp_reader *pfile, _cpp_file *file)
 {
-  struct file_name_map *map;
-  const char *from, *p;
-  char *dir;
-
-  if (! loc->name_map)
-    {
-      /* Get a null-terminated path.  */
-      char *dname = alloca (loc->len + 1);
-      memcpy (dname, loc->name, loc->len);
-      dname[loc->len] = '\0';
-
-      loc->name_map = read_name_map (pfile, dname);
-      if (! loc->name_map)
-       return name;
-    }
+  const char *fname, *p;
+  char *new_dir;
+  cpp_dir *dir;
+  size_t index, len;
 
-  /* This works since NAME has not been simplified yet.  */
-  from = name + loc->len + 1;
+  dir = file->dir;
+  fname = file->name;
 
-  for (map = loc->name_map; map; map = map->map_next)
-    if (!strcmp (map->map_from, from))
-      return map->map_to;
-
-  /* Try to find a mapping file for the particular directory we are
-     looking in.  Thus #include <sys/types.h> will look up sys/types.h
-     in /usr/include/header.gcc and look up types.h in
-     /usr/include/sys/header.gcc.  */
-  p = strrchr (name, '/');
-  if (!p)
-    return name;
+  for (;;)
+    {
+      if (!dir->name_map)
+       read_name_map (dir);
 
-  /* We know p != name as absolute paths don't call remap_filename.  */
-  if (p == name)
-    cpp_error (pfile, DL_ICE, "absolute file name in remap_filename");
+      for (index = 0; dir->name_map[index]; index += 2)
+       if (!strcmp (dir->name_map[index], fname))
+           return xstrdup (dir->name_map[index + 1]);
 
-  dir = (char *) alloca (p - name + 1);
-  memcpy (dir, name, p - name);
-  dir[p - name] = '\0';
-  from = p + 1;
+      p = strchr (fname, '/');
+      if (!p || p == fname)
+       return NULL;
 
-  for (map = read_name_map (pfile, dir); map; map = map->map_next)
-    if (! strcmp (map->map_from, from))
-      return map->map_to;
+      len = dir->len + (p - fname + 1);
+      new_dir = xmalloc (len + 1);
+      memcpy (new_dir, dir->name, dir->len);
+      memcpy (new_dir + dir->len, fname, p - fname + 1);
+      new_dir[len] = '\0';
 
-  return name;
+      dir = make_cpp_dir (pfile, new_dir, dir->sysp);
+      fname = p + 1;
+    }
 }
 
-/* Returns true if it is safe to remove the final component of path,
-   when it is followed by a ".." component.  We use lstat to avoid
-   symlinks if we have it.  If not, we can still catch errors with
-   stat ().  */
-static int
-remove_component_p (path)
-     const char *path;
+/* Return true if FILE is usable by PCH.  */
+static bool
+include_pch_p (_cpp_file *file)
 {
-  struct stat s;
-  int result;
-
-#ifdef HAVE_LSTAT
-  result = lstat (path, &s);
-#else
-  result = stat (path, &s);
-#endif
-
-  /* There's no guarantee that errno will be unchanged, even on
-     success.  Cygwin's lstat(), for example, will often set errno to
-     ENOSYS.  In case of success, reset errno to zero.  */
-  if (result == 0)
-    errno = 0;
-
-  return result == 0 && S_ISDIR (s.st_mode);
+  return file->pch & 1;
 }
 
-/* Simplify a path name in place, deleting redundant components.  This
-   reduces OS overhead and guarantees that equivalent paths compare
-   the same (modulo symlinks).
-
-   Transforms made:
-   foo/bar/../quux     foo/quux
-   foo/./bar           foo/bar
-   foo//bar            foo/bar
-   /../quux            /quux
-   //quux              //quux  (POSIX allows leading // as a namespace escape)
-
-   Guarantees no trailing slashes.  All transforms reduce the length
-   of the string.  Returns PATH.  errno is 0 if no error occurred;
-   nonzero if an error occurred when using stat () or lstat ().  */
-char *
-_cpp_simplify_pathname (path)
-     char *path;
+/* Returns true if PCHNAME is a valid PCH file for FILE.  */
+static bool
+validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname)
 {
-#ifndef VMS
-  char *from, *to;
-  char *base, *orig_base;
-  int absolute = 0;
-
-  errno = 0;
-  /* Don't overflow the empty path by putting a '.' in it below.  */
-  if (*path == '\0')
-    return path;
-
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
-  /* Convert all backslashes to slashes.  */
-  for (from = path; *from; from++)
-    if (*from == '\\') *from = '/';
-
-  /* Skip over leading drive letter if present.  */
-  if (ISALPHA (path[0]) && path[1] == ':')
-    from = to = &path[2];
-  else
-    from = to = path;
-#else
-  from = to = path;
-#endif
+  const char *saved_path = file->path;
+  bool valid = false;
 
-  /* Remove redundant leading /s.  */
-  if (*from == '/')
+  file->path = pchname;
+  if (open_file (file))
     {
-      absolute = 1;
-      to++;
-      from++;
-      if (*from == '/')
+      valid = 1 & pfile->cb.valid_pch (pfile, pchname, file->fd);
+
+      if (!valid)
        {
-         if (*++from == '/')
-           /* 3 or more initial /s are equivalent to 1 /.  */
-           while (*++from == '/');
-         else
-           /* On some hosts // differs from /; Posix allows this.  */
-           to++;
+         close (file->fd);
+         file->fd = -1;
        }
-    }
 
-  base = orig_base = to;
-  for (;;)
-    {
-      int move_base = 0;
-
-      while (*from == '/')
-       from++;
-
-      if (*from == '\0')
-       break;
-
-      if (*from == '.')
+      if (CPP_OPTION (pfile, print_include_names))
        {
-         if (from[1] == '\0')
-           break;
-         if (from[1] == '/')
-           {
-             from += 2;
-             continue;
-           }
-         else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0'))
-           {
-             /* Don't simplify if there was no previous component.  */
-             if (absolute && orig_base == to)
-               {
-                 from += 2;
-                 continue;
-               }
-             /* Don't simplify if the previous component was "../",
-                or if an error has already occurred with (l)stat.  */
-             if (base != to && errno == 0)
-               {
-                 /* We don't back up if it's a symlink.  */
-                 *to = '\0';
-                 if (remove_component_p (path))
-                   {
-                     while (to > base && *to != '/')
-                       to--;
-                     from += 2;
-                     continue;
-                   }
-               }
-             move_base = 1;
-           }
+         unsigned int i;
+         for (i = 1; i < pfile->line_maps.depth; i++)
+           putc ('.', stderr);
+         fprintf (stderr, "%c %s\n",
+                  valid ? '!' : 'x', pchname);
        }
-
-      /* Add the component separator.  */
-      if (to > orig_base)
-       *to++ = '/';
-
-      /* Copy this component until the trailing null or '/'.  */
-      while (*from != '\0' && *from != '/')
-       *to++ = *from++;
-
-      if (move_base)
-       base = to;
     }
 
-  /* Change the empty string to "." so that it is not treated as stdin.
-     Null terminate.  */
-  if (to == path)
-    *to++ = '.';
-  *to = '\0';
-
-  return path;
-#else /* VMS  */
-  errno = 0;
-  return path;
-#endif /* !VMS  */
+  file->path = saved_path;
+  return valid;
 }
index e23b38e69e1fc322a4cb14ce4796e22e946b3753..9d2f51aeb4fcadb592e8017ae9e04cfa59055a00 100644 (file)
@@ -28,28 +28,24 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #include "cpplib.h"
 #include "cpphash.h"
 
-static cpp_hashnode *alloc_node PARAMS ((hash_table *));
+static cpp_hashnode *alloc_node (hash_table *);
 
 /* Return an identifier node for hashtable.c.  Used by cpplib except
    when integrated with the C front ends.  */
 static cpp_hashnode *
-alloc_node (table)
-     hash_table *table;
+alloc_node (hash_table *table)
 {
   cpp_hashnode *node;
 
-  node = (cpp_hashnode *) obstack_alloc (&table->pfile->hash_ob,
-                                        sizeof (cpp_hashnode));
-  memset ((PTR) node, 0, sizeof (cpp_hashnode));
+  node = obstack_alloc (&table->pfile->hash_ob, sizeof (cpp_hashnode));
+  memset (node, 0, sizeof (cpp_hashnode));
   return node;
 }
 
 /* Set up the identifier hash table.  Use TABLE if non-null, otherwise
    create our own.  */
 void
-_cpp_init_hashtable (pfile, table)
-     cpp_reader *pfile;
-     hash_table *table;
+_cpp_init_hashtable (cpp_reader *pfile, hash_table *table)
 {
   struct spec_nodes *s;
 
@@ -57,8 +53,11 @@ _cpp_init_hashtable (pfile, table)
     {
       pfile->our_hashtable = 1;
       table = ht_create (13);  /* 8K (=2^13) entries.  */
-      table->alloc_node = (hashnode (*) PARAMS ((hash_table *))) alloc_node;
-      gcc_obstack_init (&pfile->hash_ob);
+      table->alloc_node = (hashnode (*) (hash_table *)) alloc_node;
+
+      _obstack_begin (&pfile->hash_ob, 0, 0,
+                     (void *(*) (long)) xmalloc,
+                     (void (*) (void *)) free);
     }
 
   table->pfile = pfile;
@@ -81,8 +80,7 @@ _cpp_init_hashtable (pfile, table)
 
 /* Tear down the identifier hash table.  */
 void
-_cpp_destroy_hashtable (pfile)
-     cpp_reader *pfile;
+_cpp_destroy_hashtable (cpp_reader *pfile)
 {
   if (pfile->our_hashtable)
     {
@@ -94,10 +92,7 @@ _cpp_destroy_hashtable (pfile)
 /* Returns the hash entry for the STR of length LEN, creating one
    if necessary.  */
 cpp_hashnode *
-cpp_lookup (pfile, str, len)
-     cpp_reader *pfile;
-     const unsigned char *str;
-     unsigned int len;
+cpp_lookup (cpp_reader *pfile, const unsigned char *str, unsigned int len)
 {
   /* ht_lookup cannot return NULL.  */
   return CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_ALLOC));
@@ -105,10 +100,7 @@ cpp_lookup (pfile, str, len)
 
 /* Determine whether the str STR, of length LEN, is a defined macro.  */
 int
-cpp_defined (pfile, str, len)
-     cpp_reader *pfile;
-     const unsigned char *str;
-     int len;
+cpp_defined (cpp_reader *pfile, const unsigned char *str, int len)
 {
   cpp_hashnode *node;
 
@@ -121,10 +113,7 @@ cpp_defined (pfile, str, len)
 /* For all nodes in the hashtable, callback CB with parameters PFILE,
    the node, and V.  */
 void
-cpp_forall_identifiers (pfile, cb, v)
-     cpp_reader *pfile;
-     cpp_cb cb;
-     PTR v;
+cpp_forall_identifiers (cpp_reader *pfile, cpp_cb cb, void *v)
 {
   /* We don't need a proxy since the hash table's identifier comes
      first in cpp_hashnode.  */
index 0643f93bd7a138f51b21c21757ff01faca9e56da..afe4c832eb853fc00c0b3d2dc4d557b4f81c7f57 100644 (file)
@@ -1,5 +1,5 @@
 /* Part of CPP library.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
    Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify it
@@ -25,9 +25,25 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "hashtable.h"
 
+#if defined HAVE_ICONV_H && defined HAVE_ICONV
+#include <iconv.h>
+#else
+#define HAVE_ICONV 0
+typedef int iconv_t;  /* dummy */
+#endif
+
 struct directive;              /* Deliberately incomplete.  */
 struct pending_option;
 struct op;
+struct _cpp_strbuf;
+
+typedef bool (*convert_f) (iconv_t, const unsigned char *, size_t,
+                          struct _cpp_strbuf *);
+struct cset_converter
+{
+  convert_f func;
+  iconv_t cd;
+};
 
 #ifndef HAVE_UCHAR
 typedef unsigned char uchar;
@@ -45,7 +61,7 @@ typedef unsigned char uchar;
 
 #define CPP_OPTION(PFILE, OPTION) ((PFILE)->opts.OPTION)
 #define CPP_BUFFER(PFILE) ((PFILE)->buffer)
-#define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base + (BUF)->col_adjust)
+#define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base)
 #define CPP_BUF_COL(BUF) CPP_BUF_COLUMN(BUF, (BUF)->cur)
 
 /* Maximum nesting of cpp_buffers.  We use a static limit, partly for
@@ -84,7 +100,7 @@ struct cpp_macro
   } exp;
 
   /* Definition line number.  */
-  unsigned int line;
+  fileline line;
 
   /* Number of tokens in expansion, or bytes for traditional macros.  */
   unsigned int count;
@@ -117,39 +133,18 @@ struct _cpp_buff
   unsigned char *base, *cur, *limit;
 };
 
-extern _cpp_buff *_cpp_get_buff PARAMS ((cpp_reader *, size_t));
-extern void _cpp_release_buff PARAMS ((cpp_reader *, _cpp_buff *));
-extern void _cpp_extend_buff PARAMS ((cpp_reader *, _cpp_buff **, size_t));
-extern _cpp_buff *_cpp_append_extend_buff PARAMS ((cpp_reader *, _cpp_buff *,
-                                                  size_t));
-extern void _cpp_free_buff PARAMS ((_cpp_buff *));
-extern unsigned char *_cpp_aligned_alloc PARAMS ((cpp_reader *, size_t));
-extern unsigned char *_cpp_unaligned_alloc PARAMS ((cpp_reader *, size_t));
+extern _cpp_buff *_cpp_get_buff (cpp_reader *, size_t);
+extern void _cpp_release_buff (cpp_reader *, _cpp_buff *);
+extern void _cpp_extend_buff (cpp_reader *, _cpp_buff **, size_t);
+extern _cpp_buff *_cpp_append_extend_buff (cpp_reader *, _cpp_buff *, size_t);
+extern void _cpp_free_buff (_cpp_buff *);
+extern unsigned char *_cpp_aligned_alloc (cpp_reader *, size_t);
+extern unsigned char *_cpp_unaligned_alloc (cpp_reader *, size_t);
 
 #define BUFF_ROOM(BUFF) (size_t) ((BUFF)->limit - (BUFF)->cur)
 #define BUFF_FRONT(BUFF) ((BUFF)->cur)
 #define BUFF_LIMIT(BUFF) ((BUFF)->limit)
 
-/* List of directories to look for include files in.  */
-struct search_path
-{
-  struct search_path *next;
-
-  /* NOTE: NAME may not be null terminated for the case of the current
-     file's directory!  */
-  const char *name;
-  unsigned int len;
-  /* We use these to tell if the directory mentioned here is a duplicate
-     of an earlier directory on the search path.  */
-  ino_t ino;
-  dev_t dev;
-  /* Nonzero if it is a system include directory.  */
-  int sysp;
-  /* Mapping of file names for this directory.  Only used on MS-DOS
-     and related platforms.  */
-  struct file_name_map *name_map;
-};
-
 /* #include types.  */
 enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE};
 
@@ -232,9 +227,6 @@ struct lexer_state
      all directives apart from #define.  */
   unsigned char save_comments;
 
-  /* Nonzero if we're mid-comment.  */
-  unsigned char lexing_comment;
-
   /* Nonzero if lexing __VA_ARGS__ is valid.  */
   unsigned char va_args_ok;
 
@@ -262,47 +254,45 @@ struct spec_nodes
   cpp_hashnode *n__asm;                /* _asm ... _endasm ; */
 };
 
-/* Encapsulates state used to convert a stream of tokens into a text
-   file.  */
-struct printer
+typedef struct _cpp_line_note _cpp_line_note;
+struct _cpp_line_note
 {
-  FILE *outf;                  /* Stream to write to.  */
-  const struct line_map *map;  /* Logical to physical line mappings.  */
-  const cpp_token *prev;       /* Previous token.  */
-  const cpp_token *source;     /* Source token for spacing.  */
-  unsigned int line;           /* Line currently being written.  */
-  unsigned char printed;       /* Nonzero if something output at line.  */
+  /* Location in the clean line the note refers to.  */
+  const uchar *pos;
+
+  /* Type of note.  The 9 'from' trigraph characters represent those
+     trigraphs, '\\' an escaped newline, ' ' an escaped newline with
+     intervening space, and anything else is invalid.  */
+  unsigned int type;
 };
 
 /* Represents the contents of a file cpplib has read in.  */
 struct cpp_buffer
 {
-  const unsigned char *cur;     /* current position */
-  const unsigned char *backup_to; /* if peeked character is not wanted */
-  const unsigned char *rlimit; /* end of valid data */
-  const unsigned char *line_base; /* start of current line */
+  const uchar *cur;            /* Current location.  */
+  const uchar *line_base;      /* Start of current physical line.  */
+  const uchar *next_line;      /* Start of to-be-cleaned logical line.  */
 
-  struct cpp_buffer *prev;
+  const uchar *buf;            /* Entire character buffer.  */
+  const uchar *rlimit;         /* Writable byte at end of file.  */
+
+  _cpp_line_note *notes;       /* Array of notes.  */
+  unsigned int cur_note;       /* Next note to process.  */
+  unsigned int notes_used;     /* Number of notes.  */
+  unsigned int notes_cap;      /* Size of allocated array.  */
 
-  const unsigned char *buf;     /* Entire character buffer.  */
+  struct cpp_buffer *prev;
 
-  /* Pointer into the include table; non-NULL if this is a file
-     buffer.  Used for include_next and to record control macros.  */
-  struct include_file *inc;
+  /* Pointer into the file table; non-NULL if this is a file buffer.
+     Used for include_next and to record control macros.  */
+  struct _cpp_file *file;
 
   /* Value of if_stack at start of this file.
      Used to prohibit unmatched #endif (etc) in an include file.  */
   struct if_stack *if_stack;
 
-  /* Token column position adjustment owing to tabs in whitespace.  */
-  unsigned int col_adjust;
-
-  /* Contains PREV_WHITE and/or AVOID_LPASTE.  */
-  unsigned char saved_flags;
-
-  /* Because of the way the lexer works, -Wtrigraphs can sometimes
-     warn twice for the same trigraph.  This helps prevent that.  */
-  const unsigned char *last_Wtrigraphs;
+  /* True if we need to get the next clean line.  */
+  bool need_line;
 
   /* True if we have already warned about C++ comments in this file.
      The warning happens only for C89 extended mode with -pedantic on,
@@ -315,18 +305,14 @@ struct cpp_buffer
      buffers.  */
   unsigned char from_stage3;
 
-  /* Nonzero means that the directory to start searching for ""
-     include files has been calculated and stored in "dir" below.  */
-  unsigned char search_cached;
-
   /* At EOF, a buffer is automatically popped.  If RETURN_AT_EOF is
      true, a CPP_EOF token is then returned.  Otherwise, the next
      token from the enclosing buffer is returned.  */
-  bool return_at_eof;
+  unsigned int return_at_eof : 1;
 
   /* The directory of the this buffer's file.  Its NAME member is not
      allocated, so we don't need to worry about freeing it.  */
-  struct search_path dir;
+  struct cpp_dir dir;
 
   /* Used for buffer overlays by cpptrad.c.  */
   const uchar *saved_cur, *saved_rlimit;
@@ -349,10 +335,10 @@ struct cpp_reader
   /* Source line tracking.  */
   struct line_maps line_maps;
   const struct line_map *map;
-  unsigned int line;
+  fileline line;
 
   /* The line of the '#' of the current directive.  */
-  unsigned int directive_line;
+  fileline directive_line;
 
   /* Memory buffers.  */
   _cpp_buff *a_buff;           /* Aligned permanent storage.  */
@@ -366,12 +352,31 @@ struct cpp_reader
   /* If in_directive, the directive if known.  */
   const struct directive *directive;
 
-  /* The next -include-d file; NULL if they all are done.  If it
-     points to NULL, the last one is in progress, and
-     _cpp_maybe_push_include_file has yet to restore the line map.  */
-  struct pending_option **next_include_file;
+  /* Search paths for include files.  */
+  struct cpp_dir *quote_include;       /* "" */
+  struct cpp_dir *bracket_include;     /* <> */
+  struct cpp_dir no_search_path;       /* No path.  */
+
+  /* Chain of all hashed _cpp_file instances.  */
+  struct _cpp_file *all_files;
+
+  struct _cpp_file *main_file;
+
+  /* File and directory hash table.  */
+  struct htab *file_hash;
+  struct htab *dir_hash;
+  struct file_hash_entry *file_hash_entries;
+  unsigned int file_hash_entries_allocated, file_hash_entries_used;
+
+  /* Nonzero means don't look for #include "foo" the source-file
+     directory.  */
+  bool quote_ignores_source_dir;
 
-  /* Multiple inlcude optimisation.  */
+  /* Nonzero if any file has contained #pragma once or #import has
+     been used.  */
+  bool seen_once_only;
+
+  /* Multiple include optimization.  */
   const cpp_hashnode *mi_cmacro;
   const cpp_hashnode *mi_ind_cmacro;
   bool mi_valid;
@@ -391,15 +396,13 @@ struct cpp_reader
   unsigned char *macro_buffer;
   unsigned int macro_buffer_len;
 
-  /* Tree of other included files.  See cppfiles.c.  */
-  struct splay_tree_s *all_include_files;
-
-  /* Current maximum length of directory names in the search path
-     for include files.  (Altered as we get more of them.)  */
-  unsigned int max_include_len;
+  /* Descriptor for converting from the source character set to the
+     execution character set.  */
+  struct cset_converter narrow_cset_desc;
 
-  /* Macros on or after this line are warned about if unused.  */
-  unsigned int first_unused_line;
+  /* Descriptor for converting from the source character set to the
+     wide execution character set.  */
+  struct cset_converter wide_cset_desc;
 
   /* Date and time text.  Calculated together if either is requested.  */
   const uchar *date;
@@ -424,7 +427,7 @@ struct cpp_reader
      list of recognized pragmas.  */
   struct pragma_entry *pragmas;
 
-  /* Call backs.  */
+  /* Call backs to cpplib client.  */
   struct cpp_callbacks cb;
 
   /* Identifier hash table.  */
@@ -440,15 +443,8 @@ struct cpp_reader
      preprocessor.  */
   struct spec_nodes spec_nodes;
 
-  /* Used when doing preprocessed output.  */
-  struct printer print;
-
-  /* Whether to print our version number.  Done this way so
-     we don't get it twice for -v -version.  */
-  unsigned char print_version;
-
   /* Whether cpplib owns the hashtable.  */
-  unsigned char our_hashtable;
+  bool our_hashtable;
 
   /* Traditional preprocessing output buffer (a logical line).  */
   struct
@@ -456,12 +452,16 @@ struct cpp_reader
     uchar *base;
     uchar *limit;
     uchar *cur;
-    unsigned int first_line;
+    fileline first_line;
   } out;
 
   /* Used to save the original line number during traditional
      preprocessing.  */
   unsigned int saved_line;
+
+  /* A saved list of the defined macros, for dependency checking
+     of precompiled headers.  */
+  struct cpp_savedstate *savedstate;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -498,81 +498,92 @@ extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
 #define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, warn_traditional)
 
 /* In cpperror.c  */
-extern int _cpp_begin_message PARAMS ((cpp_reader *, int,
-                                      unsigned int, unsigned int));
+extern int _cpp_begin_message (cpp_reader *, int, fileline, unsigned int);
 
 /* In cppmacro.c */
-extern void _cpp_free_definition       PARAMS ((cpp_hashnode *));
-extern bool _cpp_create_definition     PARAMS ((cpp_reader *, cpp_hashnode *));
-extern void _cpp_pop_context           PARAMS ((cpp_reader *));
-extern void _cpp_push_text_context     PARAMS ((cpp_reader *, cpp_hashnode *,
-                                                const uchar *, size_t));
-extern bool _cpp_save_parameter                PARAMS ((cpp_reader *, cpp_macro *,
-                                                cpp_hashnode *));
-extern bool _cpp_arguments_ok          PARAMS ((cpp_reader *, cpp_macro *,
-                                                const cpp_hashnode *,
-                                                unsigned int));
-extern const uchar *_cpp_builtin_macro_text PARAMS ((cpp_reader *,
-                                                    cpp_hashnode *));
-int _cpp_warn_if_unused_macro          PARAMS ((cpp_reader *, cpp_hashnode *,
-                                                void *));
+extern void _cpp_free_definition (cpp_hashnode *);
+extern bool _cpp_create_definition (cpp_reader *, cpp_hashnode *);
+extern void _cpp_pop_context (cpp_reader *);
+extern void _cpp_push_text_context (cpp_reader *, cpp_hashnode *,
+                                   const uchar *, size_t);
+extern bool _cpp_save_parameter (cpp_reader *, cpp_macro *, cpp_hashnode *);
+extern bool _cpp_arguments_ok (cpp_reader *, cpp_macro *, const cpp_hashnode *,
+                              unsigned int);
+extern const uchar *_cpp_builtin_macro_text (cpp_reader *, cpp_hashnode *);
+int _cpp_warn_if_unused_macro (cpp_reader *, cpp_hashnode *, void *);
 /* In cpphash.c */
-extern void _cpp_init_hashtable                PARAMS ((cpp_reader *, hash_table *));
-extern void _cpp_destroy_hashtable     PARAMS ((cpp_reader *));
+extern void _cpp_init_hashtable (cpp_reader *, hash_table *);
+extern void _cpp_destroy_hashtable (cpp_reader *);
 
 /* In cppfiles.c */
-extern void _cpp_fake_include          PARAMS ((cpp_reader *, const char *));
-extern void _cpp_never_reread          PARAMS ((struct include_file *));
-extern char *_cpp_simplify_pathname    PARAMS ((char *));
-extern bool _cpp_read_file             PARAMS ((cpp_reader *, const char *));
-extern bool _cpp_execute_include       PARAMS ((cpp_reader *,
-                                                const cpp_token *,
-                                                enum include_type));
-extern int _cpp_compare_file_date       PARAMS ((cpp_reader *,
-                                                const cpp_token *));
-extern void _cpp_report_missing_guards PARAMS ((cpp_reader *));
-extern void _cpp_init_includes         PARAMS ((cpp_reader *));
-extern void _cpp_cleanup_includes      PARAMS ((cpp_reader *));
-extern void _cpp_pop_file_buffer       PARAMS ((cpp_reader *,
-                                                struct include_file *));
+typedef struct _cpp_file _cpp_file;
+extern _cpp_file *_cpp_find_file (cpp_reader *, const char *fname,
+                                 cpp_dir *start_dir, bool fake, int);
+extern bool _cpp_find_failed (_cpp_file *);
+extern void _cpp_mark_file_once_only (cpp_reader *, struct _cpp_file *);
+extern void _cpp_fake_include (cpp_reader *, const char *);
+extern bool _cpp_stack_file (cpp_reader *, _cpp_file*, bool);
+extern bool _cpp_stack_include (cpp_reader *, const char *, int,
+                               enum include_type);
+extern int _cpp_compare_file_date (cpp_reader *, const char *, int);
+extern void _cpp_report_missing_guards (cpp_reader *);
+extern void _cpp_init_files (cpp_reader *);
+extern void _cpp_cleanup_files (cpp_reader *);
+extern void _cpp_pop_file_buffer (cpp_reader *, struct _cpp_file *);
 
 /* In cppexp.c */
-extern bool _cpp_parse_expr            PARAMS ((cpp_reader *));
-extern struct op *_cpp_expand_op_stack PARAMS ((cpp_reader *));
+extern bool _cpp_parse_expr (cpp_reader *);
+extern struct op *_cpp_expand_op_stack (cpp_reader *);
 
 /* In cpplex.c */
-extern cpp_token *_cpp_temp_token      PARAMS ((cpp_reader *));
-extern const cpp_token *_cpp_lex_token PARAMS ((cpp_reader *));
-extern cpp_token *_cpp_lex_direct      PARAMS ((cpp_reader *));
-extern int _cpp_equiv_tokens           PARAMS ((const cpp_token *,
-                                                const cpp_token *));
-extern void _cpp_init_tokenrun         PARAMS ((tokenrun *, unsigned int));
+extern void _cpp_process_line_notes (cpp_reader *, int);
+extern void _cpp_clean_line (cpp_reader *);
+extern bool _cpp_get_fresh_line (cpp_reader *);
+extern bool _cpp_skip_block_comment (cpp_reader *);
+extern cpp_token *_cpp_temp_token (cpp_reader *);
+extern const cpp_token *_cpp_lex_token (cpp_reader *);
+extern cpp_token *_cpp_lex_direct (cpp_reader *);
+extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
+extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
 
 /* In cppinit.c.  */
-extern void _cpp_maybe_push_include_file PARAMS ((cpp_reader *));
+extern void _cpp_maybe_push_include_file (cpp_reader *);
 
 /* In cpplib.c */
-extern int _cpp_test_assertion PARAMS ((cpp_reader *, unsigned int *));
-extern int _cpp_handle_directive PARAMS ((cpp_reader *, int));
-extern void _cpp_define_builtin        PARAMS ((cpp_reader *, const char *));
-extern void _cpp_do__Pragma    PARAMS ((cpp_reader *));
-extern void _cpp_init_directives PARAMS ((cpp_reader *));
-extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *));
-extern void _cpp_do_file_change PARAMS ((cpp_reader *, enum lc_reason,
-                                        const char *,
-                                        unsigned int, unsigned int));
-extern void _cpp_pop_buffer PARAMS ((cpp_reader *));
+extern int _cpp_test_assertion (cpp_reader *, unsigned int *);
+extern int _cpp_handle_directive (cpp_reader *, int);
+extern void _cpp_define_builtin (cpp_reader *, const char *);
+extern char ** _cpp_save_pragma_names (cpp_reader *);
+extern void _cpp_restore_pragma_names (cpp_reader *, char **);
+extern void _cpp_do__Pragma (cpp_reader *);
+extern void _cpp_init_directives (cpp_reader *);
+extern void _cpp_init_internal_pragmas (cpp_reader *);
+extern void _cpp_do_file_change (cpp_reader *, enum lc_reason, const char *,
+                                unsigned int, unsigned int);
+extern void _cpp_pop_buffer (cpp_reader *);
 
 /* In cpptrad.c.  */
-extern bool _cpp_read_logical_line_trad PARAMS ((cpp_reader *));
-extern void _cpp_overlay_buffer PARAMS ((cpp_reader *pfile, const uchar *,
-                                        size_t));
-extern void _cpp_remove_overlay PARAMS ((cpp_reader *));
-extern bool _cpp_create_trad_definition PARAMS ((cpp_reader *, cpp_macro *));
-extern bool _cpp_expansions_different_trad PARAMS ((const cpp_macro *,
-                                                   const cpp_macro *));
-extern uchar *_cpp_copy_replacement_text PARAMS ((const cpp_macro *, uchar *));
-extern size_t _cpp_replacement_text_len PARAMS ((const cpp_macro *));
+extern bool _cpp_scan_out_logical_line (cpp_reader *, cpp_macro *);
+extern bool _cpp_read_logical_line_trad (cpp_reader *);
+extern void _cpp_overlay_buffer (cpp_reader *pfile, const uchar *, size_t);
+extern void _cpp_remove_overlay (cpp_reader *);
+extern bool _cpp_create_trad_definition (cpp_reader *, cpp_macro *);
+extern bool _cpp_expansions_different_trad (const cpp_macro *,
+                                           const cpp_macro *);
+extern uchar *_cpp_copy_replacement_text (const cpp_macro *, uchar *);
+extern size_t _cpp_replacement_text_len (const cpp_macro *);
+
+/* In cppcharset.c.  */
+extern cppchar_t _cpp_valid_ucn (cpp_reader *, const uchar **,
+                                const uchar *, int);
+extern void _cpp_destroy_iconv (cpp_reader *);
+extern bool _cpp_interpret_string_notranslate (cpp_reader *,
+                                              const cpp_string *,
+                                              cpp_string *);
+extern uchar *_cpp_convert_input (cpp_reader *, const char *, uchar *,
+                                  size_t, size_t, off_t *);
+extern const char *_cpp_default_encoding (void);
+
 
 /* Utility routines and macros.  */
 #define DSC(str) (const uchar *)str, sizeof str - 1
@@ -584,55 +595,45 @@ extern size_t _cpp_replacement_text_len PARAMS ((const cpp_macro *));
 
 /* These are inline functions instead of macros so we can get type
    checking.  */
-static inline int ustrcmp      PARAMS ((const uchar *, const uchar *));
-static inline int ustrncmp     PARAMS ((const uchar *, const uchar *,
-                                        size_t));
-static inline size_t ustrlen   PARAMS ((const uchar *));
-static inline uchar *uxstrdup  PARAMS ((const uchar *));
-static inline uchar *ustrchr   PARAMS ((const uchar *, int));
-static inline int ufputs       PARAMS ((const uchar *, FILE *));
+static inline int ustrcmp (const uchar *, const uchar *);
+static inline int ustrncmp (const uchar *, const uchar *, size_t);
+static inline size_t ustrlen (const uchar *);
+static inline uchar *uxstrdup (const uchar *);
+static inline uchar *ustrchr (const uchar *, int);
+static inline int ufputs (const uchar *, FILE *);
 
 static inline int
-ustrcmp (s1, s2)
-     const uchar *s1, *s2;
+ustrcmp (const uchar *s1, const uchar *s2)
 {
   return strcmp ((const char *)s1, (const char *)s2);
 }
 
 static inline int
-ustrncmp (s1, s2, n)
-     const uchar *s1, *s2;
-     size_t n;
+ustrncmp (const uchar *s1, const uchar *s2, size_t n)
 {
   return strncmp ((const char *)s1, (const char *)s2, n);
 }
 
 static inline size_t
-ustrlen (s1)
-     const uchar *s1;
+ustrlen (const uchar *s1)
 {
   return strlen ((const char *)s1);
 }
 
 static inline uchar *
-uxstrdup (s1)
-     const uchar *s1;
+uxstrdup (const uchar *s1)
 {
   return (uchar *) xstrdup ((const char *)s1);
 }
 
 static inline uchar *
-ustrchr (s1, c)
-     const uchar *s1;
-     int c;
+ustrchr (const uchar *s1, int c)
 {
   return (uchar *) strchr ((const char *)s1, c);
 }
 
 static inline int
-ufputs (s, f)
-     const uchar *s;
-     FILE *f;
+ufputs (const uchar *s, FILE *f)
 {
   return fputs ((const char *)s, f);
 }
index 14f64d8f7d05856f6176f8f9437eb6ba6e5bd09d..fab2da2baaa9092a0359c12c7da4af2f9e883675 100644 (file)
@@ -1,6 +1,6 @@
 /* CPP Library.
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -23,99 +23,13 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "system.h"
 #include "cpplib.h"
 #include "cpphash.h"
-#include "prefix.h"
-#include "intl.h"
 #include "mkdeps.h"
-#include "cppdefault.h"
-
-/* Windows does not natively support inodes, and neither does MSDOS.
-   Cygwin's emulation can generate non-unique inodes, so don't use it.
-   VMS has non-numeric inodes.  */
-#ifdef VMS
-# define INO_T_EQ(A, B) (!memcmp (&(A), &(B), sizeof (A)))
-# define INO_T_COPY(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof (SRC))
-#else
-# if (defined _WIN32 && ! defined (_UWIN)) || defined __MSDOS__
-#  define INO_T_EQ(A, B) 0
-# else
-#  define INO_T_EQ(A, B) ((A) == (B))
-# endif
-# define INO_T_COPY(DEST, SRC) (DEST) = (SRC)
-#endif
-
-/* Internal structures and prototypes.  */
-
-/* A `struct pending_option' remembers one -D, -A, -U, -include, or
-   -imacros switch.  */
-typedef void (* cl_directive_handler) PARAMS ((cpp_reader *, const char *));
-struct pending_option
-{
-  struct pending_option *next;
-  const char *arg;
-  cl_directive_handler handler;
-};
-
-/* The `pending' structure accumulates all the options that are not
-   actually processed until we hit cpp_read_main_file.  It consists of
-   several lists, one for each type of option.  We keep both head and
-   tail pointers for quick insertion.  */
-struct cpp_pending
-{
-  struct pending_option *directive_head, *directive_tail;
 
-  struct search_path *quote_head, *quote_tail;
-  struct search_path *brack_head, *brack_tail;
-  struct search_path *systm_head, *systm_tail;
-  struct search_path *after_head, *after_tail;
-
-  struct pending_option *imacros_head, *imacros_tail;
-  struct pending_option *include_head, *include_tail;
-};
-
-#ifdef __STDC__
-#define APPEND(pend, list, elt) \
-  do {  if (!(pend)->list##_head) (pend)->list##_head = (elt); \
-       else (pend)->list##_tail->next = (elt); \
-       (pend)->list##_tail = (elt); \
-  } while (0)
-#else
-#define APPEND(pend, list, elt) \
-  do {  if (!(pend)->list/**/_head) (pend)->list/**/_head = (elt); \
-       else (pend)->list/**/_tail->next = (elt); \
-       (pend)->list/**/_tail = (elt); \
-  } while (0)
-#endif
-
-static void path_include               PARAMS ((cpp_reader *,
-                                                char *, int));
-static void init_library               PARAMS ((void));
-static void init_builtins              PARAMS ((cpp_reader *));
-static void mark_named_operators       PARAMS ((cpp_reader *));
-static void append_include_chain       PARAMS ((cpp_reader *,
-                                                char *, int, int));
-static struct search_path * remove_dup_dir     PARAMS ((cpp_reader *,
-                                                struct search_path *,
-                                                struct search_path **));
-static struct search_path * remove_dup_nonsys_dirs PARAMS ((cpp_reader *,
-                                                struct search_path **,
-                                                struct search_path *));
-static struct search_path * remove_dup_dirs PARAMS ((cpp_reader *,
-                                                struct search_path **));
-static void merge_include_chains       PARAMS ((cpp_reader *));
-static bool push_include               PARAMS ((cpp_reader *,
-                                                struct pending_option *));
-static void free_chain                 PARAMS ((struct pending_option *));
-static void init_standard_includes     PARAMS ((cpp_reader *));
-static void read_original_filename     PARAMS ((cpp_reader *));
-static void new_pending_directive      PARAMS ((struct cpp_pending *,
-                                                const char *,
-                                                cl_directive_handler));
-static int parse_option                        PARAMS ((const char *));
-static void post_options               PARAMS ((cpp_reader *));
-
-/* Fourth argument to append_include_chain: chain to use.
-   Note it's never asked to append to the quote chain.  */
-enum { BRACKET = 0, SYSTEM, AFTER };
+static void init_library (void);
+static void mark_named_operators (cpp_reader *);
+static void read_original_filename (cpp_reader *);
+static void read_original_directory (cpp_reader *);
+static void post_options (cpp_reader *);
 
 /* If we have designated initializers (GCC >2.7) these tables can be
    initialized, constant data.  Otherwise, they have to be filled in at
@@ -132,7 +46,7 @@ __extension__ const uchar _cpp_trigraph_map[UCHAR_MAX + 1] = {
 #else
 
 #define TRIGRAPH_MAP uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \
- static void init_trigraph_map PARAMS ((void)) { \
+ static void init_trigraph_map (void) { \
  unsigned char *x = _cpp_trigraph_map;
 
 #define END }
@@ -150,281 +64,6 @@ END
 #undef END
 #undef TRIGRAPH_MAP
 
-/* Given a colon-separated list of file names PATH,
-   add all the names to the search path for include files.  */
-static void
-path_include (pfile, list, path)
-     cpp_reader *pfile;
-     char *list;
-     int path;
-{
-  char *p, *q, *name;
-
-  p = list;
-
-  do
-    {
-      /* Find the end of this name.  */
-      q = p;
-      while (*q != 0 && *q != PATH_SEPARATOR) q++;
-      if (q == p)
-       {
-         /* An empty name in the path stands for the current directory.  */
-         name = (char *) xmalloc (2);
-         name[0] = '.';
-         name[1] = 0;
-       }
-      else
-       {
-         /* Otherwise use the directory that is named.  */
-         name = (char *) xmalloc (q - p + 1);
-         memcpy (name, p, q - p);
-         name[q - p] = 0;
-       }
-
-      append_include_chain (pfile, name, path, path == SYSTEM);
-
-      /* Advance past this name.  */
-      if (*q == 0)
-       break;
-      p = q + 1;
-    }
-  while (1);
-}
-
-/* Append DIR to include path PATH.  DIR must be allocated on the
-   heap; this routine takes responsibility for freeing it.  CXX_AWARE
-   is nonzero if the header contains extern "C" guards for C++,
-   otherwise it is zero.  */
-static void
-append_include_chain (pfile, dir, path, cxx_aware)
-     cpp_reader *pfile;
-     char *dir;
-     int path;
-     int cxx_aware;
-{
-  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
-  struct search_path *new;
-  struct stat st;
-  unsigned int len;
-
-  if (*dir == '\0')
-    {
-      free (dir);
-      dir = xstrdup (".");
-    }
-  _cpp_simplify_pathname (dir);
-
-  if (stat (dir, &st))
-    {
-      /* Dirs that don't exist are silently ignored.  */
-      if (errno != ENOENT)
-       cpp_errno (pfile, DL_ERROR, dir);
-      else if (CPP_OPTION (pfile, verbose))
-       fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir);
-      free (dir);
-      return;
-    }
-
-  if (!S_ISDIR (st.st_mode))
-    {
-      cpp_error_with_line (pfile, DL_ERROR, 0, 0, "%s: Not a directory", dir);
-      free (dir);
-      return;
-    }
-
-  len = strlen (dir);
-  if (len > pfile->max_include_len)
-    pfile->max_include_len = len;
-
-  new = (struct search_path *) xmalloc (sizeof (struct search_path));
-  new->name = dir;
-  new->len = len;
-  INO_T_COPY (new->ino, st.st_ino);
-  new->dev  = st.st_dev;
-  /* Both systm and after include file lists should be treated as system
-     include files since these two lists are really just a concatenation
-     of one "system" list.  */
-  if (path == SYSTEM || path == AFTER)
-    new->sysp = cxx_aware ? 1 : 2;
-  else
-    new->sysp = 0;
-  new->name_map = NULL;
-  new->next = NULL;
-
-  switch (path)
-    {
-    case BRACKET:      APPEND (pend, brack, new); break;
-    case SYSTEM:       APPEND (pend, systm, new); break;
-    case AFTER:                APPEND (pend, after, new); break;
-    }
-}
-
-/* Handle a duplicated include path.  PREV is the link in the chain
-   before the duplicate, or NULL if the duplicate is at the head of
-   the chain.  The duplicate is removed from the chain and freed.
-   Returns PREV.  */
-static struct search_path *
-remove_dup_dir (pfile, prev, head_ptr)
-     cpp_reader *pfile;
-     struct search_path *prev;
-     struct search_path **head_ptr;
-{
-  struct search_path *cur;
-
-  if (prev != NULL)
-    {
-      cur = prev->next;
-      prev->next = cur->next;
-    }
-  else
-    {
-      cur = *head_ptr;
-      *head_ptr = cur->next;
-    }
-
-  if (CPP_OPTION (pfile, verbose))
-    fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), cur->name);
-
-  free ((PTR) cur->name);
-  free (cur);
-
-  return prev;
-}
-
-/* Remove duplicate non-system directories for which there is an equivalent
-   system directory latter in the chain.  The range for removal is between
-   *HEAD_PTR and END.  Returns the directory before END, or NULL if none.
-   This algorithm is quadratic in the number system directories, which is
-   acceptable since there aren't usually that many of them.  */
-static struct search_path *
-remove_dup_nonsys_dirs (pfile, head_ptr, end)
-     cpp_reader *pfile;
-     struct search_path **head_ptr;
-     struct search_path *end;
-{
-  int sysdir = 0;
-  struct search_path *prev = NULL, *cur, *other;
-
-  for (cur = *head_ptr; cur; cur = cur->next)
-    {
-      if (cur->sysp)
-       {
-         sysdir = 1;
-         for (other = *head_ptr, prev = NULL;
-              other != end;
-              other = other ? other->next : *head_ptr)
-           {
-             if (!other->sysp
-                 && INO_T_EQ (cur->ino, other->ino)
-                 && cur->dev == other->dev)
-               {
-                 other = remove_dup_dir (pfile, prev, head_ptr);
-                 if (CPP_OPTION (pfile, verbose))
-                   fprintf (stderr,
-  _("  as it is a non-system directory that duplicates a system directory\n"));
-               }
-             prev = other;
-           }
-       }
-    }
-
-  if (!sysdir)
-    for (cur = *head_ptr; cur != end; cur = cur->next)
-      prev = cur;
-
-  return prev;
-}
-
-/* Remove duplicate directories from a chain.  Returns the tail of the
-   chain, or NULL if the chain is empty.  This algorithm is quadratic
-   in the number of -I switches, which is acceptable since there
-   aren't usually that many of them.  */
-static struct search_path *
-remove_dup_dirs (pfile, head_ptr)
-     cpp_reader *pfile;
-     struct search_path **head_ptr;
-{
-  struct search_path *prev = NULL, *cur, *other;
-
-  for (cur = *head_ptr; cur; cur = cur->next)
-    {
-      for (other = *head_ptr; other != cur; other = other->next)
-       if (INO_T_EQ (cur->ino, other->ino) && cur->dev == other->dev)
-         {
-           cur = remove_dup_dir (pfile, prev, head_ptr);
-           break;
-         }
-      prev = cur;
-    }
-
-  return prev;
-}
-
-/* Merge the four include chains together in the order quote, bracket,
-   system, after.  Remove duplicate dirs (as determined by
-   INO_T_EQ()).  The system_include and after_include chains are never
-   referred to again after this function; all access is through the
-   bracket_include path.  */
-static void
-merge_include_chains (pfile)
-     cpp_reader *pfile;
-{
-  struct search_path *quote, *brack, *systm, *qtail;
-
-  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
-
-  quote = pend->quote_head;
-  brack = pend->brack_head;
-  systm = pend->systm_head;
-  qtail = pend->quote_tail;
-
-  /* Paste together bracket, system, and after include chains.  */
-  if (systm)
-    pend->systm_tail->next = pend->after_head;
-  else
-    systm = pend->after_head;
-
-  if (brack)
-    pend->brack_tail->next = systm;
-  else
-    brack = systm;
-
-  /* This is a bit tricky.  First we drop non-system dupes of system
-     directories from the merged bracket-include list.  Next we drop
-     dupes from the bracket and quote include lists.  Then we drop
-     non-system dupes from the merged quote-include list.  Finally,
-     if qtail and brack are the same directory, we cut out brack and
-     move brack up to point to qtail.
-
-     We can't just merge the lists and then uniquify them because
-     then we may lose directories from the <> search path that should
-     be there; consider -Ifoo -Ibar -I- -Ifoo -Iquux.  It is however
-     safe to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written
-     -Ibar -I- -Ifoo -Iquux.  */
-
-  remove_dup_nonsys_dirs (pfile, &brack, systm);
-  remove_dup_dirs (pfile, &brack);
-
-  if (quote)
-    {
-      qtail = remove_dup_dirs (pfile, &quote);
-      qtail->next = brack;
-
-      qtail = remove_dup_nonsys_dirs (pfile, &quote, brack);
-
-      /* If brack == qtail, remove brack as it's simpler.  */
-      if (qtail && brack && INO_T_EQ (qtail->ino, brack->ino)
-         && qtail->dev == brack->dev)
-       brack = remove_dup_dir (pfile, qtail, &quote);
-    }
-  else
-    quote = brack;
-
-  CPP_OPTION (pfile, quote_include) = quote;
-  CPP_OPTION (pfile, bracket_include) = brack;
-}
-
 /* A set of booleans indicating what CPP features each source language
    requires.  */
 struct lang_flags
@@ -433,29 +72,25 @@ struct lang_flags
   char cplusplus;
   char extended_numbers;
   char std;
-  char dollars_in_ident;
   char cplusplus_comments;
   char digraphs;
 };
 
-/* ??? Enable $ in identifiers in assembly? */
 static const struct lang_flags lang_defaults[] =
-{ /*              c99 c++ xnum std dollar c++comm digr  */
-  /* GNUC89 */  { 0,  0,  1,   0,   1,     1,      1     },
-  /* GNUC99 */  { 1,  0,  1,   0,   1,     1,      1     },
-  /* STDC89 */  { 0,  0,  0,   1,   0,     0,      0     },
-  /* STDC94 */  { 0,  0,  0,   1,   0,     0,      1     },
-  /* STDC99 */  { 1,  0,  1,   1,   0,     1,      1     },
-  /* GNUCXX */  { 0,  1,  1,   0,   1,     1,      1     },
-  /* CXX98  */  { 0,  1,  1,   1,   0,     1,      1     },
-  /* ASM    */  { 0,  0,  1,   0,   0,     1,      0     }
+{ /*              c99 c++ xnum std  //   digr  */
+  /* GNUC89 */  { 0,  0,  1,   0,   1,   1     },
+  /* GNUC99 */  { 1,  0,  1,   0,   1,   1     },
+  /* STDC89 */  { 0,  0,  0,   1,   0,   0     },
+  /* STDC94 */  { 0,  0,  0,   1,   0,   1     },
+  /* STDC99 */  { 1,  0,  1,   1,   1,   1     },
+  /* GNUCXX */  { 0,  1,  1,   0,   1,   1     },
+  /* CXX98  */  { 0,  1,  1,   1,   1,   1     },
+  /* ASM    */  { 0,  0,  1,   0,   1,   0     }
 };
 
 /* Sets internal flags correctly for a given language.  */
 void
-cpp_set_lang (pfile, lang)
-     cpp_reader *pfile;
-     enum c_lang lang;
+cpp_set_lang (cpp_reader *pfile, enum c_lang lang)
 {
   const struct lang_flags *l = &lang_defaults[(int) lang];
 
@@ -466,28 +101,13 @@ cpp_set_lang (pfile, lang)
   CPP_OPTION (pfile, extended_numbers)  = l->extended_numbers;
   CPP_OPTION (pfile, std)               = l->std;
   CPP_OPTION (pfile, trigraphs)                 = l->std;
-  CPP_OPTION (pfile, dollars_in_ident)  = l->dollars_in_ident;
   CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments;
   CPP_OPTION (pfile, digraphs)          = l->digraphs;
 }
 
-#ifdef HOST_EBCDIC
-static int opt_comp PARAMS ((const void *, const void *));
-
-/* Run-time sorting of options array.  */
-static int
-opt_comp (p1, p2)
-     const void *p1, *p2;
-{
-  return strcmp (((struct cl_option *) p1)->opt_text,
-                ((struct cl_option *) p2)->opt_text);
-}
-#endif
-
-/* init initializes library global state.  It might not need to
-   do anything depending on the platform and compiler.  */
+/* Initialize library global state.  */
 static void
-init_library ()
+init_library (void)
 {
   static int initialized = 0;
 
@@ -495,12 +115,6 @@ init_library ()
     {
       initialized = 1;
 
-#ifdef HOST_EBCDIC
-      /* For non-ASCII hosts, the cl_options array needs to be sorted at
-        runtime.  */
-      qsort (cl_options, N_OPTS, sizeof (struct cl_option), opt_comp);
-#endif
-
       /* Set up the trigraph map.  This doesn't need to do anything if
         we were compiled with a compiler that supports C99 designated
         initializers.  */
@@ -510,32 +124,28 @@ init_library ()
 
 /* Initialize a cpp_reader structure.  */
 cpp_reader *
-cpp_create_reader (lang)
-     enum c_lang lang;
+cpp_create_reader (enum c_lang lang, hash_table *table)
 {
   cpp_reader *pfile;
 
   /* Initialize this instance of the library if it hasn't been already.  */
   init_library ();
 
-  pfile = (cpp_reader *) xcalloc (1, sizeof (cpp_reader));
+  pfile = xcalloc (1, sizeof (cpp_reader));
 
   cpp_set_lang (pfile, lang);
-  CPP_OPTION (pfile, warn_import) = 1;
   CPP_OPTION (pfile, warn_multichar) = 1;
   CPP_OPTION (pfile, discard_comments) = 1;
   CPP_OPTION (pfile, discard_comments_in_macro_exp) = 1;
   CPP_OPTION (pfile, show_column) = 1;
   CPP_OPTION (pfile, tabstop) = 8;
   CPP_OPTION (pfile, operator_names) = 1;
+  CPP_OPTION (pfile, warn_trigraphs) = 2;
   CPP_OPTION (pfile, warn_endif_labels) = 1;
+  CPP_OPTION (pfile, warn_deprecated) = 1;
   CPP_OPTION (pfile, warn_long_long) = !CPP_OPTION (pfile, c99);
-  CPP_OPTION (pfile, sysroot) = cpp_SYSROOT;
-  /* SDCC _asm specific */
-  CPP_OPTION (pfile, preproc_asm) = 1;
-
-  CPP_OPTION (pfile, pending) =
-    (struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending));
+  CPP_OPTION (pfile, dollars_in_ident) = 1;
+  CPP_OPTION (pfile, warn_dollars) = 1;
 
   /* Default CPP arithmetic to something sensible for the host for the
      benefit of dumb users like fix-header.  */
@@ -545,10 +155,27 @@ cpp_create_reader (lang)
   CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int);
   CPP_OPTION (pfile, unsigned_char) = 0;
   CPP_OPTION (pfile, unsigned_wchar) = 1;
+  CPP_OPTION (pfile, bytes_big_endian) = 1;  /* does not matter */
+
+  /* Default to locale/UTF-8.  */
+  CPP_OPTION (pfile, narrow_charset) = _cpp_default_encoding ();
+  CPP_OPTION (pfile, wide_charset) = 0;
+  CPP_OPTION (pfile, input_charset) = _cpp_default_encoding ();
+
+  /* SDCC specific */
+  CPP_OPTION (pfile, preproc_asm) = 1;
+  CPP_OPTION (pfile, pedantic_parse_number) = 0;
+  CPP_OPTION (pfile, obj_ext) = NULL;
+
+  /* A fake empty "directory" used as the starting point for files
+     looked up without a search path.  Name cannot be '/' because we
+     don't want to prepend anything at all to filenames using it.  All
+     other entries are correct zero-initialized.  */
+  pfile->no_search_path.name = (char *) "";
 
   /* Initialize the line map.  Start at logical line 1, so we can use
      a line number of zero for special states.  */
-  init_line_maps (&pfile->line_maps);
+  linemap_init (&pfile->line_maps);
   pfile->line = 1;
 
   /* Initialize lexer state.  */
@@ -578,9 +205,13 @@ cpp_create_reader (lang)
   _cpp_expand_op_stack (pfile);
 
   /* Initialize the buffer obstack.  */
-  gcc_obstack_init (&pfile->buffer_ob);
+  _obstack_begin (&pfile->buffer_ob, 0, 0,
+                 (void *(*) (long)) xmalloc,
+                 (void (*) (void *)) free);
 
-  _cpp_init_includes (pfile);
+  _cpp_init_files (pfile);
+
+  _cpp_init_hashtable (pfile, table);
 
   return pfile;
 }
@@ -588,15 +219,11 @@ cpp_create_reader (lang)
 /* Free resources used by PFILE.  Accessing PFILE after this function
    returns leads to undefined behavior.  Returns the error count.  */
 void
-cpp_destroy (pfile)
-     cpp_reader *pfile;
+cpp_destroy (cpp_reader *pfile)
 {
-  struct search_path *dir, *dirn;
   cpp_context *context, *contextn;
   tokenrun *run, *runn;
 
-  free_chain (CPP_OPTION (pfile, pending)->include_head);
-  free (CPP_OPTION (pfile, pending));
   free (pfile->op_stack);
 
   while (CPP_BUFFER (pfile) != NULL)
@@ -607,7 +234,7 @@ cpp_destroy (pfile)
 
   if (pfile->macro_buffer)
     {
-      free ((PTR) pfile->macro_buffer);
+      free (pfile->macro_buffer);
       pfile->macro_buffer = NULL;
       pfile->macro_buffer_len = 0;
     }
@@ -617,7 +244,8 @@ cpp_destroy (pfile)
   obstack_free (&pfile->buffer_ob, 0);
 
   _cpp_destroy_hashtable (pfile);
-  _cpp_cleanup_includes (pfile);
+  _cpp_cleanup_files (pfile);
+  _cpp_destroy_iconv (pfile);
 
   _cpp_free_buff (pfile->a_buff);
   _cpp_free_buff (pfile->u_buff);
@@ -631,20 +259,13 @@ cpp_destroy (pfile)
        free (run);
     }
 
-  for (dir = CPP_OPTION (pfile, quote_include); dir; dir = dirn)
-    {
-      dirn = dir->next;
-      free ((PTR) dir->name);
-      free (dir);
-    }
-
   for (context = pfile->base_context.next; context; context = contextn)
     {
       contextn = context->next;
       free (context);
     }
 
-  free_line_maps (&pfile->line_maps);
+  linemap_free (&pfile->line_maps);
   free (pfile);
 }
 
@@ -702,8 +323,7 @@ static const struct builtin operator_array[] =
 
 /* Mark the C++ named operators in the hash table.  */
 static void
-mark_named_operators (pfile)
-     cpp_reader *pfile;
+mark_named_operators (cpp_reader *pfile)
 {
   const struct builtin *b;
 
@@ -713,15 +333,16 @@ mark_named_operators (pfile)
     {
       cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
       hp->flags |= NODE_OPERATOR;
-      hp->value.operator = b->value;
+      hp->is_directive = 0;
+      hp->directive_index = b->value;
     }
 }
 
-/* Subroutine of cpp_read_main_file; reads the builtins table above and
-   enters them, and language-specific macros, into the hash table.  */
-static void
-init_builtins (pfile)
-     cpp_reader *pfile;
+/* Read the builtins table above and enter them, and language-specific
+   macros, into the hash table.  HOSTED is true if this is a hosted
+   environment.  */
+void
+cpp_init_builtins (cpp_reader *pfile, int hosted)
 {
   const struct builtin *b;
   size_t n = ARRAY_SIZE (builtin_array);
@@ -746,166 +367,20 @@ init_builtins (pfile)
   else if (CPP_OPTION (pfile, c99))
     _cpp_define_builtin (pfile, "__STDC_VERSION__ 199901L");
 
-  if (CPP_OPTION (pfile, objc))
-    _cpp_define_builtin (pfile, "__OBJC__ 1");
-
-  if (pfile->cb.register_builtins)
-    (*pfile->cb.register_builtins) (pfile);
-}
-
-/* And another subroutine.  This one sets up the standard include path.  */
-static void
-init_standard_includes (pfile)
-     cpp_reader *pfile;
-{
-  char *path;
-  const struct default_include *p;
-  const char *specd_prefix = CPP_OPTION (pfile, include_prefix);
-  int default_len, specd_len;
-  char *default_prefix;
-
-  /* Several environment variables may add to the include search path.
-     CPATH specifies an additional list of directories to be searched
-     as if specified with -I, while C_INCLUDE_PATH, CPLUS_INCLUDE_PATH,
-     etc. specify an additional list of directories to be searched as
-     if specified with -isystem, for the language indicated.  */
-
-  GET_ENVIRONMENT (path, "CPATH");
-  if (path != 0 && *path != 0)
-    path_include (pfile, path, BRACKET);
-
-  switch ((CPP_OPTION (pfile, objc) << 1) + CPP_OPTION (pfile, cplusplus))
-    {
-    case 0:
-      GET_ENVIRONMENT (path, "C_INCLUDE_PATH");
-      break;
-    case 1:
-      GET_ENVIRONMENT (path, "CPLUS_INCLUDE_PATH");
-      break;
-    case 2:
-      GET_ENVIRONMENT (path, "OBJC_INCLUDE_PATH");
-      break;
-    case 3:
-      GET_ENVIRONMENT (path, "OBJCPLUS_INCLUDE_PATH");
-      break;
-    }
-  if (path != 0 && *path != 0)
-    path_include (pfile, path, SYSTEM);
-
-  /* Search "translated" versions of GNU directories.
-     These have /usr/local/lib/gcc... replaced by specd_prefix.  */
-  default_len = 0;
-  specd_len = 0;
-  default_prefix = NULL;
-  if (specd_prefix != 0 && cpp_GCC_INCLUDE_DIR_len)
-    {
-      /* Remove the `include' from /usr/local/lib/gcc.../include.
-        GCC_INCLUDE_DIR will always end in /include.  */
-      default_len = cpp_GCC_INCLUDE_DIR_len;
-      default_prefix = (char *) alloca (default_len + 1);
-      specd_len = strlen (specd_prefix);
-
-      memcpy (default_prefix, cpp_GCC_INCLUDE_DIR, default_len);
-      default_prefix[default_len] = '\0';
-
-      for (p = cpp_include_defaults; p->fname; p++)
-       {
-         /* Some standard dirs are only for C++.  */
-         if (!p->cplusplus
-             || (CPP_OPTION (pfile, cplusplus)
-                 && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
-           {
-             char *str;
-
-             /* Should we be translating sysrooted dirs too?  Assume
-                that iprefix and sysroot are mutually exclusive, for
-                now.  */
-             if (p->add_sysroot && CPP_OPTION (pfile, sysroot)
-                 && *(CPP_OPTION (pfile, sysroot)))
-               continue;
-
-             /* Does this dir start with the prefix?  */
-             if (!strncmp (p->fname, default_prefix, default_len))
-               {
-                 /* Yes; change prefix and add to search list.  */
-                 int flen = strlen (p->fname);
-                 int this_len = specd_len + flen - default_len;
-
-                 str = (char *) xmalloc (this_len + 1);
-                 memcpy (str, specd_prefix, specd_len);
-                 memcpy (str + specd_len,
-                         p->fname + default_len,
-                         flen - default_len + 1);
-
-                 append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
-               }
-           }
-       }
-    }
-
-  for (p = cpp_include_defaults; p->fname; p++)
-    {
-      /* Some standard dirs are only for C++.  */
-      if (!p->cplusplus
-         || (CPP_OPTION (pfile, cplusplus)
-             && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
-       {
-         char *str;
-
-         /* Should this dir start with the sysroot?  */
-         if (p->add_sysroot && CPP_OPTION (pfile, sysroot)
-             && *(CPP_OPTION (pfile, sysroot)))
-           str = concat (CPP_OPTION (pfile, sysroot), p->fname, NULL);
-
+  if (hosted)
+    _cpp_define_builtin (pfile, "__STDC_HOSTED__ 1");
          else
-           str = update_path (p->fname, p->component);
-
-         append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
-       }
-    }
-}
-
-/* Pushes a command line -imacro and -include file indicated by P onto
-   the buffer stack.  Returns nonzero if successful.  */
-static bool
-push_include (pfile, p)
-     cpp_reader *pfile;
-     struct pending_option *p;
-{
-  cpp_token header;
-
-  /* Later: maybe update this to use the #include "" search path
-     if cpp_read_file fails.  */
-  header.type = CPP_STRING;
-  header.val.str.text = (const unsigned char *) p->arg;
-  header.val.str.len = strlen (p->arg);
-  /* Make the command line directive take up a line.  */
-  pfile->line++;
-
-  return _cpp_execute_include (pfile, &header, IT_CMDLINE);
-}
-
-/* Frees a pending_option chain.  */
-static void
-free_chain (head)
-     struct pending_option *head;
-{
-  struct pending_option *next;
+    _cpp_define_builtin (pfile, "__STDC_HOSTED__ 0");
 
-  while (head)
-    {
-      next = head->next;
-      free (head);
-      head = next;
-    }
+  if (CPP_OPTION (pfile, objc))
+    _cpp_define_builtin (pfile, "__OBJC__ 1");
 }
 
 /* Sanity-checks are dependent on command-line options, so it is
    called as a subroutine of cpp_read_main_file ().  */
 #if ENABLE_CHECKING
-static void sanity_checks PARAMS ((cpp_reader *));
-static void sanity_checks (pfile)
-     cpp_reader *pfile;
+static void sanity_checks (cpp_reader *);
+static void sanity_checks (cpp_reader *pfile)
 {
   cppchar_t test = 0;
   size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part);
@@ -914,36 +389,39 @@ static void sanity_checks (pfile)
      type precisions made by cpplib.  */
   test--;
   if (test < 1)
-    cpp_error (pfile, DL_ICE, "cppchar_t must be an unsigned type");
+    cpp_error (pfile, CPP_DL_ICE, "cppchar_t must be an unsigned type");
 
   if (CPP_OPTION (pfile, precision) > max_precision)
-    cpp_error (pfile, DL_ICE,
-              "preprocessor arithmetic has maximum precision of %lu bits; target requires %lu bits",
+    cpp_error (pfile, CPP_DL_ICE,
+              "preprocessor arithmetic has maximum precision of %lu bits;"
+              " target requires %lu bits",
               (unsigned long) max_precision,
               (unsigned long) CPP_OPTION (pfile, precision));
 
   if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision))
-    cpp_error (pfile, DL_ICE,
+    cpp_error (pfile, CPP_DL_ICE,
               "CPP arithmetic must be at least as precise as a target int");
 
   if (CPP_OPTION (pfile, char_precision) < 8)
-    cpp_error (pfile, DL_ICE, "target char is less than 8 bits wide");
+    cpp_error (pfile, CPP_DL_ICE, "target char is less than 8 bits wide");
 
   if (CPP_OPTION (pfile, wchar_precision) < CPP_OPTION (pfile, char_precision))
-    cpp_error (pfile, DL_ICE,
+    cpp_error (pfile, CPP_DL_ICE,
               "target wchar_t is narrower than target char");
 
   if (CPP_OPTION (pfile, int_precision) < CPP_OPTION (pfile, char_precision))
-    cpp_error (pfile, DL_ICE,
+    cpp_error (pfile, CPP_DL_ICE,
               "target int is narrower than target char");
 
   /* This is assumed in eval_token() and could be fixed if necessary.  */
   if (sizeof (cppchar_t) > sizeof (cpp_num_part))
-    cpp_error (pfile, DL_ICE, "CPP half-integer narrower than CPP character");
+    cpp_error (pfile, CPP_DL_ICE,
+              "CPP half-integer narrower than CPP character");
 
   if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T)
-    cpp_error (pfile, DL_ICE,
-              "CPP on this host cannot handle wide character constants over %lu bits, but the target requires %lu bits",
+    cpp_error (pfile, CPP_DL_ICE,
+              "CPP on this host cannot handle wide character constants over"
+              " %lu bits, but the target requires %lu bits",
               (unsigned long) BITS_PER_CPPCHAR_T,
               (unsigned long) CPP_OPTION (pfile, wchar_precision));
 }
@@ -955,10 +433,7 @@ static void sanity_checks (pfile)
    cpp_read_main_file().  If no targets have been added before
    cpp_read_main_file(), then the default target is used.  */
 void
-cpp_add_dependency_target (pfile, target, quote)
-     cpp_reader *pfile;
-     const char *target;
-     int quote;
+cpp_add_dependency_target (cpp_reader *pfile, const char *target, int quote)
 {
   if (!pfile->deps)
     pfile->deps = deps_init ();
@@ -967,44 +442,25 @@ cpp_add_dependency_target (pfile, target, quote)
 }
 
 /* This is called after options have been parsed, and partially
-   processed.  Setup for processing input from the file named FNAME,
-   or stdin if it is the empty string.  Return the original filename
-   on success (e.g. foo.i->foo.c), or NULL on failure.  */
-const char *
-cpp_read_main_file (pfile, fname, table)
-     cpp_reader *pfile;
-     const char *fname;
-     hash_table *table;
+   processed.  */
+void
+cpp_post_options (cpp_reader *pfile)
 {
   sanity_checks (pfile);
 
   post_options (pfile);
 
-  /* The front ends don't set up the hash table until they have
-     finished processing the command line options, so initializing the
-     hashtable is deferred until now.  */
-  _cpp_init_hashtable (pfile, table);
-
-  /* Set up the include search path now.  */
-  if (! CPP_OPTION (pfile, no_standard_includes))
-    init_standard_includes (pfile);
-
-  merge_include_chains (pfile);
-
-  /* With -v, print the list of dirs to search.  */
-  if (CPP_OPTION (pfile, verbose))
-    {
-      struct search_path *l;
-      fprintf (stderr, _("#include \"...\" search starts here:\n"));
-      for (l = CPP_OPTION (pfile, quote_include); l; l = l->next)
-       {
-         if (l == CPP_OPTION (pfile, bracket_include))
-           fprintf (stderr, _("#include <...> search starts here:\n"));
-         fprintf (stderr, " %s\n", l->name);
-       }
-      fprintf (stderr, _("End of search list.\n"));
+  /* Mark named operators before handling command line macros.  */
+  if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, operator_names))
+    mark_named_operators (pfile);
     }
 
+/* Setup for processing input from the file named FNAME, or stdin if
+   it is the empty string.  Return the original filename
+   on success (e.g. foo.i->foo.c), or NULL on failure.  */
+const char *
+cpp_read_main_file (cpp_reader *pfile, const char *fname)
+{
   if (CPP_OPTION (pfile, deps.style) != DEPS_NONE)
     {
       if (!pfile->deps)
@@ -1014,21 +470,23 @@ cpp_read_main_file (pfile, fname, table)
       deps_add_default_target (pfile, fname);
     }
 
-  /* Open the main input file.  */
-  if (!_cpp_read_file (pfile, fname))
+  pfile->main_file
+    = _cpp_find_file (pfile, fname, &pfile->no_search_path, false, 0);
+  if (_cpp_find_failed (pfile->main_file))
     return NULL;
 
-  /* Set this here so the client can change the option if it wishes,
-     and after stacking the main file so we don't trace the main
-     file.  */
-  pfile->line_maps.trace_includes = CPP_OPTION (pfile, print_include_names);
+  _cpp_stack_file (pfile, pfile->main_file, false);
 
   /* For foo.i, read the original filename foo.c now, for the benefit
      of the front ends.  */
   if (CPP_OPTION (pfile, preprocessed))
-    read_original_filename (pfile);
-
-  return pfile->map->to_file;
+    {
+      read_original_filename (pfile);
+      if (!pfile->map)
+       return NULL;
+      fname = pfile->map->to_file;
+    }
+  return fname;
 }
 
 /* For preprocessed files, if the first tokens are of the form # NUM.
@@ -1036,8 +494,7 @@ cpp_read_main_file (pfile, fname, table)
    generate file_change callbacks, which the front ends must handle
    appropriately given their state of initialization.  */
 static void
-read_original_filename (pfile)
-     cpp_reader *pfile;
+read_original_filename (cpp_reader *pfile)
 {
   const cpp_token *token, *token1;
 
@@ -1046,13 +503,16 @@ read_original_filename (pfile)
   token = _cpp_lex_direct (pfile);
   if (token->type == CPP_HASH)
     {
+      pfile->state.in_directive = 1;
       token1 = _cpp_lex_direct (pfile);
       _cpp_backup_tokens (pfile, 1);
+      pfile->state.in_directive = 0;
 
       /* If it's a #line directive, handle it.  */
       if (token1->type == CPP_NUMBER)
        {
          _cpp_handle_directive (pfile, token->flags & PREV_WHITE);
+         read_original_directory (pfile);
          return;
        }
     }
@@ -1061,70 +521,51 @@ read_original_filename (pfile)
   _cpp_backup_tokens (pfile, 1);
 }
 
-/* Handle pending command line options: -D, -U, -A, -imacros and
-   -include.  This should be called after debugging has been properly
-   set up in the front ends.  */
-void
-cpp_finish_options (pfile)
-     cpp_reader *pfile;
+/* For preprocessed files, if the tokens following the first filename
+   line is of the form # <line> "/path/name//", handle the
+   directive so we know the original current directory.  */
+static void
+read_original_directory (cpp_reader *pfile)
 {
-  /* Mark named operators before handling command line macros.  */
-  if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, operator_names))
-    mark_named_operators (pfile);
+  const cpp_token *hash, *token;
 
-  /* Install builtins and process command line macros etc. in the order
-     they appeared, but only if not already preprocessed.  */
-  if (! CPP_OPTION (pfile, preprocessed))
+  /* Lex ahead; if the first tokens are of the form # NUM, then
+     process the directive, otherwise back up.  */
+  hash = _cpp_lex_direct (pfile);
+  if (hash->type != CPP_HASH)
     {
-      struct pending_option *p;
-
-      /* Prevent -Wunused-macros with command-line redefinitions.  */
-      pfile->first_unused_line = (unsigned int) -1;
-      _cpp_do_file_change (pfile, LC_RENAME, _("<built-in>"), 1, 0);
-      init_builtins (pfile);
-      _cpp_do_file_change (pfile, LC_RENAME, _("<command line>"), 1, 0);
-      for (p = CPP_OPTION (pfile, pending)->directive_head; p; p = p->next)
-       (*p->handler) (pfile, p->arg);
-
-      /* Scan -imacros files after -D, -U, but before -include.
-        pfile->next_include_file is NULL, so _cpp_pop_buffer does not
-        push -include files.  */
-      for (p = CPP_OPTION (pfile, pending)->imacros_head; p; p = p->next)
-       if (push_include (pfile, p))
-         cpp_scan_nooutput (pfile);
-
-      pfile->next_include_file = &CPP_OPTION (pfile, pending)->include_head;
-      _cpp_maybe_push_include_file (pfile);
+      _cpp_backup_tokens (pfile, 1);
+      return;
     }
 
-  pfile->first_unused_line = pfile->line;
+  token = _cpp_lex_direct (pfile);
 
-  free_chain (CPP_OPTION (pfile, pending)->imacros_head);
-  free_chain (CPP_OPTION (pfile, pending)->directive_head);
-}
+  if (token->type != CPP_NUMBER)
+    {
+      _cpp_backup_tokens (pfile, 2);
+      return;
+    }
 
-/* Push the next buffer on the stack given by -include, if any.  */
-void
-_cpp_maybe_push_include_file (pfile)
-     cpp_reader *pfile;
-{
-  if (pfile->next_include_file)
+  token = _cpp_lex_direct (pfile);
+
+  if (token->type != CPP_STRING
+      || ! (token->val.str.len >= 5
+           && token->val.str.text[token->val.str.len-2] == '/'
+           && token->val.str.text[token->val.str.len-3] == '/'))
+    {
+      _cpp_backup_tokens (pfile, 3);
+      return;
+    }
+
+  if (pfile->cb.dir_change)
     {
-      struct pending_option *head = *pfile->next_include_file;
+      char *debugdir = alloca (token->val.str.len - 3);
 
-      while (head && !push_include (pfile, head))
-       head = head->next;
+      memcpy (debugdir, (const char *) token->val.str.text + 1,
+             token->val.str.len - 4);
+      debugdir[token->val.str.len - 4] = '\0';
 
-      if (head)
-       pfile->next_include_file = &head->next;
-      else
-       {
-         /* All done; restore the line map from <command line>.  */
-         _cpp_do_file_change (pfile, LC_RENAME,
-                              pfile->line_maps.maps[0].to_file, 1, 0);
-         /* Don't come back here again.  */
-         pfile->next_include_file = NULL;
-       }
+      pfile->cb.dir_change (pfile, debugdir);
     }
 }
 
@@ -1135,9 +576,7 @@ _cpp_maybe_push_include_file (pfile)
    Maybe it should also reset state, such that you could call
    cpp_start_read with a new filename to restart processing.  */
 int
-cpp_finish (pfile, deps_stream)
-     cpp_reader *pfile;
-     FILE *deps_stream;
+cpp_finish (cpp_reader *pfile, FILE *deps_stream)
 {
   /* Warn about unused macros before popping the final buffer.  */
   if (CPP_OPTION (pfile, warn_unused_macros))
@@ -1168,313 +607,8 @@ cpp_finish (pfile, deps_stream)
   return pfile->errors;
 }
 
-/* Add a directive to be handled later in the initialization phase.  */
 static void
-new_pending_directive (pend, text, handler)
-     struct cpp_pending *pend;
-     const char *text;
-     cl_directive_handler handler;
-{
-  struct pending_option *o = (struct pending_option *)
-    xmalloc (sizeof (struct pending_option));
-
-  o->arg = text;
-  o->next = NULL;
-  o->handler = handler;
-  APPEND (pend, directive, o);
-}
-
-/* Irix6 "cc -n32" and OSF4 cc have problems with char foo[] = ("string");
-   I.e. a const string initializer with parens around it.  That is
-   what N_("string") resolves to, so we make no_* be macros instead.  */
-#define no_ass N_("assertion missing after %s")
-#define no_dir N_("directory name missing after %s")
-#define no_fil N_("file name missing after %s")
-#define no_mac N_("macro name missing after %s")
-#define no_pth N_("path name missing after %s")
-
-/* This is the list of all command line options, with the leading
-   "-" removed.  It must be sorted in ASCII collating order.  */
-#define COMMAND_LINE_OPTIONS                                                  \
-  DEF_OPT("A",                        no_ass, OPT_A)                          \
-  DEF_OPT("D",                        no_mac, OPT_D)                          \
-  DEF_OPT("I",                        no_dir, OPT_I)                          \
-  DEF_OPT("U",                        no_mac, OPT_U)                          \
-  DEF_OPT("idirafter",                no_dir, OPT_idirafter)                  \
-  DEF_OPT("imacros",                  no_fil, OPT_imacros)                    \
-  DEF_OPT("include",                  no_fil, OPT_include)                    \
-  DEF_OPT("iprefix",                  no_pth, OPT_iprefix)                    \
-  DEF_OPT("isysroot",                 no_dir, OPT_isysroot)                   \
-  DEF_OPT("isystem",                  no_dir, OPT_isystem)                    \
-  DEF_OPT("iwithprefix",              no_dir, OPT_iwithprefix)                \
-  DEF_OPT("iwithprefixbefore",        no_dir, OPT_iwithprefixbefore)
-
-#define DEF_OPT(text, msg, code) code,
-enum opt_code
-{
-  COMMAND_LINE_OPTIONS
-  N_OPTS
-};
-#undef DEF_OPT
-
-struct cl_option
-{
-  const char *opt_text;
-  const char *msg;
-  size_t opt_len;
-  enum opt_code opt_code;
-};
-
-#define DEF_OPT(text, msg, code) { text, msg, sizeof(text) - 1, code },
-#ifdef HOST_EBCDIC
-static struct cl_option cl_options[] =
-#else
-static const struct cl_option cl_options[] =
-#endif
-{
-  COMMAND_LINE_OPTIONS
-};
-#undef DEF_OPT
-#undef COMMAND_LINE_OPTIONS
-
-/* Perform a binary search to find which, if any, option the given
-   command-line matches.  Returns its index in the option array,
-   negative on failure.  Complications arise since some options can be
-   suffixed with an argument, and multiple complete matches can occur,
-   e.g. -pedantic and -pedantic-errors.  */
-static int
-parse_option (input)
-     const char *input;
-{
-  unsigned int md, mn, mx;
-  size_t opt_len;
-  int comp;
-
-  mn = 0;
-  mx = N_OPTS;
-
-  while (mx > mn)
-    {
-      md = (mn + mx) / 2;
-
-      opt_len = cl_options[md].opt_len;
-      comp = strncmp (input, cl_options[md].opt_text, opt_len);
-
-      if (comp > 0)
-       mn = md + 1;
-      else if (comp < 0)
-       mx = md;
-      else
-       {
-         if (input[opt_len] == '\0')
-           return md;
-         /* We were passed more text.  If the option takes an argument,
-            we may match a later option or we may have been passed the
-            argument.  The longest possible option match succeeds.
-            If the option takes no arguments we have not matched and
-            continue the search (e.g. input="stdc++" match was "stdc").  */
-         mn = md + 1;
-         if (cl_options[md].msg)
-           {
-             /* Scan forwards.  If we get an exact match, return it.
-                Otherwise, return the longest option-accepting match.
-                This loops no more than twice with current options.  */
-             mx = md;
-             for (; mn < (unsigned int) N_OPTS; mn++)
-               {
-                 opt_len = cl_options[mn].opt_len;
-                 if (strncmp (input, cl_options[mn].opt_text, opt_len))
-                   break;
-                 if (input[opt_len] == '\0')
-                   return mn;
-                 if (cl_options[mn].msg)
-                   mx = mn;
-               }
-             return mx;
-           }
-       }
-    }
-
-  return -1;
-}
-
-/* Handle one command-line option in (argc, argv).
-   Can be called multiple times, to handle multiple sets of options.
-   Returns number of strings consumed.  */
-int
-cpp_handle_option (pfile, argc, argv)
-     cpp_reader *pfile;
-     int argc;
-     char **argv;
-{
-  int i = 0;
-  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
-
-    {
-      enum opt_code opt_code;
-      int opt_index;
-      const char *arg = 0;
-
-      /* Skip over '-'.  */
-      opt_index = parse_option (&argv[i][1]);
-      if (opt_index < 0)
-       return i;
-
-      opt_code = cl_options[opt_index].opt_code;
-      if (cl_options[opt_index].msg)
-       {
-         arg = &argv[i][cl_options[opt_index].opt_len + 1];
-         if (arg[0] == '\0')
-           {
-             arg = argv[++i];
-             if (!arg)
-               {
-                 cpp_error (pfile, DL_ERROR,
-                            cl_options[opt_index].msg, argv[i - 1]);
-                 return argc;
-               }
-           }
-       }
-
-      switch (opt_code)
-       {
-       case N_OPTS: /* Shut GCC up.  */
-         break;
-
-       case OPT_D:
-         new_pending_directive (pend, arg, cpp_define);
-         break;
-       case OPT_iprefix:
-         CPP_OPTION (pfile, include_prefix) = arg;
-         CPP_OPTION (pfile, include_prefix_len) = strlen (arg);
-         break;
-
-       case OPT_isysroot:
-         CPP_OPTION (pfile, sysroot) = arg;
-         break;
-
-       case OPT_A:
-         if (arg[0] == '-')
-           new_pending_directive (pend, arg + 1, cpp_unassert);
-         else
-           new_pending_directive (pend, arg, cpp_assert);
-         break;
-       case OPT_U:
-         new_pending_directive (pend, arg, cpp_undef);
-         break;
-       case OPT_I:           /* Add directory to path for includes.  */
-         if (!strcmp (arg, "-"))
-           {
-             /* -I- means:
-                Use the preceding -I directories for #include "..."
-                but not #include <...>.
-                Don't search the directory of the present file
-                for #include "...".  (Note that -I. -I- is not the same as
-                the default setup; -I. uses the compiler's working dir.)  */
-             if (! CPP_OPTION (pfile, ignore_srcdir))
-               {
-                 pend->quote_head = pend->brack_head;
-                 pend->quote_tail = pend->brack_tail;
-                 pend->brack_head = 0;
-                 pend->brack_tail = 0;
-                 CPP_OPTION (pfile, ignore_srcdir) = 1;
-               }
-             else
-               {
-                 cpp_error (pfile, DL_ERROR, "-I- specified twice");
-                 return argc;
-               }
-           }
-         else
-           append_include_chain (pfile, (char *)xstrdup (arg), BRACKET, 0);
-         break;
-       case OPT_isystem:
-         /* Add directory to beginning of system include path, as a system
-            include directory.  */
-         append_include_chain (pfile, (char *)xstrdup (arg), SYSTEM, 0);
-         break;
-       case OPT_include:
-       case OPT_imacros:
-         {
-           struct pending_option *o = (struct pending_option *)
-             xmalloc (sizeof (struct pending_option));
-           o->arg = arg;
-           o->next = NULL;
-
-           if (opt_code == OPT_include)
-             APPEND (pend, include, o);
-           else
-             APPEND (pend, imacros, o);
-         }
-         break;
-       case OPT_iwithprefix:
-         /* Add directory to end of path for includes,
-            with the default prefix at the front of its name.  */
-         /* fall through */
-       case OPT_iwithprefixbefore:
-         /* Add directory to main path for includes,
-            with the default prefix at the front of its name.  */
-         {
-           char *fname;
-           int len;
-
-           len = strlen (arg);
-
-           if (CPP_OPTION (pfile, include_prefix) != 0)
-             {
-               size_t ipl = CPP_OPTION (pfile, include_prefix_len);
-               fname = xmalloc (ipl + len + 1);
-               memcpy (fname, CPP_OPTION (pfile, include_prefix), ipl);
-               memcpy (fname + ipl, arg, len + 1);
-             }
-           else if (cpp_GCC_INCLUDE_DIR_len)
-             {
-               fname = xmalloc (cpp_GCC_INCLUDE_DIR_len + len + 1);
-               memcpy (fname, cpp_GCC_INCLUDE_DIR, cpp_GCC_INCLUDE_DIR_len);
-               memcpy (fname + cpp_GCC_INCLUDE_DIR_len, arg, len + 1);
-             }
-           else
-             fname = xstrdup (arg);
-
-           append_include_chain (pfile, fname,
-                         opt_code == OPT_iwithprefix ? SYSTEM: BRACKET, 0);
-         }
-         break;
-       case OPT_idirafter:
-         /* Add directory to end of path for includes.  */
-         append_include_chain (pfile, (char *)xstrdup (arg), AFTER, 0);
-         break;
-       }
-    }
-  return i + 1;
-}
-
-/* Handle command-line options in (argc, argv).
-   Can be called multiple times, to handle multiple sets of options.
-   Returns if an unrecognized option is seen.
-   Returns number of strings consumed.  */
-int
-cpp_handle_options (pfile, argc, argv)
-     cpp_reader *pfile;
-     int argc;
-     char **argv;
-{
-  int i;
-  int strings_processed;
-
-  for (i = 0; i < argc; i += strings_processed)
-    {
-      strings_processed = cpp_handle_option (pfile, argc - i, argv + i);
-      if (strings_processed == 0)
-       break;
-    }
-
-  return i;
-}
-
-static void
-post_options (pfile)
-     cpp_reader *pfile;
+post_options (cpp_reader *pfile)
 {
   /* -Wtraditional is not useful in C++ mode.  */
   if (CPP_OPTION (pfile, cplusplus))
@@ -1488,7 +622,16 @@ post_options (pfile)
       CPP_OPTION (pfile, traditional) = 0;
     }
 
-  /* Traditional CPP does not accurately track column information.  */
+  if (CPP_OPTION (pfile, warn_trigraphs) == 2)
+    CPP_OPTION (pfile, warn_trigraphs) = !CPP_OPTION (pfile, trigraphs);
+
   if (CPP_OPTION (pfile, traditional))
-    CPP_OPTION (pfile, show_column) = 0;
+    {
+      CPP_OPTION (pfile, cplusplus_comments) = 0;
+
+      /* Traditional CPP does not accurately track column information.  */
+      CPP_OPTION (pfile, show_column) = 0;
+      CPP_OPTION (pfile, trigraphs) = 0;
+      CPP_OPTION (pfile, warn_trigraphs) = 0;
+    }
 }
index a24b68d3959096b7a70d528fae2155cb6b40233c..610d5b134f45472f0e6c6a06d9df76641f84dd3e 100644 (file)
@@ -1,10 +1,9 @@
 /* CPP Library - lexical analysis.
-   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Per Bothner, 1994-95.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
    Broken out to separate file, Zack Weinberg, Mar 2000
-   Single-pass line tokenization by Neil Booth, April 2000
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -26,20 +25,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "cpphash.h"
 #include <assert.h>
 
-#ifdef MULTIBYTE_CHARS
-#include "mbchar.h"
-#include <locale.h>
-#endif
-
-/* Tokens with SPELL_STRING store their spelling in the token list,
-   and it's length in the token->val.name.len.  */
 enum spell_type
 {
   SPELL_OPERATOR = 0,
-  SPELL_CHAR,
   SPELL_IDENT,
-  SPELL_NUMBER,
-  SPELL_STRING,
+  SPELL_LITERAL,
   SPELL_NONE
 };
 
@@ -53,53 +43,37 @@ static const unsigned char *const digraph_spellings[] =
 { U"%:", U"%:%:", U"<:", U":>", U"<%", U"%>" };
 
 #define OP(e, s) { SPELL_OPERATOR, U s           },
-#define TK(e, s) { s,              U STRINGX (e) },
+#define TK(e, s) { s,              U #e },
 static const struct token_spelling token_spellings[N_TTYPES] = { TTYPE_TABLE };
 #undef OP
 #undef TK
 
 #define TOKEN_SPELL(token) (token_spellings[(token)->type].category)
 #define TOKEN_NAME(token) (token_spellings[(token)->type].name)
-#define BACKUP() do {buffer->cur = buffer->backup_to;} while (0)
-
-static void handle_newline PARAMS ((cpp_reader *));
-static cppchar_t skip_escaped_newlines PARAMS ((cpp_reader *));
-static cppchar_t get_effective_char PARAMS ((cpp_reader *));
-
-static int skip_asm_block PARAMS ((cpp_reader *));
-static int skip_block_comment PARAMS ((cpp_reader *));
-static int skip_line_comment PARAMS ((cpp_reader *));
-static void adjust_column PARAMS ((cpp_reader *));
-static int skip_whitespace PARAMS ((cpp_reader *, cppchar_t));
-static cpp_hashnode *parse_identifier PARAMS ((cpp_reader *));
-static uchar *parse_slow PARAMS ((cpp_reader *, const uchar *, int,
-                                 unsigned int *));
-static void pedantic_parse_number PARAMS ((cpp_reader *, cpp_string *, int));
-static void parse_number PARAMS ((cpp_reader *, cpp_string *, int));
-static int unescaped_terminator_p PARAMS ((cpp_reader *, const uchar *));
-static void parse_string PARAMS ((cpp_reader *, cpp_token *, cppchar_t));
-static bool trigraph_p PARAMS ((cpp_reader *));
-static unsigned int copy_text_chars PARAMS ((char *, const char *, unsigned int));
-static void save_asm PARAMS ((cpp_reader *, cpp_token *, const uchar *));
-static void save_comment PARAMS ((cpp_reader *, cpp_token *, const uchar *,
-                                 cppchar_t));
-static bool continue_after_nul PARAMS ((cpp_reader *));
-static int name_p PARAMS ((cpp_reader *, const cpp_string *));
-static int maybe_read_ucs PARAMS ((cpp_reader *, const unsigned char **,
-                                  const unsigned char *, cppchar_t *));
-static tokenrun *next_tokenrun PARAMS ((tokenrun *));
-
-static unsigned int hex_digit_value PARAMS ((unsigned int));
-static _cpp_buff *new_buff PARAMS ((size_t));
+
+static void add_line_note (cpp_buffer *, const uchar *, unsigned int);
+static int skip_line_comment (cpp_reader *);
+static void skip_whitespace (cpp_reader *, cppchar_t);
+static cpp_hashnode *lex_identifier (cpp_reader *, const uchar *);
+static void lex_number (cpp_reader *, cpp_string *);
+static bool forms_identifier_p (cpp_reader *, int);
+static void lex_string (cpp_reader *, cpp_token *, const uchar *);
+static void save_comment (cpp_reader *, cpp_token *, const uchar *, cppchar_t);
+static void create_literal (cpp_reader *, cpp_token *, const uchar *,
+                           unsigned int, enum cpp_ttype);
+static bool warn_in_comment (cpp_reader *, _cpp_line_note *);
+static int name_p (cpp_reader *, const cpp_string *);
+static tokenrun *next_tokenrun (tokenrun *);
+
+static _cpp_buff *new_buff (size_t);
+
 
 /* Utility routine:
 
    Compares, the token TOKEN to the NUL-terminated string STRING.
    TOKEN must be a CPP_NAME.  Returns 1 for equal, 0 for unequal.  */
 int
-cpp_ideq (token, string)
-     const cpp_token *token;
-     const char *string;
+cpp_ideq (const cpp_token *token, const char *string)
 {
   if (token->type != CPP_NAME)
     return 0;
@@ -107,152 +81,232 @@ cpp_ideq (token, string)
   return !ustrcmp (NODE_NAME (token->val.node), (const uchar *) string);
 }
 
-/* Call when meeting a newline, assumed to be in buffer->cur[-1].
-   Returns with buffer->cur pointing to the character immediately
-   following the newline (combination).  */
+/* Record a note TYPE at byte POS into the current cleaned logical
+   line.  */
 static void
-handle_newline (pfile)
-     cpp_reader *pfile;
+add_line_note (cpp_buffer *buffer, const uchar *pos, unsigned int type)
 {
-  cpp_buffer *buffer = pfile->buffer;
-
-  /* Handle CR-LF and LF-CR.  Most other implementations (e.g. java)
-     only accept CR-LF; maybe we should fall back to that behavior?  */
-  if (buffer->cur[-1] + buffer->cur[0] == '\r' + '\n')
-    buffer->cur++;
-
-  buffer->line_base = buffer->cur;
-  buffer->col_adjust = 0;
-  pfile->line++;
-}
-
-/* Subroutine of skip_escaped_newlines; called when a 3-character
-   sequence beginning with "??" is encountered.  buffer->cur points to
-   the second '?'.
-
-   Warn if necessary, and returns true if the sequence forms a
-   trigraph and the trigraph should be honored.  */
-static bool
-trigraph_p (pfile)
-     cpp_reader *pfile;
-{
-  cpp_buffer *buffer = pfile->buffer;
-  cppchar_t from_char = buffer->cur[1];
-  bool accept;
-
-  if (!_cpp_trigraph_map[from_char])
-    return false;
-
-  accept = CPP_OPTION (pfile, trigraphs);
-
-  /* Don't warn about trigraphs in comments.  */
-  if (CPP_OPTION (pfile, warn_trigraphs) && !pfile->state.lexing_comment)
+  if (buffer->notes_used == buffer->notes_cap)
     {
-      if (accept)
-       cpp_error_with_line (pfile, DL_WARNING,
-                            pfile->line, CPP_BUF_COL (buffer) - 1,
-                            "trigraph ??%c converted to %c",
-                            (int) from_char,
-                            (int) _cpp_trigraph_map[from_char]);
-      else if (buffer->cur != buffer->last_Wtrigraphs)
-       {
-         buffer->last_Wtrigraphs = buffer->cur;
-         cpp_error_with_line (pfile, DL_WARNING,
-                              pfile->line, CPP_BUF_COL (buffer) - 1,
-                              "trigraph ??%c ignored", (int) from_char);
-       }
+      buffer->notes_cap = buffer->notes_cap * 2 + 200;
+      buffer->notes = xrealloc (buffer->notes,
+                               buffer->notes_cap * sizeof (_cpp_line_note));
     }
 
-  return accept;
+  buffer->notes[buffer->notes_used].pos = pos;
+  buffer->notes[buffer->notes_used].type = type;
+  buffer->notes_used++;
 }
 
-/* Skips any escaped newlines introduced by '?' or a '\\', assumed to
-   lie in buffer->cur[-1].  Returns the next byte, which will be in
-   buffer->cur[-1].  This routine performs preprocessing stages 1 and
-   2 of the ISO C standard.  */
-static cppchar_t
-skip_escaped_newlines (pfile)
-     cpp_reader *pfile;
+/* Returns with a logical line that contains no escaped newlines or
+   trigraphs.  This is a time-critical inner loop.  */
+void
+_cpp_clean_line (cpp_reader *pfile)
 {
-  cpp_buffer *buffer = pfile->buffer;
-  cppchar_t next = buffer->cur[-1];
+  cpp_buffer *buffer;
+  const uchar *s;
+  uchar c, *d, *p;
+
+  buffer = pfile->buffer;
+  buffer->cur_note = buffer->notes_used = 0;
+  buffer->cur = buffer->line_base = buffer->next_line;
+  buffer->need_line = false;
+  s = buffer->next_line - 1;
 
-  /* Only do this if we apply stages 1 and 2.  */
   if (!buffer->from_stage3)
     {
-      const unsigned char *saved_cur;
-      cppchar_t next1;
-
-      do
+      /* Short circuit for the common case of an un-escaped line with
+        no trigraphs.  The primary win here is by not writing any
+        data back to memory until we have to.  */
+      for (;;)
        {
-         if (next == '?')
+         c = *++s;
+         if (c == '\n' || c == '\r')
            {
-             if (buffer->cur[0] != '?' || !trigraph_p (pfile))
-               break;
-
-             /* Translate the trigraph.  */
-             next = _cpp_trigraph_map[buffer->cur[1]];
-             buffer->cur += 2;
-             if (next != '\\')
-               break;
+             d = (uchar *) s;
+
+             if (s == buffer->rlimit)
+               goto done;
+
+             /* DOS line ending? */
+             if (c == '\r' && s[1] == '\n')
+               s++;
+
+             if (s == buffer->rlimit)
+               goto done;
+
+             /* check for escaped newline */
+             p = d;
+             while (p != buffer->next_line && is_nvspace (p[-1]))
+               p--;
+             if (p == buffer->next_line || p[-1] != '\\')
+               goto done;
+
+             /* Have an escaped newline; process it and proceed to
+                the slow path.  */
+             add_line_note (buffer, p - 1, p != d ? ' ' : '\\');
+             d = p - 2;
+             buffer->next_line = p - 1;
+             break;
+           }
+         if (c == '?' && s[1] == '?' && _cpp_trigraph_map[s[2]])
+           {
+             /* Have a trigraph.  We may or may not have to convert
+                it.  Add a line note regardless, for -Wtrigraphs.  */
+             add_line_note (buffer, s, s[2]);
+             if (CPP_OPTION (pfile, trigraphs))
+               {
+                 /* We do, and that means we have to switch to the
+                    slow path.  */
+                 d = (uchar *) s;
+                 *d = _cpp_trigraph_map[s[2]];
+                 s += 2;
+                 break;
+               }
            }
+       }
 
-         if (buffer->cur == buffer->rlimit)
-           break;
 
-         /* We have a backslash, and room for at least one more
-            character.  Skip horizontal whitespace.  */
-         saved_cur = buffer->cur;
-         do
-           next1 = *buffer->cur++;
-         while (is_nvspace (next1) && buffer->cur < buffer->rlimit);
+      for (;;)
+       {
+         c = *++s;
+         *++d = c;
 
-         if (!is_vspace (next1))
+         if (c == '\n' || c == '\r')
            {
-             buffer->cur = saved_cur;
-             break;
-           }
+                 /* Handle DOS line endings.  */
+             if (c == '\r' && s != buffer->rlimit && s[1] == '\n')
+               s++;
+             if (s == buffer->rlimit)
+               break;
 
-         if (saved_cur != buffer->cur - 1
-             && !pfile->state.lexing_comment)
-           cpp_error (pfile, DL_WARNING,
-                      "backslash and newline separated by space");
+             /* Escaped?  */
+             p = d;
+             while (p != buffer->next_line && is_nvspace (p[-1]))
+               p--;
+             if (p == buffer->next_line || p[-1] != '\\')
+               break;
 
-         handle_newline (pfile);
-         buffer->backup_to = buffer->cur;
-         if (buffer->cur == buffer->rlimit)
+             add_line_note (buffer, p - 1, p != d ? ' ': '\\');
+             d = p - 2;
+             buffer->next_line = p - 1;
+           }
+         else if (c == '?' && s[1] == '?' && _cpp_trigraph_map[s[2]])
            {
-             cpp_error (pfile, DL_PEDWARN,
-                        "backslash-newline at end of file");
-             next = EOF;
+             /* Add a note regardless, for the benefit of -Wtrigraphs.  */
+             add_line_note (buffer, d, s[2]);
+             if (CPP_OPTION (pfile, trigraphs))
+               {
+                 *d = _cpp_trigraph_map[s[2]];
+                 s += 2;
+               }
            }
-         else
-           next = *buffer->cur++;
        }
-      while (next == '\\' || next == '?');
     }
+  else
+    {
+      do
+       s++;
+      while (*s != '\n' && *s != '\r');
+      d = (uchar *) s;
 
-  return next;
+      /* Handle DOS line endings.  */
+      if (*s == '\r' && s != buffer->rlimit && s[1] == '\n')
+       s++;
+    }
+
+ done:
+  *d = '\n';
+  /* A sentinel note that should never be processed.  */
+  add_line_note (buffer, d + 1, '\n');
+  buffer->next_line = s + 1;
+}
+
+/* Return true if the trigraph indicated by NOTE should be warned
+   about in a comment.  */
+static bool
+warn_in_comment (cpp_reader *pfile, _cpp_line_note *note)
+{
+  const uchar *p;
+
+  /* Within comments we don't warn about trigraphs, unless the
+     trigraph forms an escaped newline, as that may change
+     behavior.  */
+  if (note->type != '/')
+    return false;
+
+  /* If -trigraphs, then this was an escaped newline iff the next note
+     is coincident.  */
+  if (CPP_OPTION (pfile, trigraphs))
+    return note[1].pos == note->pos;
+
+  /* Otherwise, see if this forms an escaped newline.  */
+  p = note->pos + 3;
+  while (is_nvspace (*p))
+    p++;
+
+  /* There might have been escaped newlines between the trigraph and the
+     newline we found.  Hence the position test.  */
+  return (*p == '\n' && p < note[1].pos);
 }
 
-/* Obtain the next character, after trigraph conversion and skipping
-   an arbitrarily long string of escaped newlines.  The common case of
-   no trigraphs or escaped newlines falls through quickly.  On return,
-   buffer->backup_to points to where to return to if the character is
-   not to be processed.  */
-static cppchar_t
-get_effective_char (pfile)
-     cpp_reader *pfile;
+/* Process the notes created by add_line_note as far as the current
+   location.  */
+void
+_cpp_process_line_notes (cpp_reader *pfile, int in_comment)
 {
-  cppchar_t next;
   cpp_buffer *buffer = pfile->buffer;
 
-  buffer->backup_to = buffer->cur;
-  next = *buffer->cur++;
-  if (__builtin_expect (next == '?' || next == '\\', 0))
-    next = skip_escaped_newlines (pfile);
+  for (;;)
+    {
+      _cpp_line_note *note = &buffer->notes[buffer->cur_note];
+      unsigned int col;
+
+      if (note->pos > buffer->cur)
+       break;
+
+      buffer->cur_note++;
+      col = CPP_BUF_COLUMN (buffer, note->pos + 1);
+
+      if (note->type == '\\' || note->type == ' ')
+       {
+         if (note->type == ' ' && !in_comment)
+           cpp_error_with_line (pfile, CPP_DL_WARNING, pfile->line, col,
+                                "backslash and newline separated by space");
+
+         if (buffer->next_line > buffer->rlimit)
+           {
+             cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line, col,
+                                  "backslash-newline at end of file");
+             /* Prevent "no newline at end of file" warning.  */
+             buffer->next_line = buffer->rlimit;
+           }
 
-  return next;
+         buffer->line_base = note->pos;
+         pfile->line++;
+       }
+      else if (_cpp_trigraph_map[note->type])
+       {
+         if (CPP_OPTION (pfile, warn_trigraphs)
+             && (!in_comment || warn_in_comment (pfile, note)))
+           {
+             if (CPP_OPTION (pfile, trigraphs))
+               cpp_error_with_line (pfile, CPP_DL_WARNING, pfile->line, col,
+                                    "trigraph ??%c converted to %c",
+                                    note->type,
+                                    (int) _cpp_trigraph_map[note->type]);
+             else
+               {
+                 cpp_error_with_line
+                   (pfile, CPP_DL_WARNING, pfile->line, col,
+                    "trigraph ??%c ignored, use -trigraphs to enable",
+                    note->type);
+               }
+           }
+       }
+      else
+       abort ();
+    }
 }
 
 /* SDCC _asm specific */
@@ -260,8 +314,7 @@ get_effective_char (pfile)
    seeing _endasm.  Returns non-zero if _asm terminated by EOF, zero
    otherwise.  */
 static int
-skip_asm_block (pfile)
-     cpp_reader *pfile;
+skip_asm_block (cpp_reader *pfile)
 {
 #define _ENDASM_STR "endasm"
 #define _ENDASM_LEN ((sizeof _ENDASM_STR) - 1)
@@ -271,17 +324,11 @@ skip_asm_block (pfile)
   int prev_space = 0;
   int ret = 1;
 
-  pfile->state.lexing_comment = 1;
   while (buffer->cur != buffer->rlimit)
     {
       prev_space = is_space(c);
       c = *buffer->cur++;
 
-      /* FIXME: For speed, create a new character class of characters
-        of interest inside block comments.  */
-      if (c == '?' || c == '\\')
-       c = skip_escaped_newlines (pfile);
-
       if (prev_space && c == '_')
        {
           if (buffer->cur + _ENDASM_LEN <= buffer->rlimit &&
@@ -292,167 +339,110 @@ skip_asm_block (pfile)
              break;
             }
        }
-      else if (is_vspace (c))
+      else if (c == '\n')
        {
-         prev_space = is_space(c);
-         handle_newline (pfile);
+         --buffer->cur;
+         _cpp_process_line_notes (pfile, true);
+         if (buffer->next_line >= buffer->rlimit)
+           return true;
+         _cpp_clean_line (pfile);
+         pfile->line++;
        }
-      else if (c == '\t')
-       adjust_column (pfile);
     }
 
-  pfile->state.lexing_comment = 0;
+  _cpp_process_line_notes (pfile, true);
   return ret;
 }
 
 /* Skip a C-style block comment.  We find the end of the comment by
    seeing if an asterisk is before every '/' we encounter.  Returns
-   nonzero if comment terminated by EOF, zero otherwise.  */
-static int
-skip_block_comment (pfile)
-     cpp_reader *pfile;
+   nonzero if comment terminated by EOF, zero otherwise.
+
+   Buffer->cur points to the initial asterisk of the comment.  */
+bool
+_cpp_skip_block_comment (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
-  cppchar_t c = EOF, prevc = EOF;
+  const uchar *cur = buffer->cur;
+  uchar c;
 
-  pfile->state.lexing_comment = 1;
-  while (buffer->cur != buffer->rlimit)
-    {
-      prevc = c, c = *buffer->cur++;
-
-      /* FIXME: For speed, create a new character class of characters
-        of interest inside block comments.  */
-      if (c == '?' || c == '\\')
-       c = skip_escaped_newlines (pfile);
+  cur++;
+  if (*cur == '/')
+    cur++;
 
+  for (;;)
+    {
       /* People like decorating comments with '*', so check for '/'
         instead for efficiency.  */
+      c = *cur++;
+
       if (c == '/')
        {
-         if (prevc == '*')
+         if (cur[-2] == '*')
            break;
 
          /* Warn about potential nested comments, but not if the '/'
             comes immediately before the true comment delimiter.
             Don't bother to get it right across escaped newlines.  */
          if (CPP_OPTION (pfile, warn_comments)
-             && buffer->cur[0] == '*' && buffer->cur[1] != '/')
-           cpp_error_with_line (pfile, DL_WARNING,
-                                pfile->line, CPP_BUF_COL (buffer),
-                                "\"/*\" within comment");
+             && cur[0] == '*' && cur[1] != '/')
+           {
+             buffer->cur = cur;
+             cpp_error_with_line (pfile, CPP_DL_WARNING,
+                                  pfile->line, CPP_BUF_COL (buffer),
+                                  "\"/*\" within comment");
+           }
+       }
+      else if (c == '\n')
+       {
+         buffer->cur = cur - 1;
+         _cpp_process_line_notes (pfile, true);
+         if (buffer->next_line >= buffer->rlimit)
+           return true;
+         _cpp_clean_line (pfile);
+         pfile->line++;
+         cur = buffer->cur;
        }
-      else if (is_vspace (c))
-       handle_newline (pfile);
-      else if (c == '\t')
-       adjust_column (pfile);
     }
 
-  pfile->state.lexing_comment = 0;
-  return c != '/' || prevc != '*';
+  buffer->cur = cur;
+  _cpp_process_line_notes (pfile, true);
+  return false;
 }
 
 /* Skip a C++ line comment, leaving buffer->cur pointing to the
    terminating newline.  Handles escaped newlines.  Returns nonzero
    if a multiline comment.  */
 static int
-skip_line_comment (pfile)
-     cpp_reader *pfile;
+skip_line_comment (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
   unsigned int orig_line = pfile->line;
-  cppchar_t c;
-#ifdef MULTIBYTE_CHARS
-  wchar_t wc;
-  int char_len;
-#endif
-
-  pfile->state.lexing_comment = 1;
-#ifdef MULTIBYTE_CHARS
-  /* Reset multibyte conversion state.  */
-  (void) local_mbtowc (NULL, NULL, 0);
-#endif
-  do
-    {
-      if (buffer->cur == buffer->rlimit)
-       goto at_eof;
 
-#ifdef MULTIBYTE_CHARS
-      char_len = local_mbtowc (&wc, (const char *) buffer->cur,
-                              buffer->rlimit - buffer->cur);
-      if (char_len == -1)
-       {
-         cpp_error (pfile, DL_WARNING,
-                    "ignoring invalid multibyte character");
-         char_len = 1;
-         c = *buffer->cur++;
-       }
-      else
-       {
-         buffer->cur += char_len;
-         c = wc;
-       }
-#else
-      c = *buffer->cur++;
-#endif
-      if (c == '?' || c == '\\')
-       c = skip_escaped_newlines (pfile);
-    }
-  while (!is_vspace (c));
-
-  /* Step back over the newline, except at EOF.  */
-  buffer->cur--;
- at_eof:
+  while (*buffer->cur != '\n')
+    buffer->cur++;
 
-  pfile->state.lexing_comment = 0;
+  _cpp_process_line_notes (pfile, true);
   return orig_line != pfile->line;
 }
 
-/* pfile->buffer->cur is one beyond the \t character.  Update
-   col_adjust so we track the column correctly.  */
+/* Skips whitespace, saving the next non-whitespace character.  */
 static void
-adjust_column (pfile)
-     cpp_reader *pfile;
-{
-  cpp_buffer *buffer = pfile->buffer;
-  unsigned int col = CPP_BUF_COL (buffer) - 1; /* Zero-based column.  */
-
-  /* Round it up to multiple of the tabstop, but subtract 1 since the
-     tab itself occupies a character position.  */
-  buffer->col_adjust += (CPP_OPTION (pfile, tabstop)
-                        - col % CPP_OPTION (pfile, tabstop)) - 1;
-}
-
-/* Skips whitespace, saving the next non-whitespace character.
-   Adjusts pfile->col_adjust to account for tabs.  Without this,
-   tokens might be assigned an incorrect column.  */
-static int
-skip_whitespace (pfile, c)
-     cpp_reader *pfile;
-     cppchar_t c;
+skip_whitespace (cpp_reader *pfile, cppchar_t c)
 {
   cpp_buffer *buffer = pfile->buffer;
-  unsigned int warned = 0;
+  bool saw_NUL = false;
 
   do
     {
       /* Horizontal space always OK.  */
-      if (c == ' ')
+      if (c == ' ' || c == '\t')
        ;
-      else if (c == '\t')
-       adjust_column (pfile);
       /* Just \f \v or \0 left.  */
       else if (c == '\0')
-       {
-         if (buffer->cur - 1 == buffer->rlimit)
-           return 0;
-         if (!warned)
-           {
-             cpp_error (pfile, DL_WARNING, "null character(s) ignored");
-             warned = 1;
-           }
-       }
+       saw_NUL = true;
       else if (pfile->state.in_directive && CPP_PEDANTIC (pfile))
-       cpp_error_with_line (pfile, DL_PEDWARN, pfile->line,
+       cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line,
                             CPP_BUF_COL (buffer),
                             "%s in preprocessing directive",
                             c == '\f' ? "form feed" : "vertical tab");
@@ -462,16 +452,16 @@ skip_whitespace (pfile, c)
   /* We only want non-vertical space, i.e. ' ' \t \f \v \0.  */
   while (is_nvspace (c));
 
+  if (saw_NUL)
+    cpp_error (pfile, CPP_DL_WARNING, "null character(s) ignored");
+
   buffer->cur--;
-  return 1;
 }
 
 /* See if the characters of a number token are valid in a name (no
    '.', '+' or '-').  */
 static int
-name_p (pfile, string)
-     cpp_reader *pfile;
-     const cpp_string *string;
+name_p (cpp_reader *pfile, const cpp_string *string)
 {
   unsigned int i;
 
@@ -482,149 +472,94 @@ name_p (pfile, string)
   return 1;
 }
 
-/* Parse an identifier, skipping embedded backslash-newlines.  This is
-   a critical inner loop.  The common case is an identifier which has
-   not been split by backslash-newline, does not contain a dollar
-   sign, and has already been scanned (roughly 10:1 ratio of
-   seen:unseen identifiers in normal code; the distribution is
-   Poisson-like).  Second most common case is a new identifier, not
-   split and no dollar sign.  The other possibilities are rare and
-   have been relegated to parse_slow.  */
-static cpp_hashnode *
-parse_identifier (pfile)
-     cpp_reader *pfile;
+/* Returns TRUE if the sequence starting at buffer->cur is invalid in
+   an identifier.  FIRST is TRUE if this starts an identifier.  */
+static bool
+forms_identifier_p (cpp_reader *pfile, int first)
 {
-  cpp_hashnode *result;
-  const uchar *cur, *base;
-
-  /* Fast-path loop.  Skim over a normal identifier.
-     N.B. ISIDNUM does not include $.  */
-  cur = pfile->buffer->cur;
-  while (ISIDNUM (*cur))
-    cur++;
+  cpp_buffer *buffer = pfile->buffer;
 
-  /* Check for slow-path cases.  */
-  if (*cur == '?' || *cur == '\\' || *cur == '$')
+  if (*buffer->cur == '$')
     {
-      unsigned int len;
+      if (!CPP_OPTION (pfile, dollars_in_ident))
+       return false;
 
-      base = parse_slow (pfile, cur, 0, &len);
-      result = (cpp_hashnode *)
-       ht_lookup (pfile->hash_table, base, len, HT_ALLOCED);
+      buffer->cur++;
+      if (CPP_OPTION (pfile, warn_dollars) && !pfile->state.skipping)
+       {
+         CPP_OPTION (pfile, warn_dollars) = 0;
+         cpp_error (pfile, CPP_DL_PEDWARN, "'$' in identifier or number");
+       }
+
+      return true;
     }
-  else
+
+  /* Is this a syntactically valid UCN?  */
+  if (0 && *buffer->cur == '\\'
+      && (buffer->cur[1] == 'u' || buffer->cur[1] == 'U'))
+    {
+      buffer->cur += 2;
+      if (_cpp_valid_ucn (pfile, &buffer->cur, buffer->rlimit, 1 + !first))
+       return true;
+      buffer->cur -= 2;
+    }
+
+  return false;
+}
+
+/* Lex an identifier starting at BUFFER->CUR - 1.  */
+static cpp_hashnode *
+lex_identifier (cpp_reader *pfile, const uchar *base)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+
+  do
     {
-      base = pfile->buffer->cur - 1;
+      cur = pfile->buffer->cur;
+
+      /* N.B. ISIDNUM does not include $.  */
+      while (ISIDNUM (*cur))
+       cur++;
+
       pfile->buffer->cur = cur;
-      result = (cpp_hashnode *)
-       ht_lookup (pfile->hash_table, base, cur - base, HT_ALLOC);
     }
+  while (forms_identifier_p (pfile, false));
+
+  result = (cpp_hashnode *)
+    ht_lookup (pfile->hash_table, base, cur - base, HT_ALLOC);
 
-  /* Rarely, identifiers require diagnostics when lexed.
-     XXX Has to be forced out of the fast path.  */
+  /* Rarely, identifiers require diagnostics when lexed.  */
   if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
                        && !pfile->state.skipping, 0))
     {
       /* It is allowed to poison the same identifier twice.  */
       if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
-       cpp_error (pfile, DL_ERROR, "attempt to use poisoned \"%s\"",
+       cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
                   NODE_NAME (result));
 
       /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
         replacement list of a variadic macro.  */
       if (result == pfile->spec_nodes.n__VA_ARGS__
          && !pfile->state.va_args_ok)
-       cpp_error (pfile, DL_PEDWARN,
-       "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro");
+       cpp_error (pfile, CPP_DL_PEDWARN,
+                  "__VA_ARGS__ can only appear in the expansion"
+                  " of a C99 variadic macro");
     }
 
   return result;
 }
 
-/* Slow path.  This handles numbers and identifiers which have been
-   split, or contain dollar signs.  The part of the token from
-   PFILE->buffer->cur-1 to CUR has already been scanned.  NUMBER_P is
-   1 if it's a number, and 2 if it has a leading period.  Returns a
-   pointer to the token's NUL-terminated spelling in permanent
-   storage, and sets PLEN to its length.  */
-static uchar *
-parse_slow (pfile, cur, number_p, plen)
-     cpp_reader *pfile;
-     const uchar *cur;
-     int number_p;
-     unsigned int *plen;
-{
-  cpp_buffer *buffer = pfile->buffer;
-  const uchar *base = buffer->cur - 1;
-  struct obstack *stack = &pfile->hash_table->stack;
-  unsigned int c, prevc, saw_dollar = 0;
-
-  /* Place any leading period.  */
-  if (number_p == 2)
-    obstack_1grow (stack, '.');
-
-  /* Copy the part of the token which is known to be okay.  */
-  obstack_grow (stack, base, cur - base);
-
-  /* Now process the part which isn't.  We are looking at one of
-     '$', '\\', or '?' on entry to this loop.  */
-  prevc = cur[-1];
-  c = *cur++;
-  buffer->cur = cur;
-  for (;;)
-    {
-      /* Potential escaped newline?  */
-      buffer->backup_to = buffer->cur - 1;
-      if (c == '?' || c == '\\')
-       c = skip_escaped_newlines (pfile);
-
-      if (!is_idchar (c))
-       {
-         if (!number_p)
-           break;
-         if (c != '.' && !VALID_SIGN (c, prevc))
-           break;
-       }
-
-      /* Handle normal identifier characters in this loop.  */
-      do
-       {
-         prevc = c;
-         obstack_1grow (stack, c);
-
-         if (c == '$')
-           saw_dollar++;
-
-         c = *buffer->cur++;
-       }
-      while (is_idchar (c));
-    }
-
-  /* Step back over the unwanted char.  */
-  BACKUP ();
-
-  /* $ is not an identifier character in the standard, but is commonly
-     accepted as an extension.  Don't warn about it in skipped
-     conditional blocks.  */
-  if (saw_dollar && CPP_PEDANTIC (pfile) && ! pfile->state.skipping)
-    cpp_error (pfile, DL_PEDWARN, "'$' character(s) in identifier or number");
-
-  /* Identifiers and numbers are null-terminated.  */
-  *plen = obstack_object_size (stack);
-  obstack_1grow (stack, '\0');
-  return obstack_finish (stack);
-}
-
 /* SDCC specific */
 /* Pedantic parse a number, beginning with character C, skipping embedded
    backslash-newlines.  LEADING_PERIOD is nonzero if there was a "."
    before C.  Place the result in NUMBER.  */
 static void
-pedantic_parse_number (pfile, number, leading_period)
-     cpp_reader *pfile;
-     cpp_string *number;
-     int leading_period;
+pedantic_lex_number (cpp_reader *pfile, cpp_string *number)
 {
+#define get_effective_char(pfile) (*pfile->buffer->cur++)
+#define BACKUP() (--pfile->buffer->cur)
+
   enum num_type_e { NT_DEC, NT_HEX } num_type = NT_DEC;
   enum num_part_e { NP_WHOLE, NP_FRACT, NP_EXP, NP_INT_SUFFIX, NP_FLOAT_SUFFIX } num_part = NP_WHOLE;
 
@@ -635,7 +570,7 @@ pedantic_parse_number (pfile, number, leading_period)
   int has_whole = 0;
   int has_fract = 0;
 
-  if (leading_period)
+  if ('.' == c)
     {
       num_part = NP_FRACT;
       ++len;
@@ -858,173 +793,99 @@ pedantic_parse_number (pfile, number, leading_period)
   number->len = len;
 }
 
-/* Parse a number, beginning with character C, skipping embedded
-   backslash-newlines.  LEADING_PERIOD is nonzero if there was a "."
-   before C.  Place the result in NUMBER.  */
+/* Lex a number to NUMBER starting at BUFFER->CUR - 1.  */
 static void
-parse_number (pfile, number, leading_period)
-     cpp_reader *pfile;
-     cpp_string *number;
-     int leading_period;
+lex_number (cpp_reader *pfile, cpp_string *number)
 {
   const uchar *cur;
+  const uchar *base;
+  uchar *dest;
 
-  /* Fast-path loop.  Skim over a normal number.
-     N.B. ISIDNUM does not include $.  */
-  cur = pfile->buffer->cur;
-  while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1]))
-    cur++;
-
-  /* Check for slow-path cases.  */
-  if (*cur == '?' || *cur == '\\' || *cur == '$')
-    number->text = parse_slow (pfile, cur, 1 + leading_period, &number->len);
-  else
+  base = pfile->buffer->cur - 1;
+  do
     {
-      const uchar *base = pfile->buffer->cur - 1;
-      uchar *dest;
+      cur = pfile->buffer->cur;
 
-      number->len = cur - base + leading_period;
-      dest = _cpp_unaligned_alloc (pfile, number->len + 1);
-      dest[number->len] = '\0';
-      number->text = dest;
+      /* N.B. ISIDNUM does not include $.  */
+      while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1]))
+       cur++;
 
-      if (leading_period)
-       *dest++ = '.';
-      memcpy (dest, base, cur - base);
       pfile->buffer->cur = cur;
     }
+  while (forms_identifier_p (pfile, false));
+
+  number->len = cur - base;
+  dest = _cpp_unaligned_alloc (pfile, number->len + 1);
+  memcpy (dest, base, number->len);
+  dest[number->len] = '\0';
+  number->text = dest;
 }
 
-/* Subroutine of parse_string.  */
-static int
-unescaped_terminator_p (pfile, dest)
-     cpp_reader *pfile;
-     const unsigned char *dest;
+/* Create a token of type TYPE with a literal spelling.  */
+static void
+create_literal (cpp_reader *pfile, cpp_token *token, const uchar *base,
+               unsigned int len, enum cpp_ttype type)
 {
-  const unsigned char *start, *temp;
-
-  /* In #include-style directives, terminators are not escapeable.  */
-  if (pfile->state.angled_headers)
-    return 1;
+  uchar *dest = _cpp_unaligned_alloc (pfile, len + 1);
 
-  start = BUFF_FRONT (pfile->u_buff);
-
-  /* An odd number of consecutive backslashes represents an escaped
-     terminator.  */
-  for (temp = dest; temp > start && temp[-1] == '\\'; temp--)
-    ;
-
-  return ((dest - temp) & 1) == 0;
+  memcpy (dest, base, len);
+  dest[len] = '\0';
+  token->type = type;
+  token->val.str.len = len;
+  token->val.str.text = dest;
 }
 
-/* Parses a string, character constant, or angle-bracketed header file
-   name.  Handles embedded trigraphs and escaped newlines.  The stored
-   string is guaranteed NUL-terminated, but it is not guaranteed that
-   this is the first NUL since embedded NULs are preserved.
+/* Lexes a string, character constant, or angle-bracketed header file
+   name.  The stored string contains the spelling, including opening
+   quote and leading any leading 'L'.  It returns the type of the
+   literal, or CPP_OTHER if it was not properly terminated.
 
-   When this function returns, buffer->cur points to the next
-   character to be processed.  */
+   The spelling is NUL-terminated, but it is not guaranteed that this
+   is the first NUL since embedded NULs are preserved.  */
 static void
-parse_string (pfile, token, terminator)
-     cpp_reader *pfile;
-     cpp_token *token;
-     cppchar_t terminator;
+lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
 {
-  cpp_buffer *buffer = pfile->buffer;
-  unsigned char *dest, *limit;
-  cppchar_t c;
-  bool warned_nulls = false;
-#ifdef MULTIBYTE_CHARS
-  wchar_t wc;
-  int char_len;
-#endif
-
-  dest = BUFF_FRONT (pfile->u_buff);
-  limit = BUFF_LIMIT (pfile->u_buff);
+  bool saw_NUL = false;
+  const uchar *cur;
+  cppchar_t terminator;
+  enum cpp_ttype type;
+
+  cur = base;
+  terminator = *cur++;
+  if (terminator == 'L')
+    terminator = *cur++;
+  if (terminator == '\"')
+    type = *base == 'L' ? CPP_WSTRING: CPP_STRING;
+  else if (terminator == '\'')
+    type = *base == 'L' ? CPP_WCHAR: CPP_CHAR;
+  else
+    terminator = '>', type = CPP_HEADER_NAME;
 
-#ifdef MULTIBYTE_CHARS
-  /* Reset multibyte conversion state.  */
-  (void) local_mbtowc (NULL, NULL, 0);
-#endif
   for (;;)
     {
-      /* We need room for another char, possibly the terminating NUL.  */
-      if ((size_t) (limit - dest) < 1)
-       {
-         size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff);
-         _cpp_extend_buff (pfile, &pfile->u_buff, 2);
-         dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
-         limit = BUFF_LIMIT (pfile->u_buff);
-       }
-
-#ifdef MULTIBYTE_CHARS
-      char_len = local_mbtowc (&wc, (const char *) buffer->cur,
-                              buffer->rlimit - buffer->cur);
-      if (char_len == -1)
-       {
-         cpp_error (pfile, DL_WARNING,
-                    "ignoring invalid multibyte character");
-         char_len = 1;
-         c = *buffer->cur++;
-       }
-      else
-       {
-         buffer->cur += char_len;
-         c = wc;
-       }
-#else
-      c = *buffer->cur++;
-#endif
-
-      /* Handle trigraphs, escaped newlines etc.  */
-      if (c == '?' || c == '\\')
-       c = skip_escaped_newlines (pfile);
+      cppchar_t c = *cur++;
 
-      if (c == terminator)
-       {
-         if (unescaped_terminator_p (pfile, dest))
-           break;
-       }
-      else if (is_vspace (c))
+      /* In #include-style directives, terminators are not escapable.  */
+      if (c == '\\' && !pfile->state.angled_headers && *cur != '\n')
+       cur++;
+      else if (c == terminator)
+       break;
+      else if (c == '\n')
        {
-         /* No string literal may extend over multiple lines.  In
-            assembly language, suppress the error except for <>
-            includes.  This is a kludge around not knowing where
-            comments are.  */
-       unterminated:
-         if (CPP_OPTION (pfile, lang) != CLK_ASM || terminator == '>')
-           cpp_error (pfile, DL_ERROR, "missing terminating %c character",
-                      (int) terminator);
-         buffer->cur--;
+         cur--;
+         type = CPP_OTHER;
          break;
        }
       else if (c == '\0')
-       {
-         if (buffer->cur - 1 == buffer->rlimit)
-           goto unterminated;
-         if (!warned_nulls)
-           {
-             warned_nulls = true;
-             cpp_error (pfile, DL_WARNING,
-                        "null character(s) preserved in literal");
-           }
-       }
-#ifdef MULTIBYTE_CHARS
-      if (char_len > 1)
-       {
-         for ( ; char_len > 0; --char_len)
-           *dest++ = (*buffer->cur - char_len);
-       }
-      else
-#endif
-       *dest++ = c;
+       saw_NUL = true;
     }
 
-  *dest = '\0';
+  if (saw_NUL && !pfile->state.skipping)
+    cpp_error (pfile, CPP_DL_WARNING,
+              "null character(s) preserved in literal");
 
-  token->val.str.text = BUFF_FRONT (pfile->u_buff);
-  token->val.str.len = dest - BUFF_FRONT (pfile->u_buff);
-  BUFF_FRONT (pfile->u_buff) = dest + 1;
+  pfile->buffer->cur = cur;
+  create_literal (pfile, token, base, cur - base, type);
 }
 
 /* Fixed _WIN32 problem with CR-CR-LF sequences when outputting
@@ -1035,10 +896,7 @@ parse_string (pfile, token, terminator)
    CRs are automatically generated, because the output is
    opened in TEXT mode. If dest == NULL, only count chars */
 static unsigned int
-copy_text_chars (dest, src, len)
-     char *dest;
-     const char *src;
-     unsigned int len;
+copy_text_chars (char *dest, const char *src, unsigned int len)
 {
   unsigned int n = 0;
   const char *p;
@@ -1061,10 +919,7 @@ copy_text_chars (dest, src, len)
 /* SDCC _asm specific */
 /* The stored comment includes the comment start and any terminator.  */
 static void
-save_asm (pfile, token, from)
-     cpp_reader *pfile;
-     cpp_token *token;
-     const unsigned char *from;
+save_asm (cpp_reader *pfile, cpp_token *token, const unsigned char *from)
 {
 #define _ASM_STR  "_asm"
 #define _ASM_LEN  ((sizeof _ASM_STR) - 1)
@@ -1088,11 +943,8 @@ save_asm (pfile, token, from)
 
 /* The stored comment includes the comment start and any terminator.  */
 static void
-save_comment (pfile, token, from, type)
-     cpp_reader *pfile;
-     cpp_token *token;
-     const unsigned char *from;
-     cppchar_t type;
+save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from,
+             cppchar_t type)
 {
   unsigned char *buffer;
   unsigned int len, clen;
@@ -1132,9 +984,7 @@ save_comment (pfile, token, from, type)
 
 /* Allocate COUNT tokens for RUN.  */
 void
-_cpp_init_tokenrun (run, count)
-     tokenrun *run;
-     unsigned int count;
+_cpp_init_tokenrun (tokenrun *run, unsigned int count)
 {
   run->base = xnewvec (cpp_token, count);
   run->limit = run->base + count;
@@ -1143,8 +993,7 @@ _cpp_init_tokenrun (run, count)
 
 /* Returns the next tokenrun, or creates one if there is none.  */
 static tokenrun *
-next_tokenrun (run)
-     tokenrun *run;
+next_tokenrun (tokenrun *run)
 {
   if (run->next == NULL)
     {
@@ -1161,8 +1010,7 @@ next_tokenrun (run)
    same as the last lexed token, so that diagnostics appear in the
    right place.  */
 cpp_token *
-_cpp_temp_token (pfile)
-     cpp_reader *pfile;
+_cpp_temp_token (cpp_reader *pfile)
 {
   cpp_token *old, *result;
 
@@ -1183,8 +1031,7 @@ _cpp_temp_token (pfile)
    like directive handling, token lookahead, multiple include
    optimization and skipping.  */
 const cpp_token *
-_cpp_lex_token (pfile)
-     cpp_reader *pfile;
+_cpp_lex_token (cpp_reader *pfile)
 {
   cpp_token *result;
 
@@ -1216,7 +1063,7 @@ _cpp_lex_token (pfile)
              && _cpp_handle_directive (pfile, result->flags & PREV_WHITE))
            continue;
          if (pfile->cb.line_change && !pfile->state.skipping)
-           (*pfile->cb.line_change)(pfile, result, pfile->state.parsing_args);
+           pfile->cb.line_change (pfile, result, pfile->state.parsing_args);
        }
 
       /* We don't skip tokens in directives.  */
@@ -1225,7 +1072,7 @@ _cpp_lex_token (pfile)
 
       /* Outside a directive, invalidate controlling macros.  At file
         EOF, _cpp_lex_direct takes care of popping the buffer, so we never
-        get here and MI optimisation works.  */
+        get here and MI optimization works.  */
       pfile->mi_valid = false;
 
       if (!pfile->state.skipping || result->type == CPP_EOF)
@@ -1235,73 +1082,66 @@ _cpp_lex_token (pfile)
   return result;
 }
 
-/* A NUL terminates the current buffer.  For ISO preprocessing this is
-   EOF, but for traditional preprocessing it indicates we need a line
-   refill.  Returns TRUE to continue preprocessing a new buffer, FALSE
-   to return a CPP_EOF to the caller.  */
-static bool
-continue_after_nul (pfile)
-     cpp_reader *pfile;
+/* Returns true if a fresh line has been loaded.  */
+bool
+_cpp_get_fresh_line (cpp_reader *pfile)
 {
-  cpp_buffer *buffer = pfile->buffer;
-  bool more = false;
+  int return_at_eof;
 
-  buffer->saved_flags = BOL;
-  if (CPP_OPTION (pfile, traditional))
-    {
-      if (pfile->state.in_directive)
-       return false;
+  /* We can't get a new line until we leave the current directive.  */
+  if (pfile->state.in_directive)
+    return false;
 
-      _cpp_remove_overlay (pfile);
-      more = _cpp_read_logical_line_trad (pfile);
-      _cpp_overlay_buffer (pfile, pfile->out.base,
-                          pfile->out.cur - pfile->out.base);
-      pfile->line = pfile->out.first_line;
-    }
-  else
+  for (;;)
     {
-      /* Stop parsing arguments with a CPP_EOF.  When we finally come
-        back here, do the work of popping the buffer.  */
-      if (!pfile->state.parsing_args)
+      cpp_buffer *buffer = pfile->buffer;
+
+      if (!buffer->need_line)
+       return true;
+
+      if (buffer->next_line < buffer->rlimit)
        {
-         if (buffer->cur != buffer->line_base)
-           {
-             /* Non-empty files should end in a newline.  Don't warn
-                for command line and _Pragma buffers.  */
-             if (!buffer->from_stage3)
-               cpp_error (pfile, DL_PEDWARN, "no newline at end of file");
-             handle_newline (pfile);
-           }
+         _cpp_clean_line (pfile);
+         return true;
+       }
 
-         /* Similarly, finish an in-progress directive with CPP_EOF
-            before popping the buffer.  */
-         if (!pfile->state.in_directive && buffer->prev)
-           {
-             more = !buffer->return_at_eof;
-             _cpp_pop_buffer (pfile);
-           }
+      /* First, get out of parsing arguments state.  */
+      if (pfile->state.parsing_args)
+       return false;
+
+      /* End of buffer.  Non-empty files should end in a newline.  */
+      if (buffer->buf != buffer->rlimit
+         && buffer->next_line > buffer->rlimit
+         && !buffer->from_stage3)
+       {
+         /* Only warn once.  */
+         buffer->next_line = buffer->rlimit;
+         cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line - 1,
+                              CPP_BUF_COLUMN (buffer, buffer->cur),
+                              "no newline at end of file");
        }
-    }
 
-  return more;
+      return_at_eof = buffer->return_at_eof;
+      _cpp_pop_buffer (pfile);
+      if (pfile->buffer == NULL || return_at_eof)
+       return false;
+    }
 }
 
-#define IF_NEXT_IS(CHAR, THEN_TYPE, ELSE_TYPE) \
-  do {                                         \
-    if (get_effective_char (pfile) == CHAR)    \
-      result->type = THEN_TYPE;                        \
-    else                                       \
-      {                                                \
-        BACKUP ();                             \
-        result->type = ELSE_TYPE;              \
-      }                                                \
-  } while (0)
+#define IF_NEXT_IS(CHAR, THEN_TYPE, ELSE_TYPE)         \
+  do                                                   \
+    {                                                  \
+      result->type = ELSE_TYPE;                                \
+      if (*buffer->cur == CHAR)                                \
+       buffer->cur++, result->type = THEN_TYPE;        \
+    }                                                  \
+  while (0)
 
 /* Lex a token into pfile->cur_token, which is also incremented, to
    get diagnostics pointing to the correct location.
 
    Does not handle issues such as token lookahead, multiple-include
-   optimisation, directives, skipping etc.  This function is only
+   optimization, directives, skipping etc.  This function is only
    suitable for use by _cpp_lex_token, and in special cases like
    lex_expansion_token which doesn't care for any of these issues.
 
@@ -1309,8 +1149,7 @@ continue_after_nul (pfile)
    otherwise returns to the start of the token buffer if permissible.
    Returns the location of the lexed token.  */
 cpp_token *
-_cpp_lex_direct (pfile)
-     cpp_reader *pfile;
+_cpp_lex_direct (cpp_reader *pfile)
 {
   cppchar_t c;
   cpp_buffer *buffer;
@@ -1318,101 +1157,75 @@ _cpp_lex_direct (pfile)
   cpp_token *result = pfile->cur_token++;
 
  fresh_line:
+  result->flags = 0;
+  buffer = pfile->buffer;
+  if (buffer->need_line)
+    {
+      if (!_cpp_get_fresh_line (pfile))
+       {
+         result->type = CPP_EOF;
+         if (!pfile->state.in_directive)
+           {
+             /* Tell the compiler the line number of the EOF token.  */
+             result->line = pfile->line;
+             result->flags = BOL;
+           }
+         return result;
+       }
+      if (!pfile->keep_tokens)
+       {
+         pfile->cur_run = &pfile->base_run;
+         result = pfile->base_run.base;
+         pfile->cur_token = result + 1;
+       }
+      result->flags = BOL;
+      if (pfile->state.parsing_args == 2)
+       result->flags |= PREV_WHITE;
+    }
   buffer = pfile->buffer;
-  result->flags = buffer->saved_flags;
-  buffer->saved_flags = 0;
  update_tokens_line:
   result->line = pfile->line;
 
  skipped_white:
+  if (buffer->cur >= buffer->notes[buffer->cur_note].pos
+      && !pfile->overlaid_buffer)
+    {
+      _cpp_process_line_notes (pfile, false);
+      result->line = pfile->line;
+    }
   c = *buffer->cur++;
   result->col = CPP_BUF_COLUMN (buffer, buffer->cur);
 
- trigraph:
   switch (c)
     {
     case ' ': case '\t': case '\f': case '\v': case '\0':
       result->flags |= PREV_WHITE;
-      if (skip_whitespace (pfile, c))
-       goto skipped_white;
-
-      /* End of buffer.  */
-      buffer->cur--;
-      if (continue_after_nul (pfile))
-       goto fresh_line;
-      result->type = CPP_EOF;
-      break;
+      skip_whitespace (pfile, c);
+      goto skipped_white;
 
-    case '\n': case '\r':
-      handle_newline (pfile);
-      buffer->saved_flags = BOL;
-      if (! pfile->state.in_directive)
-       {
-         if (pfile->state.parsing_args == 2)
-           buffer->saved_flags |= PREV_WHITE;
-         if (!pfile->keep_tokens)
-           {
-             pfile->cur_run = &pfile->base_run;
-             result = pfile->base_run.base;
-             pfile->cur_token = result + 1;
-           }
-         goto fresh_line;
-       }
-      result->type = CPP_EOF;
-      break;
-
-    case '?':
-    case '\\':
-      /* These could start an escaped newline, or '?' a trigraph.  Let
-        skip_escaped_newlines do all the work.  */
-      {
-       unsigned int line = pfile->line;
-
-       c = skip_escaped_newlines (pfile);
-       if (line != pfile->line)
-         {
-           buffer->cur--;
-           /* We had at least one escaped newline of some sort.
-              Update the token's line and column.  */
-           goto update_tokens_line;
-         }
-      }
-
-      /* We are either the original '?' or '\\', or a trigraph.  */
-      if (c == '?')
-       result->type = CPP_QUERY;
-      else if (c == '\\')
-       goto random_char;
-      else
-       goto trigraph;
-      break;
+    case '\n':
+      pfile->line++;
+      buffer->need_line = true;
+      goto fresh_line;
 
     case '0': case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9':
       result->type = CPP_NUMBER;
       if (CPP_OPTION(pfile, pedantic_parse_number))
-        pedantic_parse_number (pfile, &result->val.str, 0);
+        pedantic_lex_number (pfile, &result->val.str);
       else
-        parse_number (pfile, &result->val.str, 0);
+        lex_number (pfile, &result->val.str);
       break;
 
     case 'L':
       /* 'L' may introduce wide characters or strings.  */
-      {
-       const unsigned char *pos = buffer->cur;
-
-       c = get_effective_char (pfile);
-       if (c == '\'' || c == '"')
-         {
-           result->type = (c == '"' ? CPP_WSTRING: CPP_WCHAR);
-           parse_string (pfile, result, c);
-           break;
-         }
-       buffer->cur = pos;
-      }
+      if (*buffer->cur == '\'' || *buffer->cur == '"')
+       {
+         lex_string (pfile, result, buffer->cur - 1);
+         break;
+       }
       /* Fall through.  */
 
-    start_ident:
     case '_':
     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
@@ -1425,7 +1238,7 @@ _cpp_lex_direct (pfile)
     case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
     case 'Y': case 'Z':
       result->type = CPP_NAME;
-      result->val.node = parse_identifier (pfile);
+      result->val.node = lex_identifier (pfile, buffer->cur - 1);
 
       /* SDCC _asm specific */
       /* handle _asm ... _endasm ;  */
@@ -1441,25 +1254,24 @@ _cpp_lex_direct (pfile)
       else if (result->val.node->flags & NODE_OPERATOR)
        {
          result->flags |= NAMED_OP;
-         result->type = result->val.node->value.operator;
+         result->type = result->val.node->directive_index;
        }
       break;
 
     case '\'':
     case '"':
-      result->type = c == '"' ? CPP_STRING: CPP_CHAR;
-      parse_string (pfile, result, c);
+      lex_string (pfile, result, buffer->cur - 1);
       break;
 
     case '/':
       /* A potential block or line comment.  */
       comment_start = buffer->cur;
-      c = get_effective_char (pfile);
+      c = *buffer->cur;
 
       if (c == '*')
        {
-         if (skip_block_comment (pfile))
-           cpp_error (pfile, DL_ERROR, "unterminated comment");
+         if (_cpp_skip_block_comment (pfile))
+           cpp_error (pfile, CPP_DL_ERROR, "unterminated comment");
        }
       else if (c == '/' && (CPP_OPTION (pfile, cplusplus_comments)
                            || CPP_IN_SYSTEM_HEADER (pfile)))
@@ -1469,24 +1281,24 @@ _cpp_lex_direct (pfile)
          if (CPP_OPTION (pfile, lang) == CLK_GNUC89 && CPP_PEDANTIC (pfile)
              && ! buffer->warned_cplusplus_comments)
            {
-             cpp_error (pfile, DL_PEDWARN,
+             cpp_error (pfile, CPP_DL_PEDWARN,
                         "C++ style comments are not allowed in ISO C90");
-             cpp_error (pfile, DL_PEDWARN,
+             cpp_error (pfile, CPP_DL_PEDWARN,
                         "(this will be reported only once per input file)");
              buffer->warned_cplusplus_comments = 1;
            }
 
          if (skip_line_comment (pfile) && CPP_OPTION (pfile, warn_comments))
-           cpp_error (pfile, DL_WARNING, "multi-line comment");
+           cpp_error (pfile, CPP_DL_WARNING, "multi-line comment");
        }
       else if (c == '=')
        {
+         buffer->cur++;
          result->type = CPP_DIV_EQ;
          break;
        }
       else
        {
-         BACKUP ();
          result->type = CPP_DIV;
          break;
        }
@@ -1504,186 +1316,144 @@ _cpp_lex_direct (pfile)
     case '<':
       if (pfile->state.angled_headers)
        {
-         result->type = CPP_HEADER_NAME;
-         parse_string (pfile, result, '>');
+         lex_string (pfile, result, buffer->cur - 1);
          break;
        }
 
-      c = get_effective_char (pfile);
-      if (c == '=')
-       result->type = CPP_LESS_EQ;
-      else if (c == '<')
-       IF_NEXT_IS ('=', CPP_LSHIFT_EQ, CPP_LSHIFT);
-      else if (c == '?' && CPP_OPTION (pfile, cplusplus))
-       IF_NEXT_IS ('=', CPP_MIN_EQ, CPP_MIN);
-      else if (c == ':' && CPP_OPTION (pfile, digraphs))
+      result->type = CPP_LESS;
+      if (*buffer->cur == '=')
+       buffer->cur++, result->type = CPP_LESS_EQ;
+      else if (*buffer->cur == '<')
        {
-         result->type = CPP_OPEN_SQUARE;
-         result->flags |= DIGRAPH;
+         buffer->cur++;
+         IF_NEXT_IS ('=', CPP_LSHIFT_EQ, CPP_LSHIFT);
        }
-      else if (c == '%' && CPP_OPTION (pfile, digraphs))
+      else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus))
        {
-         result->type = CPP_OPEN_BRACE;
-         result->flags |= DIGRAPH;
+         buffer->cur++;
+         IF_NEXT_IS ('=', CPP_MIN_EQ, CPP_MIN);
        }
-      else
+      else if (CPP_OPTION (pfile, digraphs))
        {
-         BACKUP ();
-         result->type = CPP_LESS;
+         if (*buffer->cur == ':')
+           {
+             buffer->cur++;
+             result->flags |= DIGRAPH;
+             result->type = CPP_OPEN_SQUARE;
+           }
+         else if (*buffer->cur == '%')
+           {
+             buffer->cur++;
+             result->flags |= DIGRAPH;
+             result->type = CPP_OPEN_BRACE;
+           }
        }
       break;
 
     case '>':
-      c = get_effective_char (pfile);
-      if (c == '=')
-       result->type = CPP_GREATER_EQ;
-      else if (c == '>')
-       IF_NEXT_IS ('=', CPP_RSHIFT_EQ, CPP_RSHIFT);
-      else if (c == '?' && CPP_OPTION (pfile, cplusplus))
-       IF_NEXT_IS ('=', CPP_MAX_EQ, CPP_MAX);
-      else
+      result->type = CPP_GREATER;
+      if (*buffer->cur == '=')
+       buffer->cur++, result->type = CPP_GREATER_EQ;
+      else if (*buffer->cur == '>')
        {
-         BACKUP ();
-         result->type = CPP_GREATER;
+         buffer->cur++;
+         IF_NEXT_IS ('=', CPP_RSHIFT_EQ, CPP_RSHIFT);
+       }
+      else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus))
+       {
+         buffer->cur++;
+         IF_NEXT_IS ('=', CPP_MAX_EQ, CPP_MAX);
        }
       break;
 
     case '%':
-      c = get_effective_char (pfile);
-      if (c == '=')
-       result->type = CPP_MOD_EQ;
-      else if (CPP_OPTION (pfile, digraphs) && c == ':')
+      result->type = CPP_MOD;
+      if (*buffer->cur == '=')
+       buffer->cur++, result->type = CPP_MOD_EQ;
+      else if (CPP_OPTION (pfile, digraphs))
        {
-         result->flags |= DIGRAPH;
-         result->type = CPP_HASH;
-         if (get_effective_char (pfile) == '%')
+         if (*buffer->cur == ':')
            {
-             const unsigned char *pos = buffer->cur;
-
-             if (get_effective_char (pfile) == ':')
-               result->type = CPP_PASTE;
-             else
-               buffer->cur = pos - 1;
+             buffer->cur++;
+             result->flags |= DIGRAPH;
+             result->type = CPP_HASH;
+             if (*buffer->cur == '%' && buffer->cur[1] == ':')
+               buffer->cur += 2, result->type = CPP_PASTE;
+           }
+         else if (*buffer->cur == '>')
+           {
+             buffer->cur++;
+             result->flags |= DIGRAPH;
+             result->type = CPP_CLOSE_BRACE;
            }
-         else
-           BACKUP ();
-       }
-      else if (CPP_OPTION (pfile, digraphs) && c == '>')
-       {
-         result->flags |= DIGRAPH;
-         result->type = CPP_CLOSE_BRACE;
-       }
-      else
-       {
-         BACKUP ();
-         result->type = CPP_MOD;
        }
       break;
 
     case '.':
       result->type = CPP_DOT;
-      c = get_effective_char (pfile);
-      if (c == '.')
-       {
-         const unsigned char *pos = buffer->cur;
-
-         if (get_effective_char (pfile) == '.')
-           result->type = CPP_ELLIPSIS;
-         else
-           buffer->cur = pos - 1;
-       }
-      /* All known character sets have 0...9 contiguous.  */
-      else if (ISDIGIT (c))
+      if (ISDIGIT (*buffer->cur))
        {
          result->type = CPP_NUMBER;
           if (CPP_OPTION(pfile, pedantic_parse_number))
-            pedantic_parse_number (pfile, &result->val.str, 1);
+            pedantic_lex_number (pfile, &result->val.str);
           else
-           parse_number (pfile, &result->val.str, 1);
+            lex_number (pfile, &result->val.str);
        }
-      else if (c == '*' && CPP_OPTION (pfile, cplusplus))
-       result->type = CPP_DOT_STAR;
-      else
-       BACKUP ();
+      else if (*buffer->cur == '.' && buffer->cur[1] == '.')
+       buffer->cur += 2, result->type = CPP_ELLIPSIS;
+      else if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus))
+       buffer->cur++, result->type = CPP_DOT_STAR;
       break;
 
     case '+':
-      c = get_effective_char (pfile);
-      if (c == '+')
-       result->type = CPP_PLUS_PLUS;
-      else if (c == '=')
-       result->type = CPP_PLUS_EQ;
-      else
-       {
-         BACKUP ();
-         result->type = CPP_PLUS;
-       }
+      result->type = CPP_PLUS;
+      if (*buffer->cur == '+')
+       buffer->cur++, result->type = CPP_PLUS_PLUS;
+      else if (*buffer->cur == '=')
+       buffer->cur++, result->type = CPP_PLUS_EQ;
       break;
 
     case '-':
-      c = get_effective_char (pfile);
-      if (c == '>')
+      result->type = CPP_MINUS;
+      if (*buffer->cur == '>')
        {
+         buffer->cur++;
          result->type = CPP_DEREF;
-         if (CPP_OPTION (pfile, cplusplus))
-           {
-             if (get_effective_char (pfile) == '*')
-               result->type = CPP_DEREF_STAR;
-             else
-               BACKUP ();
-           }
-       }
-      else if (c == '-')
-       result->type = CPP_MINUS_MINUS;
-      else if (c == '=')
-       result->type = CPP_MINUS_EQ;
-      else
-       {
-         BACKUP ();
-         result->type = CPP_MINUS;
+         if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus))
+           buffer->cur++, result->type = CPP_DEREF_STAR;
        }
+      else if (*buffer->cur == '-')
+       buffer->cur++, result->type = CPP_MINUS_MINUS;
+      else if (*buffer->cur == '=')
+       buffer->cur++, result->type = CPP_MINUS_EQ;
       break;
 
     case '&':
-      c = get_effective_char (pfile);
-      if (c == '&')
-       result->type = CPP_AND_AND;
-      else if (c == '=')
-       result->type = CPP_AND_EQ;
-      else
-       {
-         BACKUP ();
-         result->type = CPP_AND;
-       }
+      result->type = CPP_AND;
+      if (*buffer->cur == '&')
+       buffer->cur++, result->type = CPP_AND_AND;
+      else if (*buffer->cur == '=')
+       buffer->cur++, result->type = CPP_AND_EQ;
       break;
 
     case '|':
-      c = get_effective_char (pfile);
-      if (c == '|')
-       result->type = CPP_OR_OR;
-      else if (c == '=')
-       result->type = CPP_OR_EQ;
-      else
-       {
-         BACKUP ();
-         result->type = CPP_OR;
-       }
+      result->type = CPP_OR;
+      if (*buffer->cur == '|')
+       buffer->cur++, result->type = CPP_OR_OR;
+      else if (*buffer->cur == '=')
+       buffer->cur++, result->type = CPP_OR_EQ;
       break;
 
     case ':':
-      c = get_effective_char (pfile);
-      if (c == ':' && CPP_OPTION (pfile, cplusplus))
-       result->type = CPP_SCOPE;
-      else if (c == '>' && CPP_OPTION (pfile, digraphs))
+      result->type = CPP_COLON;
+      if (*buffer->cur == ':' && CPP_OPTION (pfile, cplusplus))
+       buffer->cur++, result->type = CPP_SCOPE;
+      else if (*buffer->cur == '>' && CPP_OPTION (pfile, digraphs))
        {
+         buffer->cur++;
          result->flags |= DIGRAPH;
          result->type = CPP_CLOSE_SQUARE;
        }
-      else
-       {
-         BACKUP ();
-         result->type = CPP_COLON;
-       }
       break;
 
     case '*': IF_NEXT_IS ('=', CPP_MULT_EQ, CPP_MULT); break;
@@ -1692,6 +1462,7 @@ _cpp_lex_direct (pfile)
     case '^': IF_NEXT_IS ('=', CPP_XOR_EQ, CPP_XOR); break;
     case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); break;
 
+    case '?': result->type = CPP_QUERY; break;
     case '~': result->type = CPP_COMPL; break;
     case ',': result->type = CPP_COMMA; break;
     case '(': result->type = CPP_OPEN_PAREN; break;
@@ -1706,48 +1477,51 @@ _cpp_lex_direct (pfile)
     case '@': result->type = CPP_ATSIGN; break;
 
     case '$':
-      if (CPP_OPTION (pfile, dollars_in_ident))
-       goto start_ident;
-      /* Fall through...  */
+    case '\\':
+      {
+       const uchar *base = --buffer->cur;
+
+       if (forms_identifier_p (pfile, true))
+         {
+           result->type = CPP_NAME;
+           result->val.node = lex_identifier (pfile, base);
+           break;
+         }
+       buffer->cur++;
+      }
 
-    random_char:
     default:
-      result->type = CPP_OTHER;
-      result->val.c = c;
+      create_literal (pfile, result, buffer->cur - 1, 1, CPP_OTHER);
       break;
     }
 
   return result;
 }
 
-/* An upper bound on the number of bytes needed to spell TOKEN,
-   including preceding whitespace.  */
+/* An upper bound on the number of bytes needed to spell TOKEN.
+   Does not include preceding whitespace.  */
 unsigned int
-cpp_token_len (token)
-     const cpp_token *token;
+cpp_token_len (const cpp_token *token)
 {
   unsigned int len;
 
   switch (TOKEN_SPELL (token))
     {
-    default:           len = 0;                                break;
-    case SPELL_NUMBER:
-    case SPELL_STRING: len = token->val.str.len;               break;
+    default:           len = 4;                                break;
+    case SPELL_LITERAL:        len = token->val.str.len;               break;
     case SPELL_IDENT:  len = NODE_LEN (token->val.node);       break;
     }
-  /* 1 for whitespace, 4 for comment delimiters.  */
-  return len + 5;
+
+  return len;
 }
 
 /* Write the spelling of a token TOKEN to BUFFER.  The buffer must
    already contain the enough space to hold the token's spelling.
-   Returns a pointer to the character after the last character
-   written.  */
+   Returns a pointer to the character after the last character written.
+   FIXME: Would be nice if we didn't need the PFILE argument.  */
 unsigned char *
-cpp_spell_token (pfile, token, buffer)
-     cpp_reader *pfile;                /* Would be nice to be rid of this...  */
-     const cpp_token *token;
-     unsigned char *buffer;
+cpp_spell_token (cpp_reader *pfile, const cpp_token *token,
+                unsigned char *buffer)
 {
   switch (TOKEN_SPELL (token))
     {
@@ -1769,46 +1543,20 @@ cpp_spell_token (pfile, token, buffer)
       }
       break;
 
-    case SPELL_CHAR:
-      *buffer++ = token->val.c;
-      break;
-
     spell_ident:
     case SPELL_IDENT:
       memcpy (buffer, NODE_NAME (token->val.node), NODE_LEN (token->val.node));
       buffer += NODE_LEN (token->val.node);
       break;
 
-    case SPELL_NUMBER:
+    case SPELL_LITERAL:
       memcpy (buffer, token->val.str.text, token->val.str.len);
       buffer += token->val.str.len;
       break;
 
-    case SPELL_STRING:
-      {
-       int left, right, tag;
-       switch (token->type)
-         {
-         case CPP_STRING:      left = '"';  right = '"';  tag = '\0'; break;
-         case CPP_WSTRING:     left = '"';  right = '"';  tag = 'L';  break;
-         case CPP_CHAR:        left = '\''; right = '\''; tag = '\0'; break;
-         case CPP_WCHAR:       left = '\''; right = '\''; tag = 'L';  break;
-         case CPP_HEADER_NAME: left = '<';  right = '>';  tag = '\0'; break;
-         default:
-           cpp_error (pfile, DL_ICE, "unknown string token %s\n",
-                      TOKEN_NAME (token));
-           return buffer;
-         }
-       if (tag) *buffer++ = tag;
-       *buffer++ = left;
-       memcpy (buffer, token->val.str.text, token->val.str.len);
-       buffer += token->val.str.len;
-       *buffer++ = right;
-      }
-      break;
-
     case SPELL_NONE:
-      cpp_error (pfile, DL_ICE, "unspellable token %s", TOKEN_NAME (token));
+      cpp_error (pfile, CPP_DL_ICE,
+                "unspellable token %s", TOKEN_NAME (token));
       break;
     }
 
@@ -1818,11 +1566,9 @@ cpp_spell_token (pfile, token, buffer)
 /* Returns TOKEN spelt as a null-terminated string.  The string is
    freed when the reader is destroyed.  Useful for diagnostics.  */
 unsigned char *
-cpp_token_as_text (pfile, token)
-     cpp_reader *pfile;
-     const cpp_token *token;
+cpp_token_as_text (cpp_reader *pfile, const cpp_token *token)
 {
-  unsigned int len = cpp_token_len (token);
+  unsigned int len = cpp_token_len (token) + 1;
   unsigned char *start = _cpp_unaligned_alloc (pfile, len), *end;
 
   end = cpp_spell_token (pfile, token, start);
@@ -1834,8 +1580,7 @@ cpp_token_as_text (pfile, token)
 /* Used by C front ends, which really should move to using
    cpp_token_as_text.  */
 const char *
-cpp_type2name (type)
-     enum cpp_ttype type;
+cpp_type2name (enum cpp_ttype type)
 {
   return (const char *) token_spellings[type].name;
 }
@@ -1844,9 +1589,7 @@ cpp_type2name (type)
    Separated from cpp_spell_token for efficiency - to avoid stdio
    double-buffering.  */
 void
-cpp_output_token (token, fp)
-     const cpp_token *token;
-     FILE *fp;
+cpp_output_token (const cpp_token *token, FILE *fp)
 {
   switch (TOKEN_SPELL (token))
     {
@@ -1870,41 +1613,15 @@ cpp_output_token (token, fp)
       }
       break;
 
-    case SPELL_CHAR:
-      putc (token->val.c, fp);
-      break;
-
     spell_ident:
     case SPELL_IDENT:
       fwrite (NODE_NAME (token->val.node), 1, NODE_LEN (token->val.node), fp);
     break;
 
-    case SPELL_NUMBER:
+    case SPELL_LITERAL:
       fwrite (token->val.str.text, 1, token->val.str.len, fp);
       break;
 
-    case SPELL_STRING:
-      {
-       int left, right, tag;
-       switch (token->type)
-         {
-         case CPP_STRING:      left = '"';  right = '"';  tag = '\0'; break;
-         case CPP_WSTRING:     left = '"';  right = '"';  tag = 'L';  break;
-         case CPP_CHAR:        left = '\''; right = '\''; tag = '\0'; break;
-         case CPP_WCHAR:       left = '\''; right = '\''; tag = 'L';  break;
-         case CPP_HEADER_NAME: left = '<';  right = '>';  tag = '\0'; break;
-         case CPP_ASM:         left = '\0'; right = '\0'; tag = '\0'; break;
-          default:
-           fprintf (stderr, "impossible STRING token %s\n", TOKEN_NAME (token));
-           return;
-         }
-       if (tag) putc (tag, fp);
-       if (left) putc (left, fp);
-       fwrite (token->val.str.text, 1, token->val.str.len, fp);
-       if (right) putc (right, fp);
-      }
-      break;
-
     case SPELL_NONE:
       /* An error, most probably.  */
       break;
@@ -1913,8 +1630,7 @@ cpp_output_token (token, fp)
 
 /* Compare two tokens.  */
 int
-_cpp_equiv_tokens (a, b)
-     const cpp_token *a, *b;
+_cpp_equiv_tokens (const cpp_token *a, const cpp_token *b)
 {
   if (a->type == b->type && a->flags == b->flags)
     switch (TOKEN_SPELL (a))
@@ -1922,14 +1638,11 @@ _cpp_equiv_tokens (a, b)
       default:                 /* Keep compiler happy.  */
       case SPELL_OPERATOR:
        return 1;
-      case SPELL_CHAR:
-       return a->val.c == b->val.c; /* Character.  */
       case SPELL_NONE:
        return (a->type != CPP_MACRO_ARG || a->val.arg_no == b->val.arg_no);
       case SPELL_IDENT:
        return a->val.node == b->val.node;
-      case SPELL_NUMBER:
-      case SPELL_STRING:
+      case SPELL_LITERAL:
        return (a->val.str.len == b->val.str.len
                && !memcmp (a->val.str.text, b->val.str.text,
                            a->val.str.len));
@@ -1943,9 +1656,8 @@ _cpp_equiv_tokens (a, b)
    conservative, and occasionally advises a space where one is not
    needed, e.g. "." and ".2".  */
 int
-cpp_avoid_paste (pfile, token1, token2)
-     cpp_reader *pfile;
-     const cpp_token *token1, *token2;
+cpp_avoid_paste (cpp_reader *pfile, const cpp_token *token1,
+                const cpp_token *token2)
 {
   enum cpp_ttype a = token1->type, b = token2->type;
   cppchar_t c;
@@ -1985,9 +1697,12 @@ cpp_avoid_paste (pfile, token1, token2)
                                || b == CPP_CHAR || b == CPP_STRING); /* L */
     case CPP_NUMBER:   return (b == CPP_NUMBER || b == CPP_NAME
                                || c == '.' || c == '+' || c == '-');
-    case CPP_OTHER:    return (CPP_OPTION (pfile, objc)
-                               && token1->val.c == '@'
-                               && (b == CPP_NAME || b == CPP_STRING));
+                                     /* UCNs */
+    case CPP_OTHER:    return ((token1->val.str.text[0] == '\\'
+                                && b == CPP_NAME)
+                               || (CPP_OPTION (pfile, objc)
+                                   && token1->val.str.text[0] == '@'
+                                   && (b == CPP_NAME || b == CPP_STRING)));
     default:           break;
     }
 
@@ -1998,9 +1713,7 @@ cpp_avoid_paste (pfile, token1, token2)
    character, to FP.  Leading whitespace is removed.  If there are
    macros, special token padding is not performed.  */
 void
-cpp_output_line (pfile, fp)
-     cpp_reader *pfile;
-     FILE *fp;
+cpp_output_line (cpp_reader *pfile, FILE *fp)
 {
   const cpp_token *token;
 
@@ -2016,369 +1729,6 @@ cpp_output_line (pfile, fp)
   putc ('\n', fp);
 }
 
-/* Returns the value of a hexadecimal digit.  */
-static unsigned int
-hex_digit_value (c)
-     unsigned int c;
-{
-  if (hex_p (c))
-    return hex_value (c);
-  else
-    abort ();
-}
-
-/* Parse a '\uNNNN' or '\UNNNNNNNN' sequence.  Returns 1 to indicate
-   failure if cpplib is not parsing C++ or C99.  Such failure is
-   silent, and no variables are updated.  Otherwise returns 0, and
-   warns if -Wtraditional.
-
-   [lex.charset]: The character designated by the universal character
-   name \UNNNNNNNN is that character whose character short name in
-   ISO/IEC 10646 is NNNNNNNN; the character designated by the
-   universal character name \uNNNN is that character whose character
-   short name in ISO/IEC 10646 is 0000NNNN.  If the hexadecimal value
-   for a universal character name is less than 0x20 or in the range
-   0x7F-0x9F (inclusive), or if the universal character name
-   designates a character in the basic source character set, then the
-   program is ill-formed.
-
-   We assume that wchar_t is Unicode, so we don't need to do any
-   mapping.  Is this ever wrong?
-
-   PC points to the 'u' or 'U', PSTR is points to the byte after PC,
-   LIMIT is the end of the string or charconst.  PSTR is updated to
-   point after the UCS on return, and the UCS is written into PC.  */
-
-static int
-maybe_read_ucs (pfile, pstr, limit, pc)
-     cpp_reader *pfile;
-     const unsigned char **pstr;
-     const unsigned char *limit;
-     cppchar_t *pc;
-{
-  const unsigned char *p = *pstr;
-  unsigned int code = 0;
-  unsigned int c = *pc, length;
-
-  /* Only attempt to interpret a UCS for C++ and C99.  */
-  if (! (CPP_OPTION (pfile, cplusplus) || CPP_OPTION (pfile, c99)))
-    return 1;
-
-  if (CPP_WTRADITIONAL (pfile))
-    cpp_error (pfile, DL_WARNING,
-              "the meaning of '\\%c' is different in traditional C", c);
-
-  length = (c == 'u' ? 4: 8);
-
-  if ((size_t) (limit - p) < length)
-    {
-      cpp_error (pfile, DL_ERROR, "incomplete universal-character-name");
-      /* Skip to the end to avoid more diagnostics.  */
-      p = limit;
-    }
-  else
-    {
-      for (; length; length--, p++)
-       {
-         c = *p;
-         if (ISXDIGIT (c))
-           code = (code << 4) + hex_digit_value (c);
-         else
-           {
-             cpp_error (pfile, DL_ERROR,
-                        "non-hex digit '%c' in universal-character-name", c);
-             /* We shouldn't skip in case there are multibyte chars.  */
-             break;
-           }
-       }
-    }
-
-#ifdef TARGET_EBCDIC
-  cpp_error (pfile, DL_ERROR, "universal-character-name on EBCDIC target");
-  code = 0x3f;  /* EBCDIC invalid character */
-#else
- /* True extended characters are OK.  */
-  if (code >= 0xa0
-      && !(code & 0x80000000)
-      && !(code >= 0xD800 && code <= 0xDFFF))
-    ;
-  /* The standard permits $, @ and ` to be specified as UCNs.  We use
-     hex escapes so that this also works with EBCDIC hosts.  */
-  else if (code == 0x24 || code == 0x40 || code == 0x60)
-    ;
-  /* Don't give another error if one occurred above.  */
-  else if (length == 0)
-    cpp_error (pfile, DL_ERROR, "universal-character-name out of range");
-#endif
-
-  *pstr = p;
-  *pc = code;
-  return 0;
-}
-
-/* Returns the value of an escape sequence, truncated to the correct
-   target precision.  PSTR points to the input pointer, which is just
-   after the backslash.  LIMIT is how much text we have.  WIDE is true
-   if the escape sequence is part of a wide character constant or
-   string literal.  Handles all relevant diagnostics.  */
-cppchar_t
-cpp_parse_escape (pfile, pstr, limit, wide)
-     cpp_reader *pfile;
-     const unsigned char **pstr;
-     const unsigned char *limit;
-     int wide;
-{
-  int unknown = 0;
-  const unsigned char *str = *pstr;
-  cppchar_t c, mask;
-  unsigned int width;
-
-  if (wide)
-    width = CPP_OPTION (pfile, wchar_precision);
-  else
-    width = CPP_OPTION (pfile, char_precision);
-  if (width < BITS_PER_CPPCHAR_T)
-    mask = ((cppchar_t) 1 << width) - 1;
-  else
-    mask = ~0;
-
-  c = *str++;
-  switch (c)
-    {
-    case '\\': case '\'': case '"': case '?': break;
-    case 'b': c = TARGET_BS;     break;
-    case 'f': c = TARGET_FF;     break;
-    case 'n': c = TARGET_NEWLINE; break;
-    case 'r': c = TARGET_CR;     break;
-    case 't': c = TARGET_TAB;    break;
-    case 'v': c = TARGET_VT;     break;
-
-    case '(': case '{': case '[': case '%':
-      /* '\(', etc, are used at beginning of line to avoid confusing Emacs.
-        '\%' is used to prevent SCCS from getting confused.  */
-      unknown = CPP_PEDANTIC (pfile);
-      break;
-
-    case 'a':
-      if (CPP_WTRADITIONAL (pfile))
-       cpp_error (pfile, DL_WARNING,
-                  "the meaning of '\\a' is different in traditional C");
-      c = TARGET_BELL;
-      break;
-
-    case 'e': case 'E':
-      if (CPP_PEDANTIC (pfile))
-       cpp_error (pfile, DL_PEDWARN,
-                  "non-ISO-standard escape sequence, '\\%c'", (int) c);
-      c = TARGET_ESC;
-      break;
-
-    case 'u': case 'U':
-      unknown = maybe_read_ucs (pfile, &str, limit, &c);
-      break;
-
-    case 'x':
-      if (CPP_WTRADITIONAL (pfile))
-       cpp_error (pfile, DL_WARNING,
-                  "the meaning of '\\x' is different in traditional C");
-
-      {
-       cppchar_t i = 0, overflow = 0;
-       int digits_found = 0;
-
-       while (str < limit)
-         {
-           c = *str;
-           if (! ISXDIGIT (c))
-             break;
-           str++;
-           overflow |= i ^ (i << 4 >> 4);
-           i = (i << 4) + hex_digit_value (c);
-           digits_found = 1;
-         }
-
-       if (!digits_found)
-         cpp_error (pfile, DL_ERROR,
-                      "\\x used with no following hex digits");
-
-       if (overflow | (i != (i & mask)))
-         {
-           cpp_error (pfile, DL_PEDWARN,
-                      "hex escape sequence out of range");
-           i &= mask;
-         }
-       c = i;
-      }
-      break;
-
-    case '0':  case '1':  case '2':  case '3':
-    case '4':  case '5':  case '6':  case '7':
-      {
-       size_t count = 0;
-       cppchar_t i = c - '0';
-
-       while (str < limit && ++count < 3)
-         {
-           c = *str;
-           if (c < '0' || c > '7')
-             break;
-           str++;
-           i = (i << 3) + c - '0';
-         }
-
-       if (i != (i & mask))
-         {
-           cpp_error (pfile, DL_PEDWARN,
-                      "octal escape sequence out of range");
-           i &= mask;
-         }
-       c = i;
-      }
-      break;
-
-    default:
-      unknown = 1;
-      break;
-    }
-
-  if (unknown)
-    {
-      if (ISGRAPH (c))
-       cpp_error (pfile, DL_PEDWARN,
-                  "unknown escape sequence '\\%c'", (int) c);
-      else
-       cpp_error (pfile, DL_PEDWARN,
-                  "unknown escape sequence: '\\%03o'", (int) c);
-    }
-
-  if (c > mask)
-    {
-      cpp_error (pfile, DL_PEDWARN, "escape sequence out of range for its type");
-      c &= mask;
-    }
-
-  *pstr = str;
-  return c;
-}
-
-/* Interpret a (possibly wide) character constant in TOKEN.
-   WARN_MULTI warns about multi-character charconsts.  PCHARS_SEEN
-   points to a variable that is filled in with the number of
-   characters seen, and UNSIGNEDP to a variable that indicates whether
-   the result has signed type.  */
-cppchar_t
-cpp_interpret_charconst (pfile, token, pchars_seen, unsignedp)
-     cpp_reader *pfile;
-     const cpp_token *token;
-     unsigned int *pchars_seen;
-     int *unsignedp;
-{
-  const unsigned char *str = token->val.str.text;
-  const unsigned char *limit = str + token->val.str.len;
-  unsigned int chars_seen = 0;
-  size_t width, max_chars;
-  cppchar_t c, mask, result = 0;
-  bool unsigned_p;
-
-#ifdef MULTIBYTE_CHARS
-  (void) local_mbtowc (NULL, NULL, 0);
-#endif
-
-  /* Width in bits.  */
-  if (token->type == CPP_CHAR)
-    {
-      width = CPP_OPTION (pfile, char_precision);
-      max_chars = CPP_OPTION (pfile, int_precision) / width;
-      unsigned_p = CPP_OPTION (pfile, unsigned_char);
-    }
-  else
-    {
-      width = CPP_OPTION (pfile, wchar_precision);
-      max_chars = 1;
-      unsigned_p = CPP_OPTION (pfile, unsigned_wchar);
-    }
-
-  if (width < BITS_PER_CPPCHAR_T)
-    mask = ((cppchar_t) 1 << width) - 1;
-  else
-    mask = ~0;
-
-  while (str < limit)
-    {
-#ifdef MULTIBYTE_CHARS
-      wchar_t wc;
-      int char_len;
-
-      char_len = local_mbtowc (&wc, str, limit - str);
-      if (char_len == -1)
-       {
-         cpp_error (pfile, DL_WARNING,
-                    "ignoring invalid multibyte character");
-         c = *str++;
-       }
-      else
-       {
-         str += char_len;
-         c = wc;
-       }
-#else
-      c = *str++;
-#endif
-
-      if (c == '\\')
-       c = cpp_parse_escape (pfile, &str, limit, token->type == CPP_WCHAR);
-
-#ifdef MAP_CHARACTER
-      if (ISPRINT (c))
-       c = MAP_CHARACTER (c);
-#endif
-
-      chars_seen++;
-
-      /* Truncate the character, scale the result and merge the two.  */
-      c &= mask;
-      if (width < BITS_PER_CPPCHAR_T)
-       result = (result << width) | c;
-      else
-       result = c;
-    }
-
-  if (chars_seen == 0)
-    cpp_error (pfile, DL_ERROR, "empty character constant");
-  else if (chars_seen > 1)
-    {
-      /* Multichar charconsts are of type int and therefore signed.  */
-      unsigned_p = 0;
-
-      if (chars_seen > max_chars)
-       {
-         chars_seen = max_chars;
-         cpp_error (pfile, DL_WARNING,
-                    "character constant too long for its type");
-       }
-      else if (CPP_OPTION (pfile, warn_multichar))
-       cpp_error (pfile, DL_WARNING, "multi-character character constant");
-    }
-
-  /* Sign-extend or truncate the constant to cppchar_t.  The value is
-     in WIDTH bits, but for multi-char charconsts it's value is the
-     full target type's width.  */
-  if (chars_seen > 1)
-    width *= max_chars;
-  if (width < BITS_PER_CPPCHAR_T)
-    {
-      mask = ((cppchar_t) 1 << width) - 1;
-      if (unsigned_p || !(result & (1 << (width - 1))))
-       result &= mask;
-      else
-       result |= ~mask;
-    }
-
-  *pchars_seen = chars_seen;
-  *unsignedp = unsigned_p;
-  return result;
-}
-
 /* Memory buffers.  Changing these three constants can have a dramatic
    effect on performance.  The values here are reasonable defaults,
    but might be tuned.  If you adjust them, be sure to test across a
@@ -2397,8 +1747,7 @@ cpp_interpret_charconst (pfile, token, pchars_seen, unsignedp)
 /* Create a new allocation buffer.  Place the control block at the end
    of the buffer, so that buffer overflows will cause immediate chaos.  */
 static _cpp_buff *
-new_buff (len)
-     size_t len;
+new_buff (size_t len)
 {
   _cpp_buff *result;
   unsigned char *base;
@@ -2418,9 +1767,7 @@ new_buff (len)
 
 /* Place a chain of unwanted allocation buffers on the free list.  */
 void
-_cpp_release_buff (pfile, buff)
-     cpp_reader *pfile;
-     _cpp_buff *buff;
+_cpp_release_buff (cpp_reader *pfile, _cpp_buff *buff)
 {
   _cpp_buff *end = buff;
 
@@ -2432,9 +1779,7 @@ _cpp_release_buff (pfile, buff)
 
 /* Return a free buffer of size at least MIN_SIZE.  */
 _cpp_buff *
-_cpp_get_buff (pfile, min_size)
-     cpp_reader *pfile;
-     size_t min_size;
+_cpp_get_buff (cpp_reader *pfile, size_t min_size)
 {
   _cpp_buff *result, **p;
 
@@ -2463,10 +1808,7 @@ _cpp_get_buff (pfile, min_size)
    the excess bytes to the new buffer.  Chains the new buffer after
    BUFF, and returns the new buffer.  */
 _cpp_buff *
-_cpp_append_extend_buff (pfile, buff, min_extra)
-     cpp_reader *pfile;
-     _cpp_buff *buff;
-     size_t min_extra;
+_cpp_append_extend_buff (cpp_reader *pfile, _cpp_buff *buff, size_t min_extra)
 {
   size_t size = EXTENDED_BUFF_SIZE (buff, min_extra);
   _cpp_buff *new_buff = _cpp_get_buff (pfile, size);
@@ -2482,10 +1824,7 @@ _cpp_append_extend_buff (pfile, buff, min_extra)
    Chains the new buffer before the buffer pointed to by BUFF, and
    updates the pointer to point to the new buffer.  */
 void
-_cpp_extend_buff (pfile, pbuff, min_extra)
-     cpp_reader *pfile;
-     _cpp_buff **pbuff;
-     size_t min_extra;
+_cpp_extend_buff (cpp_reader *pfile, _cpp_buff **pbuff, size_t min_extra)
 {
   _cpp_buff *new_buff, *old_buff = *pbuff;
   size_t size = EXTENDED_BUFF_SIZE (old_buff, min_extra);
@@ -2498,8 +1837,7 @@ _cpp_extend_buff (pfile, pbuff, min_extra)
 
 /* Free a chain of buffers starting at BUFF.  */
 void
-_cpp_free_buff (buff)
-     _cpp_buff *buff;
+_cpp_free_buff (_cpp_buff *buff)
 {
   _cpp_buff *next;
 
@@ -2512,9 +1850,7 @@ _cpp_free_buff (buff)
 
 /* Allocate permanent, unaligned storage of length LEN.  */
 unsigned char *
-_cpp_unaligned_alloc (pfile, len)
-     cpp_reader *pfile;
-     size_t len;
+_cpp_unaligned_alloc (cpp_reader *pfile, size_t len)
 {
   _cpp_buff *buff = pfile->u_buff;
   unsigned char *result = buff->cur;
@@ -2542,9 +1878,7 @@ _cpp_unaligned_alloc (pfile, len)
    All existing other uses clearly fit this restriction: storing
    registered pragmas during initialization.  */
 unsigned char *
-_cpp_aligned_alloc (pfile, len)
-     cpp_reader *pfile;
-     size_t len;
+_cpp_aligned_alloc (cpp_reader *pfile, size_t len)
 {
   _cpp_buff *buff = pfile->a_buff;
   unsigned char *result = buff->cur;
index 6d2984a7202fe6d06aa2c2a7a0ebe3a910a159c7..8a291125fbc5d6b8cc7f3ad4c2ea70d0e5504b22 100644 (file)
@@ -21,7 +21,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
-
 #include "cpplib.h"
 #include "cpphash.h"
 #include "obstack.h"
@@ -43,11 +42,11 @@ struct if_stack
   const cpp_hashnode *mi_cmacro;/* macro name for #ifndef around entire file */
   bool skip_elses;             /* Can future #else / #elif be skipped?  */
   bool was_skipping;           /* If were skipping on entry.  */
-  int type;                    /* Most recent conditional, for diagnostics.  */
+  int type;                    /* Most recent conditional for diagnostics.  */
 };
 
 /* Contains a registered pragma or pragma namespace.  */
-typedef void (*pragma_cb) PARAMS ((cpp_reader *));
+typedef void (*pragma_cb) (cpp_reader *);
 struct pragma_entry
 {
   struct pragma_entry *next;
@@ -80,7 +79,7 @@ struct pragma_entry
 #define EXPAND         (1 << 4)
 
 /* Defines one #-directive, including how to handle it.  */
-typedef void (*directive_handler) PARAMS ((cpp_reader *));
+typedef void (*directive_handler) (cpp_reader *);
 typedef struct directive directive;
 struct directive
 {
@@ -93,49 +92,47 @@ struct directive
 
 /* Forward declarations.  */
 
-static void skip_rest_of_line  PARAMS ((cpp_reader *));
-static void check_eol          PARAMS ((cpp_reader *));
-static void start_directive    PARAMS ((cpp_reader *));
-static void prepare_directive_trad PARAMS ((cpp_reader *));
-static void end_directive      PARAMS ((cpp_reader *, int));
-static void directive_diagnostics
-       PARAMS ((cpp_reader *, const directive *, int));
-static void run_directive      PARAMS ((cpp_reader *, int,
-                                        const char *, size_t));
-static const cpp_token *glue_header_name PARAMS ((cpp_reader *));
-static const cpp_token *parse_include PARAMS ((cpp_reader *));
-static void push_conditional   PARAMS ((cpp_reader *, int, int,
-                                        const cpp_hashnode *));
-static unsigned int read_flag  PARAMS ((cpp_reader *, unsigned int));
-static uchar *dequote_string   PARAMS ((cpp_reader *, const uchar *,
-                                        unsigned int));
-static int  strtoul_for_line   PARAMS ((const uchar *, unsigned int,
-                                        unsigned long *));
-static void do_diagnostic      PARAMS ((cpp_reader *, int, int));
-static cpp_hashnode *lex_macro_node    PARAMS ((cpp_reader *));
-static void do_include_common  PARAMS ((cpp_reader *, enum include_type));
-static struct pragma_entry *lookup_pragma_entry
-  PARAMS ((struct pragma_entry *, const cpp_hashnode *pragma));
-static struct pragma_entry *insert_pragma_entry
-  PARAMS ((cpp_reader *, struct pragma_entry **, const cpp_hashnode *,
-          pragma_cb));
-static void do_pragma_once     PARAMS ((cpp_reader *));
-static void do_pragma_poison   PARAMS ((cpp_reader *));
-static void do_pragma_sdcc_hash PARAMS ((cpp_reader *));
-static void do_pragma_preproc_asm      PARAMS ((cpp_reader *));
-static void do_pragma_pedantic_parse_number PARAMS ((cpp_reader *));
-static void do_pragma_system_header    PARAMS ((cpp_reader *));
-static void do_pragma_dependency       PARAMS ((cpp_reader *));
-static void do_linemarker              PARAMS ((cpp_reader *));
-static const cpp_token *get_token_no_padding PARAMS ((cpp_reader *));
-static const cpp_token *get__Pragma_string PARAMS ((cpp_reader *));
-static void destringize_and_run PARAMS ((cpp_reader *, const cpp_string *));
-static int parse_answer PARAMS ((cpp_reader *, struct answer **, int));
-static cpp_hashnode *parse_assertion PARAMS ((cpp_reader *, struct answer **,
-                                             int));
-static struct answer ** find_answer PARAMS ((cpp_hashnode *,
-                                            const struct answer *));
-static void handle_assertion   PARAMS ((cpp_reader *, const char *, int));
+static void skip_rest_of_line (cpp_reader *);
+static void check_eol (cpp_reader *);
+static void start_directive (cpp_reader *);
+static void prepare_directive_trad (cpp_reader *);
+static void end_directive (cpp_reader *, int);
+static void directive_diagnostics (cpp_reader *, const directive *, int);
+static void run_directive (cpp_reader *, int, const char *, size_t);
+static char *glue_header_name (cpp_reader *);
+static const char *parse_include (cpp_reader *, int *);
+static void push_conditional (cpp_reader *, int, int, const cpp_hashnode *);
+static unsigned int read_flag (cpp_reader *, unsigned int);
+static int strtoul_for_line (const uchar *, unsigned int, unsigned long *);
+static void do_diagnostic (cpp_reader *, int, int);
+static cpp_hashnode *lex_macro_node (cpp_reader *);
+static int undefine_macros (cpp_reader *, cpp_hashnode *, void *);
+static void do_include_common (cpp_reader *, enum include_type);
+static struct pragma_entry *lookup_pragma_entry (struct pragma_entry *,
+                                                 const cpp_hashnode *);
+static struct pragma_entry *insert_pragma_entry (cpp_reader *,
+                                                 struct pragma_entry **,
+                                                 const cpp_hashnode *,
+                                                 pragma_cb);
+static int count_registered_pragmas (struct pragma_entry *);
+static char ** save_registered_pragmas (struct pragma_entry *, char **);
+static char ** restore_registered_pragmas (cpp_reader *, struct pragma_entry *,
+                                           char **);
+static void do_pragma_once (cpp_reader *);
+static void do_pragma_poison (cpp_reader *);
+static void do_pragma_system_header (cpp_reader *);
+static void do_pragma_dependency (cpp_reader *);
+static void do_pragma_sdcc_hash (cpp_reader *pfile);
+static void do_pragma_preproc_asm (cpp_reader *pfile);
+static void do_pragma_pedantic_parse_number (cpp_reader *pfile);
+static void do_linemarker (cpp_reader *);
+static const cpp_token *get_token_no_padding (cpp_reader *);
+static const cpp_token *get__Pragma_string (cpp_reader *);
+static void destringize_and_run (cpp_reader *, const cpp_string *);
+static int parse_answer (cpp_reader *, struct answer **, int);
+static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
+static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
+static void handle_assertion (cpp_reader *, const char *, int);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -170,8 +167,7 @@ D(sccs,             T_SCCS,         EXTENSION, 0)              /* 0 SVR4? */
 /* Use the table to generate a series of prototypes, an enum for the
    directive names, and an array of directive handlers.  */
 
-/* Don't invoke CONCAT2 with any whitespace or K&R cc will fail.  */
-#define D(name, t, o, f) static void CONCAT2(do_,name) PARAMS ((cpp_reader *));
+#define D(name, t, o, f) static void do_##name (cpp_reader *);
 DIRECTIVE_TABLE
 #undef D
 
@@ -183,10 +179,9 @@ enum
 };
 #undef D
 
-/* Don't invoke CONCAT2 with any whitespace or K&R cc will fail.  */
 #define D(name, t, origin, flags) \
-{ CONCAT2(do_,name), (const uchar *) STRINGX(name), \
-  sizeof STRINGX(name) - 1, origin, flags },
+{ do_##name, (const uchar *) #name, \
+  sizeof #name - 1, origin, flags },
 static const directive dtable[] =
 {
 DIRECTIVE_TABLE
@@ -206,8 +201,7 @@ static const directive linemarker_dir =
 
 /* Skip any remaining tokens in a directive.  */
 static void
-skip_rest_of_line (pfile)
-     cpp_reader *pfile;
+skip_rest_of_line (cpp_reader *pfile)
 {
   /* Discard all stacked contexts.  */
   while (pfile->context->prev)
@@ -221,18 +215,16 @@ skip_rest_of_line (pfile)
 
 /* Ensure there are no stray tokens at the end of a directive.  */
 static void
-check_eol (pfile)
-     cpp_reader *pfile;
+check_eol (cpp_reader *pfile)
 {
   if (! SEEN_EOL () && _cpp_lex_token (pfile)->type != CPP_EOF)
-    cpp_error (pfile, DL_PEDWARN, "extra tokens at end of #%s directive",
+    cpp_error (pfile, CPP_DL_PEDWARN, "extra tokens at end of #%s directive",
               pfile->directive->name);
 }
 
 /* Called when entering a directive, _Pragma or command-line directive.  */
 static void
-start_directive (pfile)
-     cpp_reader *pfile;
+start_directive (cpp_reader *pfile)
 {
   /* Setup in-directive state.  */
   pfile->state.in_directive = 1;
@@ -244,9 +236,7 @@ start_directive (pfile)
 
 /* Called when leaving a directive, _Pragma or command-line directive.  */
 static void
-end_directive (pfile, skip_line)
-     cpp_reader *pfile;
-     int skip_line;
+end_directive (cpp_reader *pfile, int skip_line)
 {
   if (CPP_OPTION (pfile, traditional))
     {
@@ -277,8 +267,7 @@ end_directive (pfile, skip_line)
 
 /* Prepare to handle the directive in pfile->directive.  */
 static void
-prepare_directive_trad (pfile)
-     cpp_reader *pfile;
+prepare_directive_trad (cpp_reader *pfile)
 {
   if (pfile->directive != &dtable[T_DEFINE])
     {
@@ -286,14 +275,17 @@ prepare_directive_trad (pfile)
                        && ! (pfile->directive->flags & EXPAND));
       bool was_skipping = pfile->state.skipping;
 
-      pfile->state.skipping = false;
       pfile->state.in_expression = (pfile->directive == &dtable[T_IF]
                                    || pfile->directive == &dtable[T_ELIF]);
+      if (pfile->state.in_expression)
+       pfile->state.skipping = false;
+
       if (no_expand)
        pfile->state.prevent_expansion++;
-      _cpp_read_logical_line_trad (pfile);
+      _cpp_scan_out_logical_line (pfile, NULL);
       if (no_expand)
        pfile->state.prevent_expansion--;
+
       pfile->state.skipping = was_skipping;
       _cpp_overlay_buffer (pfile, pfile->out.base,
                           pfile->out.cur - pfile->out.base);
@@ -306,16 +298,13 @@ prepare_directive_trad (pfile)
 /* Output diagnostics for a directive DIR.  INDENTED is nonzero if
    the '#' was indented.  */
 static void
-directive_diagnostics (pfile, dir, indented)
-     cpp_reader *pfile;
-     const directive *dir;
-     int indented;
+directive_diagnostics (cpp_reader *pfile, const directive *dir, int indented)
 {
   /* Issue -pedantic warnings for extensions.  */
   if (CPP_PEDANTIC (pfile)
       && ! pfile->state.skipping
       && dir->origin == EXTENSION)
-    cpp_error (pfile, DL_PEDWARN, "#%s is a GCC extension", dir->name);
+    cpp_error (pfile, CPP_DL_PEDWARN, "#%s is a GCC extension", dir->name);
 
   /* Traditionally, a directive is ignored unless its # is in
      column 1.  Therefore in code intended to work with K+R
@@ -326,14 +315,14 @@ directive_diagnostics (pfile, dir, indented)
   if (CPP_WTRADITIONAL (pfile))
     {
       if (dir == &dtable[T_ELIF])
-       cpp_error (pfile, DL_WARNING,
+       cpp_error (pfile, CPP_DL_WARNING,
                   "suggest not using #elif in traditional C");
       else if (indented && dir->origin == KANDR)
-       cpp_error (pfile, DL_WARNING,
+       cpp_error (pfile, CPP_DL_WARNING,
                   "traditional C ignores #%s with the # indented",
                   dir->name);
       else if (!indented && dir->origin != KANDR)
-       cpp_error (pfile, DL_WARNING,
+       cpp_error (pfile, CPP_DL_WARNING,
                   "suggest hiding #%s from traditional C with an indented #",
                   dir->name);
     }
@@ -345,9 +334,7 @@ directive_diagnostics (pfile, dir, indented)
    nonzero if the line of tokens has been handled, zero if we should
    continue processing the line.  */
 int
-_cpp_handle_directive (pfile, indented)
-     cpp_reader *pfile;
-     int indented;
+_cpp_handle_directive (cpp_reader *pfile, int indented)
 {
   const directive *dir = 0;
   const cpp_token *dname;
@@ -357,7 +344,7 @@ _cpp_handle_directive (pfile, indented)
   if (was_parsing_args)
     {
       if (CPP_OPTION (pfile, pedantic))
-       cpp_error (pfile, DL_PEDWARN,
+       cpp_error (pfile, CPP_DL_PEDWARN,
             "embedding a directive within macro arguments is not portable");
       pfile->state.parsing_args = 0;
       pfile->state.prevent_expansion = 0;
@@ -367,8 +354,8 @@ _cpp_handle_directive (pfile, indented)
 
   if (dname->type == CPP_NAME)
     {
-      if (dname->val.node->directive_index)
-       dir = &dtable[dname->val.node->directive_index - 1];
+      if (dname->val.node->is_directive)
+       dir = &dtable[dname->val.node->directive_index];
     }
   /* We do not recognize the # followed by a number extension in
      assembler code.  */
@@ -377,7 +364,7 @@ _cpp_handle_directive (pfile, indented)
       dir = &linemarker_dir;
       if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed)
          && ! pfile->state.skipping)
-       cpp_error (pfile, DL_PEDWARN,
+       cpp_error (pfile, CPP_DL_PEDWARN,
                   "style of line directive is a GCC extension");
     }
 
@@ -428,7 +415,7 @@ _cpp_handle_directive (pfile, indented)
       if (CPP_OPTION (pfile, lang) == CLK_ASM)
        skip = 0;
       else if (!pfile->state.skipping)
-       cpp_error (pfile, DL_ERROR, "invalid preprocessing directive #%s",
+       cpp_error (pfile, CPP_DL_ERROR, "invalid preprocessing directive #%s",
                   cpp_token_as_text (pfile, dname));
     }
 
@@ -437,7 +424,7 @@ _cpp_handle_directive (pfile, indented)
     prepare_directive_trad (pfile);
 
   if (dir)
-    (*pfile->directive->handler) (pfile);
+    pfile->directive->handler (pfile);
   else if (skip == 0)
     _cpp_backup_tokens (pfile, 1);
 
@@ -447,43 +434,40 @@ _cpp_handle_directive (pfile, indented)
       /* Restore state when within macro args.  */
       pfile->state.parsing_args = 2;
       pfile->state.prevent_expansion = 1;
-      pfile->buffer->saved_flags |= PREV_WHITE;
     }
   return skip;
 }
 
 /* Directive handler wrapper used by the command line option
-   processor.  */
+   processor.  BUF is \n terminated.  */
 static void
-run_directive (pfile, dir_no, buf, count)
-     cpp_reader *pfile;
-     int dir_no;
-     const char *buf;
-     size_t count;
+run_directive (cpp_reader *pfile, int dir_no, const char *buf, size_t count)
 {
   cpp_push_buffer (pfile, (const uchar *) buf, count,
-                  /* from_stage3 */ true, 1);
+                  /* from_stage3 */ true);
   /* Disgusting hack.  */
   if (dir_no == T_PRAGMA)
-    pfile->buffer->inc = pfile->buffer->prev->inc;
+    pfile->buffer->file = pfile->buffer->prev->file;
   start_directive (pfile);
-  /* We don't want a leading # to be interpreted as a directive.  */
-  pfile->buffer->saved_flags = 0;
+
+  /* This is a short-term fix to prevent a leading '#' being
+     interpreted as a directive.  */
+  _cpp_clean_line (pfile);
+
   pfile->directive = &dtable[dir_no];
   if (CPP_OPTION (pfile, traditional))
     prepare_directive_trad (pfile);
-  (void) (*pfile->directive->handler) (pfile);
+  pfile->directive->handler (pfile);
   end_directive (pfile, 1);
   if (dir_no == T_PRAGMA)
-    pfile->buffer->inc = NULL;
+    pfile->buffer->file = NULL;
   _cpp_pop_buffer (pfile);
 }
 
 /* Checks for validity the macro name in #define, #undef, #ifdef and
    #ifndef directives.  */
 static cpp_hashnode *
-lex_macro_node (pfile)
-     cpp_reader *pfile;
+lex_macro_node (cpp_reader *pfile)
 {
   const cpp_token *token = _cpp_lex_token (pfile);
 
@@ -499,28 +483,27 @@ lex_macro_node (pfile)
       cpp_hashnode *node = token->val.node;
 
       if (node == pfile->spec_nodes.n_defined)
-       cpp_error (pfile, DL_ERROR,
+       cpp_error (pfile, CPP_DL_ERROR,
                   "\"defined\" cannot be used as a macro name");
       else if (! (node->flags & NODE_POISONED))
        return node;
     }
   else if (token->flags & NAMED_OP)
-    cpp_error (pfile, DL_ERROR,
+    cpp_error (pfile, CPP_DL_ERROR,
        "\"%s\" cannot be used as a macro name as it is an operator in C++",
               NODE_NAME (token->val.node));
   else if (token->type == CPP_EOF)
-    cpp_error (pfile, DL_ERROR, "no macro name given in #%s directive",
+    cpp_error (pfile, CPP_DL_ERROR, "no macro name given in #%s directive",
               pfile->directive->name);
   else
-    cpp_error (pfile, DL_ERROR, "macro names must be identifiers");
+    cpp_error (pfile, CPP_DL_ERROR, "macro names must be identifiers");
 
   return NULL;
 }
 
 /* Process a #define directive.  Most work is done in cppmacro.c.  */
 static void
-do_define (pfile)
-     cpp_reader *pfile;
+do_define (cpp_reader *pfile)
 {
   cpp_hashnode *node = lex_macro_node (pfile);
 
@@ -533,188 +516,225 @@ do_define (pfile)
 
       if (_cpp_create_definition (pfile, node))
        if (pfile->cb.define)
-         (*pfile->cb.define) (pfile, pfile->directive_line, node);
+         pfile->cb.define (pfile, pfile->directive_line, node);
     }
 }
 
 /* Handle #undef.  Mark the identifier NT_VOID in the hash table.  */
 static void
-do_undef (pfile)
-     cpp_reader *pfile;
+do_undef (cpp_reader *pfile)
 {
   cpp_hashnode *node = lex_macro_node (pfile);
 
-  /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified identifier
-     is not currently defined as a macro name.  */
-  if (node && node->type == NT_MACRO)
+  if (node)
     {
       if (pfile->cb.undef)
-       (*pfile->cb.undef) (pfile, pfile->directive_line, node);
+       pfile->cb.undef (pfile, pfile->directive_line, node);
 
-      if (node->flags & NODE_WARN)
-       cpp_error (pfile, DL_WARNING, "undefining \"%s\"", NODE_NAME (node));
+      /* 6.10.3.5 paragraph 2: [#undef] is ignored if the specified
+        identifier is not currently defined as a macro name.  */
+      if (node->type == NT_MACRO)
+       {
+         if (node->flags & NODE_WARN)
+           cpp_error (pfile, CPP_DL_WARNING,
+                      "undefining \"%s\"", NODE_NAME (node));
 
-      if (CPP_OPTION (pfile, warn_unused_macros))
-       _cpp_warn_if_unused_macro (pfile, node, NULL);
+         if (CPP_OPTION (pfile, warn_unused_macros))
+           _cpp_warn_if_unused_macro (pfile, node, NULL);
 
-      _cpp_free_definition (node);
+         _cpp_free_definition (node);
+       }
     }
+
   check_eol (pfile);
 }
 
+/* Undefine a single macro/assertion/whatever.  */
+
+static int
+undefine_macros (cpp_reader *pfile, cpp_hashnode *h,
+                void *data_p ATTRIBUTE_UNUSED)
+{
+  switch (h->type)
+    {
+    case NT_VOID:
+      break;
+
+    case NT_MACRO:
+      if (pfile->cb.undef)
+        (*pfile->cb.undef) (pfile, pfile->directive_line, h);
+
+      if (CPP_OPTION (pfile, warn_unused_macros))
+        _cpp_warn_if_unused_macro (pfile, h, NULL);
+
+      /* And fall through....  */
+    case NT_ASSERTION:
+      _cpp_free_definition (h);
+      break;
+
+    default:
+      abort ();
+    }
+  h->flags &= ~NODE_POISONED;
+  return 1;
+}
+
+/* Undefine all macros and assertions.  */
+
+void
+cpp_undef_all (cpp_reader *pfile)
+{
+  cpp_forall_identifiers (pfile, undefine_macros, NULL);
+}
+
+
 /* Helper routine used by parse_include.  Reinterpret the current line
    as an h-char-sequence (< ... >); we are looking at the first token
-   after the <.  Returns the header as a token, or NULL on failure.  */
-static const cpp_token *
-glue_header_name (pfile)
-     cpp_reader *pfile;
+   after the <.  Returns a malloced filename.  */
+static char *
+glue_header_name (cpp_reader *pfile)
 {
-  cpp_token *header = NULL;
   const cpp_token *token;
-  unsigned char *buffer;
+  char *buffer;
   size_t len, total_len = 0, capacity = 1024;
 
   /* To avoid lexed tokens overwriting our glued name, we can only
      allocate from the string pool once we've lexed everything.  */
-  buffer = (unsigned char *) xmalloc (capacity);
+  buffer = xmalloc (capacity);
   for (;;)
     {
       token = get_token_no_padding (pfile);
 
-      if (token->type == CPP_GREATER || token->type == CPP_EOF)
+      if (token->type == CPP_GREATER)
        break;
+      if (token->type == CPP_EOF)
+       {
+         cpp_error (pfile, CPP_DL_ERROR, "missing terminating > character");
+         break;
+       }
 
-      len = cpp_token_len (token);
+      len = cpp_token_len (token) + 2; /* Leading space, terminating \0.  */
       if (total_len + len > capacity)
        {
          capacity = (capacity + len) * 2;
-         buffer = (unsigned char *) xrealloc (buffer, capacity);
+         buffer = xrealloc (buffer, capacity);
        }
 
       if (token->flags & PREV_WHITE)
        buffer[total_len++] = ' ';
 
-      total_len = cpp_spell_token (pfile, token, &buffer[total_len]) - buffer;
+      total_len = (cpp_spell_token (pfile, token, (uchar *) &buffer[total_len])
+                  - (uchar *) buffer);
     }
 
-  if (token->type == CPP_EOF)
-    cpp_error (pfile, DL_ERROR, "missing terminating > character");
-  else
-    {
-      unsigned char *token_mem = _cpp_unaligned_alloc (pfile, total_len + 1);
-      memcpy (token_mem, buffer, total_len);
-      token_mem[total_len] = '\0';
-
-      header = _cpp_temp_token (pfile);
-      header->type = CPP_HEADER_NAME;
-      header->flags = 0;
-      header->val.str.len = total_len;
-      header->val.str.text = token_mem;
-    }
-
-  free ((PTR) buffer);
-  return header;
+  buffer[total_len] = '\0';
+  return buffer;
 }
 
-/* Returns the header string of #include, #include_next, #import and
-   #pragma dependency.  Returns NULL on error.  */
-static const cpp_token *
-parse_include (pfile)
-     cpp_reader *pfile;
+/* Returns the file name of #include, #include_next, #import and
+   #pragma dependency.  The string is malloced and the caller should
+   free it.  Returns NULL on error.  */
+static const char *
+parse_include (cpp_reader *pfile, int *pangle_brackets)
 {
-  const unsigned char *dir;
+  char *fname;
   const cpp_token *header;
 
-  if (pfile->directive == &dtable[T_PRAGMA])
-    dir = U"pragma dependency";
-  else
-    dir = pfile->directive->name;
-
   /* Allow macro expansion.  */
   header = get_token_no_padding (pfile);
-  if (header->type != CPP_STRING && header->type != CPP_HEADER_NAME)
+  if (header->type == CPP_STRING || header->type == CPP_HEADER_NAME)
     {
-      if (header->type != CPP_LESS)
-       {
-         cpp_error (pfile, DL_ERROR,
-                    "#%s expects \"FILENAME\" or <FILENAME>", dir);
-         return NULL;
-       }
-
-      header = glue_header_name (pfile);
-      if (header == NULL)
-       return header;
+      fname = xmalloc (header->val.str.len - 1);
+      memcpy (fname, header->val.str.text + 1, header->val.str.len - 2);
+      fname[header->val.str.len - 2] = '\0';
+      *pangle_brackets = header->type == CPP_HEADER_NAME;
     }
-
-  if (header->val.str.len == 0)
+  else if (header->type == CPP_LESS)
+    {
+      fname = glue_header_name (pfile);
+      *pangle_brackets = 1;
+    }
+  else
     {
-      cpp_error (pfile, DL_ERROR, "empty file name in #%s", dir);
+      const unsigned char *dir;
+
+      if (pfile->directive == &dtable[T_PRAGMA])
+       dir = U"pragma dependency";
+      else
+       dir = pfile->directive->name;
+      cpp_error (pfile, CPP_DL_ERROR, "#%s expects \"FILENAME\" or <FILENAME>",
+                dir);
+
       return NULL;
     }
 
-  return header;
+  check_eol (pfile);
+  return fname;
 }
 
 /* Handle #include, #include_next and #import.  */
 static void
-do_include_common (pfile, type)
-     cpp_reader *pfile;
-     enum include_type type;
+do_include_common (cpp_reader *pfile, enum include_type type)
 {
-  const cpp_token *header;
+  const char *fname;
+  int angle_brackets;
 
-  /* For #include_next, if this is the primary source file, warn and
-     use the normal search logic.  */
-  if (type == IT_INCLUDE_NEXT && ! pfile->buffer->prev)
-    {
-      cpp_error (pfile, DL_WARNING, "#include_next in primary source file");
-      type = IT_INCLUDE;
-    }
-  else if (type == IT_IMPORT && CPP_OPTION (pfile, warn_import))
-    {
-      CPP_OPTION (pfile, warn_import) = 0;
-      cpp_error (pfile, DL_WARNING,
-          "#import is obsolete, use an #ifndef wrapper in the header file");
-    }
+  fname = parse_include (pfile, &angle_brackets);
+  if (!fname)
+    return;
+
+  if (!*fname)
+  {
+    cpp_error (pfile, CPP_DL_ERROR, "empty filename in #%s",
+               pfile->directive->name);
+    free ((void *) fname);
+    return;
+  }
 
-  header = parse_include (pfile);
-  if (header)
+  /* Prevent #include recursion.  */
+  if (pfile->line_maps.depth >= CPP_STACK_MAX)
+    cpp_error (pfile, CPP_DL_ERROR, "#include nested too deeply");
+  else
     {
-      /* Prevent #include recursion.  */
-      if (pfile->line_maps.depth >= CPP_STACK_MAX)
-       cpp_error (pfile, DL_ERROR, "#include nested too deeply");
-      else
-       {
-         check_eol (pfile);
-         /* Get out of macro context, if we are.  */
-         skip_rest_of_line (pfile);
-         if (pfile->cb.include)
-           (*pfile->cb.include) (pfile, pfile->directive_line,
-                                 pfile->directive->name, header);
-         _cpp_execute_include (pfile, header, type);
-       }
+      /* Get out of macro context, if we are.  */
+      skip_rest_of_line (pfile);
+
+      if (pfile->cb.include)
+       pfile->cb.include (pfile, pfile->directive_line,
+                          pfile->directive->name, fname, angle_brackets);
+
+      _cpp_stack_include (pfile, fname, angle_brackets, type);
     }
+
+  free ((void *) fname);
 }
 
 static void
-do_include (pfile)
-     cpp_reader *pfile;
+do_include (cpp_reader *pfile)
 {
   do_include_common (pfile, IT_INCLUDE);
 }
 
 static void
-do_import (pfile)
-     cpp_reader *pfile;
+do_import (cpp_reader *pfile)
 {
   do_include_common (pfile, IT_IMPORT);
 }
 
 static void
-do_include_next (pfile)
-     cpp_reader *pfile;
+do_include_next (cpp_reader *pfile)
 {
-  do_include_common (pfile, IT_INCLUDE_NEXT);
+  enum include_type type = IT_INCLUDE_NEXT;
+
+  /* If this is the primary source file, warn and use the normal
+     search logic.  */
+  if (! pfile->buffer->prev)
+    {
+      cpp_error (pfile, CPP_DL_WARNING,
+                "#include_next in primary source file");
+      type = IT_INCLUDE;
+    }
+  do_include_common (pfile, type);
 }
 
 /* Subroutine of do_linemarker.  Read possible flags after file name.
@@ -722,9 +742,7 @@ do_include_next (pfile)
    flag if it is valid, 0 at the end of the directive. Otherwise
    complain.  */
 static unsigned int
-read_flag (pfile, last)
-     cpp_reader *pfile;
-     unsigned int last;
+read_flag (cpp_reader *pfile, unsigned int last)
 {
   const cpp_token *token = _cpp_lex_token (pfile);
 
@@ -739,45 +757,16 @@ read_flag (pfile, last)
     }
 
   if (token->type != CPP_EOF)
-    cpp_error (pfile, DL_ERROR, "invalid flag \"%s\" in line directive",
+    cpp_error (pfile, CPP_DL_ERROR, "invalid flag \"%s\" in line directive",
               cpp_token_as_text (pfile, token));
   return 0;
 }
 
-/* Subroutine of do_line and do_linemarker.  Returns a version of STR
-   which has a NUL terminator and all escape sequences converted to
-   their equivalents.  Temporary, hopefully.  */
-static uchar *
-dequote_string (pfile, str, len)
-     cpp_reader *pfile;
-     const uchar *str;
-     unsigned int len;
-{
-  uchar *result = _cpp_unaligned_alloc (pfile, len + 1);
-  uchar *dst = result;
-  const uchar *limit = str + len;
-  cppchar_t c;
-
-  while (str < limit)
-    {
-      c = *str++;
-      if (c != '\\')
-       *dst++ = c;
-      else
-       *dst++ = cpp_parse_escape (pfile, &str, limit, 0);
-    }
-  *dst++ = '\0';
-  return result;
-}
-
 /* Subroutine of do_line and do_linemarker.  Convert a number in STR,
    of length LEN, to binary; store it in NUMP, and return 0 if the
    number was well-formed, 1 if not.  Temporary, hopefully.  */
 static int
-strtoul_for_line (str, len, nump)
-     const uchar *str;
-     unsigned int len;
-     unsigned long *nump;
+strtoul_for_line (const uchar *str, unsigned int len, long unsigned int *nump)
 {
   unsigned long reg = 0;
   uchar c;
@@ -797,8 +786,7 @@ strtoul_for_line (str, len, nump)
    Note that the filename string (if any) is a true string constant
    (escapes are interpreted), unlike in #line.  */
 static void
-do_line (pfile)
-     cpp_reader *pfile;
+do_line (cpp_reader *pfile)
 {
   const cpp_token *token;
   const char *new_file = pfile->map->to_file;
@@ -813,25 +801,26 @@ do_line (pfile)
       || strtoul_for_line (token->val.str.text, token->val.str.len,
                           &new_lineno))
     {
-      cpp_error (pfile, DL_ERROR,
+      cpp_error (pfile, CPP_DL_ERROR,
                 "\"%s\" after #line is not a positive integer",
                 cpp_token_as_text (pfile, token));
       return;
     }
 
   if (CPP_PEDANTIC (pfile) && (new_lineno == 0 || new_lineno > cap))
-    cpp_error (pfile, DL_PEDWARN, "line number out of range");
+    cpp_error (pfile, CPP_DL_PEDWARN, "line number out of range");
 
   token = cpp_get_token (pfile);
   if (token->type == CPP_STRING)
     {
-      new_file = (const char *) dequote_string (pfile, token->val.str.text,
-                                               token->val.str.len);
+      cpp_string s = { 0, 0 };
+      if (_cpp_interpret_string_notranslate (pfile, &token->val.str, &s))
+       new_file = (const char *)s.text;
       check_eol (pfile);
     }
   else if (token->type != CPP_EOF)
     {
-      cpp_error (pfile, DL_ERROR, "\"%s\" is not a valid filename",
+      cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename",
                 cpp_token_as_text (pfile, token));
       return;
     }
@@ -845,8 +834,7 @@ do_line (pfile)
    different syntax and semantics from #line:  Flags are allowed,
    and we never complain about the line number being too big.  */
 static void
-do_linemarker (pfile)
-     cpp_reader *pfile;
+do_linemarker (cpp_reader *pfile)
 {
   const cpp_token *token;
   const char *new_file = pfile->map->to_file;
@@ -866,7 +854,8 @@ do_linemarker (pfile)
       || strtoul_for_line (token->val.str.text, token->val.str.len,
                           &new_lineno))
     {
-      cpp_error (pfile, DL_ERROR, "\"%s\" after # is not a positive integer",
+      cpp_error (pfile, CPP_DL_ERROR,
+                "\"%s\" after # is not a positive integer",
                 cpp_token_as_text (pfile, token));
       return;
     }
@@ -874,8 +863,10 @@ do_linemarker (pfile)
   token = cpp_get_token (pfile);
   if (token->type == CPP_STRING)
     {
-      new_file = (const char *) dequote_string (pfile, token->val.str.text,
-                                               token->val.str.len);
+      cpp_string s = { 0, 0 };
+      if (_cpp_interpret_string_notranslate (pfile, &token->val.str, &s))
+       new_file = (const char *)s.text;
+
       new_sysp = 0;
       flag = read_flag (pfile, 0);
       if (flag == 1)
@@ -902,7 +893,7 @@ do_linemarker (pfile)
     }
   else if (token->type != CPP_EOF)
     {
-      cpp_error (pfile, DL_ERROR, "\"%s\" is not a valid filename",
+      cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename",
                 cpp_token_as_text (pfile, token));
       return;
     }
@@ -916,27 +907,21 @@ do_linemarker (pfile)
    header, 2 for a system header that needs to be extern "C" protected,
    and zero otherwise.  */
 void
-_cpp_do_file_change (pfile, reason, to_file, file_line, sysp)
-     cpp_reader *pfile;
-     enum lc_reason reason;
-     const char *to_file;
-     unsigned int file_line;
-     unsigned int sysp;
+_cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason,
+                    const char *to_file, unsigned int file_line,
+                    unsigned int sysp)
 {
-  pfile->map = add_line_map (&pfile->line_maps, reason, sysp,
-                            pfile->line, to_file, file_line);
+  pfile->map = linemap_add (&pfile->line_maps, reason, sysp,
+                           pfile->line, to_file, file_line);
 
   if (pfile->cb.file_change)
-    (*pfile->cb.file_change) (pfile, pfile->map);
+    pfile->cb.file_change (pfile, pfile->map);
 }
 
 /* Report a warning or error detected by the program we are
    processing.  Use the directive's tokens in the error message.  */
 static void
-do_diagnostic (pfile, code, print_dir)
-     cpp_reader *pfile;
-     int code;
-     int print_dir;
+do_diagnostic (cpp_reader *pfile, int code, int print_dir)
 {
   if (_cpp_begin_message (pfile, code,
                          pfile->cur_token[-1].line,
@@ -951,31 +936,28 @@ do_diagnostic (pfile, code, print_dir)
 }
 
 static void
-do_error (pfile)
-     cpp_reader *pfile;
+do_error (cpp_reader *pfile)
 {
-  do_diagnostic (pfile, DL_ERROR, 1);
+  do_diagnostic (pfile, CPP_DL_ERROR, 1);
 }
 
 static void
-do_warning (pfile)
-     cpp_reader *pfile;
+do_warning (cpp_reader *pfile)
 {
   /* We want #warning diagnostics to be emitted in system headers too.  */
-  do_diagnostic (pfile, DL_WARNING_SYSHDR, 1);
+  do_diagnostic (pfile, CPP_DL_WARNING_SYSHDR, 1);
 }
 
 /* Report program identification.  */
 static void
-do_ident (pfile)
-     cpp_reader *pfile;
+do_ident (cpp_reader *pfile)
 {
   const cpp_token *str = cpp_get_token (pfile);
 
   if (str->type != CPP_STRING)
-    cpp_error (pfile, DL_ERROR, "invalid #ident directive");
+    cpp_error (pfile, CPP_DL_ERROR, "invalid #ident directive");
   else if (pfile->cb.ident)
-    (*pfile->cb.ident) (pfile, pfile->directive_line, &str->val.str);
+    pfile->cb.ident (pfile, pfile->directive_line, &str->val.str);
 
   check_eol (pfile);
 }
@@ -984,9 +966,7 @@ do_ident (pfile)
    matching entry, or NULL if none is found.  The returned entry could
    be the start of a namespace chain, or a pragma.  */
 static struct pragma_entry *
-lookup_pragma_entry (chain, pragma)
-     struct pragma_entry *chain;
-     const cpp_hashnode *pragma;
+lookup_pragma_entry (struct pragma_entry *chain, const cpp_hashnode *pragma)
 {
   while (chain && chain->pragma != pragma)
     chain = chain->next;
@@ -998,11 +978,8 @@ lookup_pragma_entry (chain, pragma)
    singly-linked CHAIN.  If handler is NULL, it is a namespace,
    otherwise it is a pragma and its handler.  */
 static struct pragma_entry *
-insert_pragma_entry (pfile, chain, pragma, handler)
-     cpp_reader *pfile;
-     struct pragma_entry **chain;
-     const cpp_hashnode *pragma;
-     pragma_cb handler;
+insert_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain,
+                    const cpp_hashnode *pragma, pragma_cb handler)
 {
   struct pragma_entry *new;
 
@@ -1029,11 +1006,8 @@ insert_pragma_entry (pfile, chain, pragma, handler)
    goes in the global namespace.  HANDLER is the handler it will call,
    which must be non-NULL.  */
 void
-cpp_register_pragma (pfile, space, name, handler)
-     cpp_reader *pfile;
-     const char *space;
-     const char *name;
-     pragma_cb handler;
+cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name,
+                    pragma_cb handler)
 {
   struct pragma_entry **chain = &pfile->pragmas;
   struct pragma_entry *entry;
@@ -1060,14 +1034,14 @@ cpp_register_pragma (pfile, space, name, handler)
     {
       if (entry->is_nspace)
        clash:
-       cpp_error (pfile, DL_ICE,
+       cpp_error (pfile, CPP_DL_ICE,
                 "registering \"%s\" as both a pragma and a pragma namespace",
                 NODE_NAME (node));
       else if (space)
-       cpp_error (pfile, DL_ICE, "#pragma %s %s is already registered",
+       cpp_error (pfile, CPP_DL_ICE, "#pragma %s %s is already registered",
                   space, name);
       else
-       cpp_error (pfile, DL_ICE, "#pragma %s is already registered", name);
+       cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name);
     }
   else
     insert_pragma_entry (pfile, chain, node, handler);
@@ -1075,8 +1049,7 @@ cpp_register_pragma (pfile, space, name, handler)
 
 /* Register the pragmas the preprocessor itself handles.  */
 void
-_cpp_init_internal_pragmas (pfile)
-     cpp_reader *pfile;
+_cpp_init_internal_pragmas (cpp_reader *pfile)
 {
   /* Pragmas in the global namespace.  */
   cpp_register_pragma (pfile, 0, "once", do_pragma_once);
@@ -1094,14 +1067,84 @@ _cpp_init_internal_pragmas (pfile)
   cpp_register_pragma(pfile, 0, "pedantic_parse_number", do_pragma_pedantic_parse_number);
 }
 
+/* Return the number of registered pragmas in PE.  */
+
+static int
+count_registered_pragmas (struct pragma_entry *pe)
+{
+  int ct = 0;
+  for (; pe != NULL; pe = pe->next)
+    {
+      if (pe->is_nspace)
+       ct += count_registered_pragmas (pe->u.space);
+      ct++;
+    }
+  return ct;
+}
+
+/* Save into SD the names of the registered pragmas referenced by PE,
+   and return a pointer to the next free space in SD.  */
+
+static char **
+save_registered_pragmas (struct pragma_entry *pe, char **sd)
+{
+  for (; pe != NULL; pe = pe->next)
+    {
+      if (pe->is_nspace)
+       sd = save_registered_pragmas (pe->u.space, sd);
+      *sd++ = xmemdup (HT_STR (&pe->pragma->ident),
+                      HT_LEN (&pe->pragma->ident),
+                      HT_LEN (&pe->pragma->ident) + 1);
+    }
+  return sd;
+}
+
+/* Return a newly-allocated array which saves the names of the
+   registered pragmas.  */
+
+char **
+_cpp_save_pragma_names (cpp_reader *pfile)
+{
+  int ct = count_registered_pragmas (pfile->pragmas);
+  char **result = xnewvec (char *, ct);
+  (void) save_registered_pragmas (pfile->pragmas, result);
+  return result;
+}
+
+/* Restore from SD the names of the registered pragmas referenced by PE,
+   and return a pointer to the next unused name in SD.  */
+
+static char **
+restore_registered_pragmas (cpp_reader *pfile, struct pragma_entry *pe,
+                           char **sd)
+{
+  for (; pe != NULL; pe = pe->next)
+    {
+      if (pe->is_nspace)
+       sd = restore_registered_pragmas (pfile, pe->u.space, sd);
+      pe->pragma = cpp_lookup (pfile, U *sd, strlen (*sd));
+      free (*sd);
+      sd++;
+    }
+  return sd;
+}
+
+/* Restore the names of the registered pragmas from SAVED.  */
+
+void
+_cpp_restore_pragma_names (cpp_reader *pfile, char **saved)
+{
+  (void) restore_registered_pragmas (pfile, pfile->pragmas, saved);
+  free (saved);
+}
+
 /* Pragmata handling.  We handle some, and pass the rest on to the
    front end.  C99 defines three pragmas and says that no macro
    expansion is to be performed on them; whether or not macro
    expansion happens for other pragmas is implementation defined.
    This implementation never macro-expands the text after #pragma.  */
 static void
-do_pragma (pfile)
-     cpp_reader *pfile;
+do_pragma (cpp_reader *pfile)
 {
   const struct pragma_entry *p = NULL;
   const cpp_token *token, *pragma_token = pfile->cur_token;
@@ -1136,7 +1179,7 @@ do_pragma (pfile)
   else if (pfile->cb.def_pragma)
     {
       _cpp_backup_tokens (pfile, count);
-      (*pfile->cb.def_pragma) (pfile, pfile->directive_line);
+      pfile->cb.def_pragma (pfile, pfile->directive_line);
     }
 
   pfile->state.prevent_expansion--;
@@ -1144,24 +1187,19 @@ do_pragma (pfile)
 
 /* Handle #pragma once.  */
 static void
-do_pragma_once (pfile)
-     cpp_reader *pfile;
+do_pragma_once (cpp_reader *pfile)
 {
-  cpp_error (pfile, DL_WARNING, "#pragma once is obsolete");
-
   if (pfile->buffer->prev == NULL)
-    cpp_error (pfile, DL_WARNING, "#pragma once in main file");
-  else
-    _cpp_never_reread (pfile->buffer->inc);
+    cpp_error (pfile, CPP_DL_WARNING, "#pragma once in main file");
 
   check_eol (pfile);
+  _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
-do_pragma_poison (pfile)
-     cpp_reader *pfile;
+do_pragma_poison (cpp_reader *pfile)
 {
   const cpp_token *tok;
   cpp_hashnode *hp;
@@ -1174,7 +1212,8 @@ do_pragma_poison (pfile)
        break;
       if (tok->type != CPP_NAME)
        {
-         cpp_error (pfile, DL_ERROR, "invalid #pragma GCC poison directive");
+         cpp_error (pfile, CPP_DL_ERROR,
+                    "invalid #pragma GCC poison directive");
          break;
        }
 
@@ -1183,7 +1222,7 @@ do_pragma_poison (pfile)
        continue;
 
       if (hp->type == NT_MACRO)
-       cpp_error (pfile, DL_WARNING, "poisoning existing macro \"%s\"",
+       cpp_error (pfile, CPP_DL_WARNING, "poisoning existing macro \"%s\"",
                   NODE_NAME (hp));
       _cpp_free_definition (hp);
       hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
@@ -1194,31 +1233,29 @@ do_pragma_poison (pfile)
 /* SDCC specific
    sdcc_hash pragma */
 static void
-do_pragma_sdcc_hash (pfile)
-     cpp_reader *pfile;
+do_pragma_sdcc_hash (cpp_reader *pfile)
 {
-  const cpp_token *tok = _cpp_lex_token (pfile);
+    const cpp_token *tok = _cpp_lex_token (pfile);
 
-  if (tok->type == CPP_PLUS)
+    if (tok->type == CPP_PLUS)
     {
-      CPP_OPTION(pfile, allow_naked_hash)++;
+       CPP_OPTION(pfile, allow_naked_hash)++;
     }
-  else if (tok->type == CPP_MINUS)
+    else if (tok->type == CPP_MINUS)
     {
-      CPP_OPTION(pfile, allow_naked_hash)--;
+       CPP_OPTION(pfile, allow_naked_hash)--;
     }
-  else
+    else
     {
-      cpp_error (pfile, DL_ERROR,
-                 "invalid #pragma sdcc_hash directive, need '+' or '-'");
+       cpp_error (pfile, CPP_DL_ERROR,
+                  "invalid #pragma sdcc_hash directive, need '+' or '-'");
     }
 }
 
 /* SDCC specific
    pedantic_parse_number pragma */
 static void
-do_pragma_pedantic_parse_number (pfile)
-     cpp_reader *pfile;
+do_pragma_pedantic_parse_number (cpp_reader *pfile)
 {
     const cpp_token *tok = _cpp_lex_token (pfile);
 
@@ -1232,7 +1269,7 @@ do_pragma_pedantic_parse_number (pfile)
     }
   else
     {
-      cpp_error (pfile, DL_ERROR,
+      cpp_error (pfile, CPP_DL_ERROR,
                  "invalid #pragma pedantic_parse_number directive, need '+' or '-'");
     }
 }
@@ -1240,23 +1277,22 @@ do_pragma_pedantic_parse_number (pfile)
 /* SDCC _asm specific
    switch _asm block preprocessing on / off */
 static void
-do_pragma_preproc_asm (pfile)
-     cpp_reader *pfile;
+do_pragma_preproc_asm (cpp_reader *pfile)
 {
   const cpp_token *tok = _cpp_lex_token (pfile);
 
   if (tok->type == CPP_PLUS)
     {
-      CPP_OPTION(pfile, preproc_asm) = 1;
+      CPP_OPTION(pfile, preproc_asm)++;
     }
   else if (tok->type == CPP_MINUS)
     {
-      CPP_OPTION(pfile, preproc_asm)= 0;
+      CPP_OPTION(pfile, preproc_asm)--;
     }
   else
     {
-      cpp_error (pfile, DL_ERROR,
-                 "invalid #pragma preproc_asm directive, need '+' or '-'");
+      cpp_error (pfile, CPP_DL_ERROR,
+                "invalid #pragma preproc_asm directive, need '+' or '-'");
     }
 }
 
@@ -1267,13 +1303,12 @@ do_pragma_preproc_asm (pfile)
    system include directory.  To prevent abuse, it is rejected in the
    primary source file.  */
 static void
-do_pragma_system_header (pfile)
-     cpp_reader *pfile;
+do_pragma_system_header (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
 
   if (buffer->prev == 0)
-    cpp_error (pfile, DL_WARNING,
+    cpp_error (pfile, CPP_DL_WARNING,
               "#pragma system_header ignored outside include file");
   else
     {
@@ -1287,36 +1322,35 @@ do_pragma_system_header (pfile)
    file. Issue a diagnostic, if the specified file is newer. We use this to
    determine if a fixed header should be refixed.  */
 static void
-do_pragma_dependency (pfile)
-     cpp_reader *pfile;
+do_pragma_dependency (cpp_reader *pfile)
 {
-  const cpp_token *header;
-  int ordering;
+  const char *fname;
+  int angle_brackets, ordering;
 
-  header = parse_include (pfile);
-  if (!header)
+  fname = parse_include (pfile, &angle_brackets);
+  if (!fname)
     return;
 
-  ordering = _cpp_compare_file_date (pfile, header);
+  ordering = _cpp_compare_file_date (pfile, fname, angle_brackets);
   if (ordering < 0)
-    cpp_error (pfile, DL_WARNING, "cannot find source %s",
-              cpp_token_as_text (pfile, header));
+    cpp_error (pfile, CPP_DL_WARNING, "cannot find source file %s", fname);
   else if (ordering > 0)
     {
-      cpp_error (pfile, DL_WARNING, "current file is older than %s",
-                cpp_token_as_text (pfile, header));
+      cpp_error (pfile, CPP_DL_WARNING,
+                "current file is older than %s", fname);
       if (cpp_get_token (pfile)->type != CPP_EOF)
        {
          _cpp_backup_tokens (pfile, 1);
-         do_diagnostic (pfile, DL_WARNING, 0);
+         do_diagnostic (pfile, CPP_DL_WARNING, 0);
        }
     }
+
+  free ((void *) fname);
 }
 
 /* Get a token but skip padding.  */
 static const cpp_token *
-get_token_no_padding (pfile)
-     cpp_reader *pfile;
+get_token_no_padding (cpp_reader *pfile)
 {
   for (;;)
     {
@@ -1329,8 +1363,7 @@ get_token_no_padding (pfile)
 /* Check syntax is "(string-literal)".  Returns the string on success,
    or NULL on failure.  */
 static const cpp_token *
-get__Pragma_string (pfile)
-     cpp_reader *pfile;
+get__Pragma_string (cpp_reader *pfile)
 {
   const cpp_token *string;
 
@@ -1350,22 +1383,22 @@ get__Pragma_string (pfile)
 /* Destringize IN into a temporary buffer, by removing the first \ of
    \" and \\ sequences, and process the result as a #pragma directive.  */
 static void
-destringize_and_run (pfile, in)
-     cpp_reader *pfile;
-     const cpp_string *in;
+destringize_and_run (cpp_reader *pfile, const cpp_string *in)
 {
   const unsigned char *src, *limit;
   char *dest, *result;
 
-  dest = result = alloca (in->len + 1);
-  for (src = in->text, limit = src + in->len; src < limit;)
+  dest = result = alloca (in->len - 1);
+  src = in->text + 1 + (in->text[0] == 'L');
+  limit = in->text + in->len - 1;
+  while (src < limit)
     {
       /* We know there is a character following the backslash.  */
       if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
        src++;
       *dest++ = *src++;
     }
-  *dest = '\0';
+  *dest = '\n';
 
   /* Ugh; an awful kludge.  We are really not set up to be lexing
      tokens when in the middle of a macro expansion.  Use a new
@@ -1405,34 +1438,31 @@ destringize_and_run (pfile, in)
 
       Getting the line markers is a little tricky.  */
   if (pfile->cb.line_change)
-    (*pfile->cb.line_change) (pfile, pfile->cur_token, false);
+    pfile->cb.line_change (pfile, pfile->cur_token, false);
 }
 
 /* Handle the _Pragma operator.  */
 void
-_cpp_do__Pragma (pfile)
-     cpp_reader *pfile;
+_cpp_do__Pragma (cpp_reader *pfile)
 {
   const cpp_token *string = get__Pragma_string (pfile);
 
   if (string)
     destringize_and_run (pfile, &string->val.str);
   else
-    cpp_error (pfile, DL_ERROR,
+    cpp_error (pfile, CPP_DL_ERROR,
               "_Pragma takes a parenthesized string literal");
 }
 
-/* Just ignore #sccs on all systems.  */
+/* Ignore #sccs on all systems.  */
 static void
-do_sccs (pfile)
-     cpp_reader *pfile ATTRIBUTE_UNUSED;
+do_sccs (cpp_reader *pfile ATTRIBUTE_UNUSED)
 {
 }
 
 /* Handle #ifdef.  */
 static void
-do_ifdef (pfile)
-     cpp_reader *pfile;
+do_ifdef (cpp_reader *pfile)
 {
   int skip = 1;
 
@@ -1453,8 +1483,7 @@ do_ifdef (pfile)
 
 /* Handle #ifndef.  */
 static void
-do_ifndef (pfile)
-     cpp_reader *pfile;
+do_ifndef (cpp_reader *pfile)
 {
   int skip = 1;
   const cpp_hashnode *node = 0;
@@ -1476,12 +1505,11 @@ do_ifndef (pfile)
 
 /* _cpp_parse_expr puts a macro in a "#if !defined ()" expression in
    pfile->mi_ind_cmacro so we can handle multiple-include
-   optimisations.  If macro expansion occurs in the expression, we
+   optimizations.  If macro expansion occurs in the expression, we
    cannot treat it as a controlling conditional, since the expansion
    could change in the future.  That is handled by cpp_get_token.  */
 static void
-do_if (pfile)
-     cpp_reader *pfile;
+do_if (cpp_reader *pfile)
 {
   int skip = 1;
 
@@ -1495,20 +1523,19 @@ do_if (pfile)
    if_stack; this is so that the error message for missing #endif's
    etc. will point to the original #if.  */
 static void
-do_else (pfile)
-     cpp_reader *pfile;
+do_else (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
   struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
-    cpp_error (pfile, DL_ERROR, "#else without #if");
+    cpp_error (pfile, CPP_DL_ERROR, "#else without #if");
   else
     {
       if (ifs->type == T_ELSE)
        {
-         cpp_error (pfile, DL_ERROR, "#else after #else");
-         cpp_error_with_line (pfile, DL_ERROR, ifs->line, 0,
+         cpp_error (pfile, CPP_DL_ERROR, "#else after #else");
+         cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0,
                               "the conditional began here");
        }
       ifs->type = T_ELSE;
@@ -1529,20 +1556,19 @@ do_else (pfile)
 /* Handle a #elif directive by not changing if_stack either.  See the
    comment above do_else.  */
 static void
-do_elif (pfile)
-     cpp_reader *pfile;
+do_elif (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
   struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
-    cpp_error (pfile, DL_ERROR, "#elif without #if");
+    cpp_error (pfile, CPP_DL_ERROR, "#elif without #if");
   else
     {
       if (ifs->type == T_ELSE)
        {
-         cpp_error (pfile, DL_ERROR, "#elif after #else");
-         cpp_error_with_line (pfile, DL_ERROR, ifs->line, 0,
+         cpp_error (pfile, CPP_DL_ERROR, "#elif after #else");
+         cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0,
                               "the conditional began here");
        }
       ifs->type = T_ELIF;
@@ -1565,14 +1591,13 @@ do_elif (pfile)
 
 /* #endif pops the if stack and resets pfile->state.skipping.  */
 static void
-do_endif (pfile)
-     cpp_reader *pfile;
+do_endif (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
   struct if_stack *ifs = buffer->if_stack;
 
   if (ifs == NULL)
-    cpp_error (pfile, DL_ERROR, "#endif without #if");
+    cpp_error (pfile, CPP_DL_ERROR, "#endif without #if");
   else
     {
       /* Only check EOL if was not originally skipping.  */
@@ -1597,11 +1622,8 @@ do_endif (pfile)
    is #if or #ifndef, CMACRO is a potentially controlling macro, and
    we need to check here that we are at the top of the file.  */
 static void
-push_conditional (pfile, skip, type, cmacro)
-     cpp_reader *pfile;
-     int skip;
-     int type;
-     const cpp_hashnode *cmacro;
+push_conditional (cpp_reader *pfile, int skip, int type,
+                 const cpp_hashnode *cmacro)
 {
   struct if_stack *ifs;
   cpp_buffer *buffer = pfile->buffer;
@@ -1627,10 +1649,7 @@ push_conditional (pfile, skip, type, cmacro)
    storage, i.e. the #assert case.  Returns 0 on success, and sets
    ANSWERP to point to the answer.  */
 static int
-parse_answer (pfile, answerp, type)
-     cpp_reader *pfile;
-     struct answer **answerp;
-     int type;
+parse_answer (cpp_reader *pfile, struct answer **answerp, int type)
 {
   const cpp_token *paren;
   struct answer *answer;
@@ -1655,7 +1674,7 @@ parse_answer (pfile, answerp, type)
       if (type == T_UNASSERT && paren->type == CPP_EOF)
        return 0;
 
-      cpp_error (pfile, DL_ERROR, "missing '(' after predicate");
+      cpp_error (pfile, CPP_DL_ERROR, "missing '(' after predicate");
       return 1;
     }
 
@@ -1670,7 +1689,7 @@ parse_answer (pfile, answerp, type)
 
       if (token->type == CPP_EOF)
        {
-         cpp_error (pfile, DL_ERROR, "missing ')' to complete answer");
+         cpp_error (pfile, CPP_DL_ERROR, "missing ')' to complete answer");
          return 1;
        }
 
@@ -1690,7 +1709,7 @@ parse_answer (pfile, answerp, type)
 
   if (acount == 0)
     {
-      cpp_error (pfile, DL_ERROR, "predicate's answer is empty");
+      cpp_error (pfile, CPP_DL_ERROR, "predicate's answer is empty");
       return 1;
     }
 
@@ -1706,10 +1725,7 @@ parse_answer (pfile, answerp, type)
    the hash node of the predicate, or 0 on error.  If an answer was
    supplied, it is placed in ANSWERP, otherwise it is set to 0.  */
 static cpp_hashnode *
-parse_assertion (pfile, answerp, type)
-     cpp_reader *pfile;
-     struct answer **answerp;
-     int type;
+parse_assertion (cpp_reader *pfile, struct answer **answerp, int type)
 {
   cpp_hashnode *result = 0;
   const cpp_token *predicate;
@@ -1720,9 +1736,9 @@ parse_assertion (pfile, answerp, type)
   *answerp = 0;
   predicate = cpp_get_token (pfile);
   if (predicate->type == CPP_EOF)
-    cpp_error (pfile, DL_ERROR, "assertion without predicate");
+    cpp_error (pfile, CPP_DL_ERROR, "assertion without predicate");
   else if (predicate->type != CPP_NAME)
-    cpp_error (pfile, DL_ERROR, "predicate must be an identifier");
+    cpp_error (pfile, CPP_DL_ERROR, "predicate must be an identifier");
   else if (parse_answer (pfile, answerp, type) == 0)
     {
       unsigned int len = NODE_LEN (predicate->val.node);
@@ -1741,9 +1757,7 @@ parse_assertion (pfile, answerp, type)
 /* Returns a pointer to the pointer to CANDIDATE in the answer chain,
    or a pointer to NULL if the answer is not in the chain.  */
 static struct answer **
-find_answer (node, candidate)
-     cpp_hashnode *node;
-     const struct answer *candidate;
+find_answer (cpp_hashnode *node, const struct answer *candidate)
 {
   unsigned int i;
   struct answer **result;
@@ -1770,9 +1784,7 @@ find_answer (node, candidate)
    nonzero on failure, zero on success.  On success, the result of
    the test is written into VALUE, otherwise the value 0.  */
 int
-_cpp_test_assertion (pfile, value)
-     cpp_reader *pfile;
-     unsigned int *value;
+_cpp_test_assertion (cpp_reader *pfile, unsigned int *value)
 {
   struct answer *answer;
   cpp_hashnode *node;
@@ -1795,8 +1807,7 @@ _cpp_test_assertion (pfile, value)
 
 /* Handle #assert.  */
 static void
-do_assert (pfile)
-     cpp_reader *pfile;
+do_assert (cpp_reader *pfile)
 {
   struct answer *new_answer;
   cpp_hashnode *node;
@@ -1811,7 +1822,7 @@ do_assert (pfile)
        {
          if (*find_answer (node, new_answer))
            {
-             cpp_error (pfile, DL_WARNING, "\"%s\" re-asserted",
+             cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted",
                         NODE_NAME (node) + 1);
              return;
            }
@@ -1829,8 +1840,7 @@ do_assert (pfile)
 
 /* Handle #unassert.  */
 static void
-do_unassert (pfile)
-     cpp_reader *pfile;
+do_unassert (cpp_reader *pfile)
 {
   cpp_hashnode *node;
   struct answer *answer;
@@ -1868,9 +1878,7 @@ do_unassert (pfile)
    If STR has anything after the identifier, then it should
    be identifier=definition.  */
 void
-cpp_define (pfile, str)
-     cpp_reader *pfile;
-     const char *str;
+cpp_define (cpp_reader *pfile, const char *str)
 {
   char *buf, *p;
   size_t count;
@@ -1880,7 +1888,7 @@ cpp_define (pfile, str)
      tack " 1" on the end.  */
 
   count = strlen (str);
-  buf = (char *) alloca (count + 3);
+  buf = alloca (count + 3);
   memcpy (buf, str, count);
 
   p = strchr (str, '=');
@@ -1891,110 +1899,101 @@ cpp_define (pfile, str)
       buf[count++] = ' ';
       buf[count++] = '1';
     }
-  buf[count] = '\0';
+  buf[count] = '\n';
 
   run_directive (pfile, T_DEFINE, buf, count);
 }
 
 /* Slight variant of the above for use by initialize_builtins.  */
 void
-_cpp_define_builtin (pfile, str)
-     cpp_reader *pfile;
-     const char *str;
+_cpp_define_builtin (cpp_reader *pfile, const char *str)
 {
-  run_directive (pfile, T_DEFINE, str, strlen (str));
+  size_t len = strlen (str);
+  char *buf = alloca (len + 1);
+  memcpy (buf, str, len);
+  buf[len] = '\n';
+  run_directive (pfile, T_DEFINE, buf, len);
 }
 
 /* Process MACRO as if it appeared as the body of an #undef.  */
 void
-cpp_undef (pfile, macro)
-     cpp_reader *pfile;
-     const char *macro;
+cpp_undef (cpp_reader *pfile, const char *macro)
 {
-  run_directive (pfile, T_UNDEF, macro, strlen (macro));
+  size_t len = strlen (macro);
+  char *buf = alloca (len + 1);
+  memcpy (buf, macro, len);
+  buf[len] = '\n';
+  run_directive (pfile, T_UNDEF, buf, len);
 }
 
 /* Process the string STR as if it appeared as the body of a #assert.  */
 void
-cpp_assert (pfile, str)
-     cpp_reader *pfile;
-     const char *str;
+cpp_assert (cpp_reader *pfile, const char *str)
 {
   handle_assertion (pfile, str, T_ASSERT);
 }
 
 /* Process STR as if it appeared as the body of an #unassert.  */
 void
-cpp_unassert (pfile, str)
-     cpp_reader *pfile;
-     const char *str;
+cpp_unassert (cpp_reader *pfile, const char *str)
 {
   handle_assertion (pfile, str, T_UNASSERT);
 }
 
 /* Common code for cpp_assert (-A) and cpp_unassert (-A-).  */
 static void
-handle_assertion (pfile, str, type)
-     cpp_reader *pfile;
-     const char *str;
-     int type;
+handle_assertion (cpp_reader *pfile, const char *str, int type)
 {
   size_t count = strlen (str);
   const char *p = strchr (str, '=');
 
+  /* Copy the entire option so we can modify it.  Change the first
+     "=" in the string to a '(', and tack a ')' on the end.  */
+  char *buf = alloca (count + 2);
+
+  memcpy (buf, str, count);
   if (p)
     {
-      /* Copy the entire option so we can modify it.  Change the first
-        "=" in the string to a '(', and tack a ')' on the end.  */
-      char *buf = (char *) alloca (count + 2);
-
-      memcpy (buf, str, count);
       buf[p - str] = '(';
       buf[count++] = ')';
-      buf[count] = '\0';
-      str = buf;
     }
+  buf[count] = '\n';
+  str = buf;
 
   run_directive (pfile, type, str, count);
 }
 
 /* The number of errors for a given reader.  */
 unsigned int
-cpp_errors (pfile)
-     cpp_reader *pfile;
+cpp_errors (cpp_reader *pfile)
 {
   return pfile->errors;
 }
 
 /* The options structure.  */
 cpp_options *
-cpp_get_options (pfile)
-     cpp_reader *pfile;
+cpp_get_options (cpp_reader *pfile)
 {
   return &pfile->opts;
 }
 
 /* The callbacks structure.  */
 cpp_callbacks *
-cpp_get_callbacks (pfile)
-     cpp_reader *pfile;
+cpp_get_callbacks (cpp_reader *pfile)
 {
   return &pfile->cb;
 }
 
 /* The line map set.  */
-const struct line_maps *
-cpp_get_line_maps (pfile)
-     cpp_reader *pfile;
+struct line_maps *
+cpp_get_line_maps (cpp_reader *pfile)
 {
   return &pfile->line_maps;
 }
 
 /* Copy the given callbacks structure to our own.  */
 void
-cpp_set_callbacks (pfile, cb)
-     cpp_reader *pfile;
-     cpp_callbacks *cb;
+cpp_set_callbacks (cpp_reader *pfile, cpp_callbacks *cb)
 {
   pfile->cb = *cb;
 }
@@ -2003,44 +2002,37 @@ cpp_set_callbacks (pfile, cb)
    doesn't fail.  It does not generate a file change call back; that
    is the responsibility of the caller.  */
 cpp_buffer *
-cpp_push_buffer (pfile, buffer, len, from_stage3, return_at_eof)
-     cpp_reader *pfile;
-     const uchar *buffer;
-     size_t len;
-     int from_stage3;
-     int return_at_eof;
+cpp_push_buffer (cpp_reader *pfile, const uchar *buffer, size_t len,
+                int from_stage3)
 {
   cpp_buffer *new = xobnew (&pfile->buffer_ob, cpp_buffer);
 
   /* Clears, amongst other things, if_stack and mi_cmacro.  */
   memset (new, 0, sizeof (cpp_buffer));
 
-  new->line_base = new->buf = new->cur = buffer;
+  new->next_line = new->buf = buffer;
   new->rlimit = buffer + len;
-  new->from_stage3 = from_stage3 || CPP_OPTION (pfile, traditional);
+  new->from_stage3 = from_stage3;
   new->prev = pfile->buffer;
-  new->return_at_eof = return_at_eof;
-  new->saved_flags = BOL;
+  new->need_line = true;
 
   pfile->buffer = new;
-
   return new;
 }
 
 /* Pops a single buffer, with a file change call-back if appropriate.
    Then pushes the next -include file, if any remain.  */
 void
-_cpp_pop_buffer (pfile)
-     cpp_reader *pfile;
+_cpp_pop_buffer (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->buffer;
-  struct include_file *inc = buffer->inc;
+  struct _cpp_file *inc = buffer->file;
   struct if_stack *ifs;
 
   /* Walk back up the conditional stack till we reach its level at
      entry to this file, issuing error messages.  */
   for (ifs = buffer->if_stack; ifs; ifs = ifs->next)
-    cpp_error_with_line (pfile, DL_ERROR, ifs->line, 0,
+    cpp_error_with_line (pfile, CPP_DL_ERROR, ifs->line, 0,
                         "unterminated #%s", dtable[ifs->type].name);
 
   /* In case of a missing #endif.  */
@@ -2049,6 +2041,8 @@ _cpp_pop_buffer (pfile)
   /* _cpp_do_file_change expects pfile->buffer to be the new one.  */
   pfile->buffer = buffer->prev;
 
+  free (buffer->notes);
+
   /* Free the buffer object now; we may want to push a new buffer
      in _cpp_push_next_include_file.  */
   obstack_free (&pfile->buffer_ob, buffer);
@@ -2057,23 +2051,13 @@ _cpp_pop_buffer (pfile)
     {
       _cpp_pop_file_buffer (pfile, inc);
 
-      /* Don't generate a callback for popping the main file.  */
-      if (pfile->buffer)
-       {
-         _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
-
-         /* If this is the main file, there may be some -include
-            files left to push.  */
-         if (!pfile->buffer->prev)
-           _cpp_maybe_push_include_file (pfile);
-       }
+      _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
     }
 }
 
 /* Enter all recognized directives in the hash table.  */
 void
-_cpp_init_directives (pfile)
-     cpp_reader *pfile;
+_cpp_init_directives (cpp_reader *pfile)
 {
   unsigned int i;
   cpp_hashnode *node;
@@ -2081,6 +2065,7 @@ _cpp_init_directives (pfile)
   for (i = 0; i < (unsigned int) N_DIRECTIVES; i++)
     {
       node = cpp_lookup (pfile, dtable[i].name, dtable[i].length);
-      node->directive_index = i + 1;
+      node->is_directive = 1;
+      node->directive_index = i;
     }
 }
index 7875af4b98abc84a36b1b696062e45ea400d75ec..4ce262c47586c318bb2f1713d9090854ae504ee1 100644 (file)
@@ -1,5 +1,5 @@
 /* Definitions for CPP library.
-   Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
    Free Software Foundation, Inc.
    Written by Per Bothner, 1994-95.
 
@@ -31,10 +31,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 extern "C" {
 #endif
 
-/* For complex reasons, cpp_reader is also typedefed in c-pragma.h.  */
-#ifndef GCC_C_PRAGMA_H
 typedef struct cpp_reader cpp_reader;
-#endif
 typedef struct cpp_buffer cpp_buffer;
 typedef struct cpp_options cpp_options;
 typedef struct cpp_token cpp_token;
@@ -42,9 +39,9 @@ typedef struct cpp_string cpp_string;
 typedef struct cpp_hashnode cpp_hashnode;
 typedef struct cpp_macro cpp_macro;
 typedef struct cpp_callbacks cpp_callbacks;
+typedef struct cpp_dir cpp_dir;
 
 struct answer;
-struct file_name_map_list;
 
 /* The first three groups, apart from '=', can appear in preprocessor
    expressions (+= and -= are used to indicate unary + and - resp.).
@@ -126,23 +123,25 @@ struct file_name_map_list;
   OP(CPP_ATSIGN,       "@")  /* used in Objective-C */ \
 \
   TK(CPP_NAME,         SPELL_IDENT)    /* word */                      \
-  TK(CPP_NUMBER,       SPELL_NUMBER)   /* 34_be+ta  */                 \
+  TK(CPP_AT_NAME,       SPELL_IDENT)    /* @word - Objective-C */       \
+  TK(CPP_NUMBER,       SPELL_LITERAL)  /* 34_be+ta  */                 \
 \
-  TK(CPP_CHAR,         SPELL_STRING)   /* 'char' */                    \
-  TK(CPP_WCHAR,                SPELL_STRING)   /* L'char' */                   \
-  TK(CPP_OTHER,                SPELL_CHAR)     /* stray punctuation */         \
+  TK(CPP_CHAR,         SPELL_LITERAL)  /* 'char' */                    \
+  TK(CPP_WCHAR,                SPELL_LITERAL)  /* L'char' */                   \
+  TK(CPP_OTHER,                SPELL_LITERAL)  /* stray punctuation */         \
 \
-  TK(CPP_STRING,       SPELL_STRING)   /* "string" */                  \
-  TK(CPP_WSTRING,      SPELL_STRING)   /* L"string" */                 \
-  TK(CPP_HEADER_NAME,  SPELL_STRING)   /* <stdio.h> in #include */     \
+  TK(CPP_STRING,       SPELL_LITERAL)  /* "string" */                  \
+  TK(CPP_WSTRING,      SPELL_LITERAL)  /* L"string" */                 \
+  TK(CPP_OBJC_STRING,   SPELL_LITERAL)  /* @"string" - Objective-C */  \
+  TK(CPP_HEADER_NAME,  SPELL_LITERAL)  /* <stdio.h> in #include */     \
 \
-  TK(CPP_COMMENT,      SPELL_NUMBER)   /* Only if output comments.  */ \
-                                        /* SPELL_NUMBER happens to DTRT.  */ \
+  TK(CPP_COMMENT,      SPELL_LITERAL)  /* Only if output comments.  */ \
+                                        /* SPELL_LITERAL happens to DTRT.  */ \
   TK(CPP_MACRO_ARG,    SPELL_NONE)     /* Macro argument.  */          \
   TK(CPP_PADDING,      SPELL_NONE)     /* Whitespace for cpp0.  */     \
 \
   /* SDCC _asm specific */                                             \
-  TK(CPP_ASM,          SPELL_STRING)   /* _asm ... _endasm ; */
+  TK(CPP_ASM,          SPELL_LITERAL)   /* _asm ... _endasm ; */
 #define OP(e, s) e,
 #define TK(e, s) e,
 enum cpp_ttype
@@ -177,7 +176,7 @@ struct cpp_string
    occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts.  */
 struct cpp_token
 {
-  unsigned int line;           /* Logical line of first char of token.  */
+  fileline line;               /* Logical line of first char of token.  */
   unsigned short col;          /* Column of first char of token.  */
   ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT;  /* token type */
   unsigned char flags;         /* flags - see above */
@@ -188,78 +187,41 @@ struct cpp_token
     const cpp_token *source;   /* Inherit padding from this token.  */
     struct cpp_string str;     /* A string, or number.  */
     unsigned int arg_no;       /* Argument no. for a CPP_MACRO_ARG.  */
-    unsigned char c;           /* Character represented by CPP_OTHER.  */
   } val;
 };
 
 /* A type wide enough to hold any multibyte source character.
    cpplib's character constant interpreter requires an unsigned type.
-   Also, a typedef for the signed equivalent.  */
-#ifndef MAX_WCHAR_TYPE_SIZE
-# define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
-#endif
-#if CHAR_BIT * SIZEOF_INT >= MAX_WCHAR_TYPE_SIZE
+   Also, a typedef for the signed equivalent.
+   The width of this type is capped at 32 bits; there do exist targets
+   where wchar_t is 64 bits, but only in a non-default mode, and there
+   would be no meaningful interpretation for a wchar_t value greater
+   than 2^32 anyway -- the widest wide-character encoding around is
+   ISO 10646, which stops at 2^31.  */
+#if CHAR_BIT * SIZEOF_INT >= 32
 # define CPPCHAR_SIGNED_T int
+#elif CHAR_BIT * SIZEOF_LONG >= 32
+# define CPPCHAR_SIGNED_T long
 #else
-# if CHAR_BIT * SIZEOF_LONG >= MAX_WCHAR_TYPE_SIZE || !HAVE_LONG_LONG
-#  define CPPCHAR_SIGNED_T long
-# else
-#  define CPPCHAR_SIGNED_T long long
-# endif
+# error "Cannot find a least-32-bit signed integer type"
 #endif
 typedef unsigned CPPCHAR_SIGNED_T cppchar_t;
 typedef CPPCHAR_SIGNED_T cppchar_signed_t;
 
-/* Values for opts.dump_macros.
-  dump_only means inhibit output of the preprocessed text
-             and instead output the definitions of all user-defined
-             macros in a form suitable for use as input to cpp.
-   dump_names means pass #define and the macro name through to output.
-   dump_definitions means pass the whole definition (plus #define) through
-*/
-enum { dump_none = 0, dump_only, dump_names, dump_definitions };
-
 /* This structure is nested inside struct cpp_reader, and
    carries all the options visible to the command line.  */
 struct cpp_options
 {
-  /* Name of input and output files.  */
-  const char *in_fname;
-  const char *out_fname;
-
   /* Characters between tab stops.  */
   unsigned int tabstop;
 
-  /* Pending options - -D, -U, -A, -I, -ixxx.  */
-  struct cpp_pending *pending;
-
-  /* Search paths for include files.  */
-  struct search_path *quote_include;   /* "" */
-  struct search_path *bracket_include;  /* <> */
-
-  /* Map between header names and file names, used only on DOS where
-     file names are limited in length.  */
-  struct file_name_map_list *map_list;
-
-  /* Directory prefix that should replace `/usr/lib/gcc-lib/TARGET/VERSION'
-     in the standard include file directories.  */
-  const char *include_prefix;
-  unsigned int include_prefix_len;
-
-  /* Directory prefix for system include directories in the standard search
-     path.  */
-  const char *sysroot;
-
   /* The language we're preprocessing.  */
   enum c_lang lang;
 
-  /* Non-0 means -v, so print the full set of include dirs.  */
-  unsigned char verbose;
-
   /* Nonzero means use extra default include directories for C++.  */
   unsigned char cplusplus;
 
-  /* Nonzero means handle cplusplus style comments */
+  /* Nonzero means handle cplusplus style comments */
   unsigned char cplusplus_comments;
 
   /* Nonzero means define __OBJC__, treat @ as a special token, and
@@ -291,6 +253,9 @@ struct cpp_options
   /* Nonzero means don't print warning messages.  */
   unsigned char inhibit_warnings;
 
+  /* Nonzero means complain about deprecated features.  */
+  unsigned char warn_deprecated;
+
   /* Nonzero means don't suppress warnings from system headers.  */
   unsigned char warn_system_headers;
 
@@ -304,9 +269,6 @@ struct cpp_options
   /* Nonzero means warn if there are any trigraphs.  */
   unsigned char warn_trigraphs;
 
-  /* Nonzero means warn if #import is used.  */
-  unsigned char warn_import;
-
   /* Nonzero means warn about multicharacter charconsts.  */
   unsigned char warn_multichar;
 
@@ -327,24 +289,17 @@ struct cpp_options
   /* Nonzero means turn warnings into errors.  */
   unsigned char warnings_are_errors;
 
-  /* Nonzero causes output not to be done, but directives such as
-     #define that have side effects are still obeyed.  */
-  unsigned char no_output;
-
   /* Nonzero means we should look for header.gcc files that remap file
      names.  */
   unsigned char remap;
 
-  /* Nonzero means don't output line number information.  */
-  unsigned char no_line_commands;
-
-  /* Nonzero means -I- has been seen, so don't look for #include "foo"
-     the source-file directory.  */
-  unsigned char ignore_srcdir;
-
   /* Zero means dollar signs are punctuation.  */
   unsigned char dollars_in_ident;
 
+  /* True if we should warn about dollars in identifiers or numbers
+     for this translation unit.  */
+  unsigned char warn_dollars;
+
   /* Nonzero means warn if undefined identifiers are evaluated in an #if.  */
   unsigned char warn_undef;
 
@@ -364,18 +319,6 @@ struct cpp_options
      bother trying to do macro expansion and whatnot.  */
   unsigned char preprocessed;
 
-  /* Nonzero disables all the standard directories for headers.  */
-  unsigned char no_standard_includes;
-
-  /* Nonzero disables the C++-specific standard directories for headers.  */
-  unsigned char no_standard_cplusplus_includes;
-
-  /* Nonzero means dump macros in some fashion - see above.  */
-  unsigned char dump_macros;
-
-  /* Nonzero means pass #include lines through to the output.  */
-  unsigned char dump_includes;
-
   /* Print column number in error messages.  */
   unsigned char show_column;
 
@@ -385,10 +328,20 @@ struct cpp_options
   /* True for traditional preprocessing.  */
   unsigned char traditional;
 
-  /* True if --help, --version or --target-help appeared in the
-     options.  Stand-alone CPP should then bail out after option
-     parsing; drivers might want to continue printing help.  */
-  unsigned char help_only;
+  /* Holds the name of the target (execution) character set.  */
+  const char *narrow_charset;
+
+  /* Holds the name of the target wide character set.  */
+  const char *wide_charset;
+
+  /* Holds the name of the input character set.  */
+  const char *input_charset;
+
+  /* True to warn about precompiled header files we couldn't use.  */
+  bool warn_invalid_pch;
+
+  /* True if dependencies should be restored from a precompiled header.  */
+  bool restore_pch_deps;
 
   /* SDCC abuse by Kevin: allow naked '#' characters in expanded macros
    * (see _cpp_create_definition in cppmacro.c)
@@ -420,15 +373,8 @@ struct cpp_options
        one.  */
     bool phony_targets;
 
-    /* If true, fopen (deps_file, "a") else fopen (deps_file, "w").  */
-    unsigned char append;
-
     /* If true, no dependency is generated on the main file.  */
     bool ignore_main_file;
-
-    /* File name which deps are being written to.  This is 0 if deps are
-       being written to stdout.  */
-    const char *file;
   } deps;
 
   /* Target-specific features set by the front end or client.  */
@@ -440,25 +386,59 @@ struct cpp_options
   /* True means chars (wide chars) are unsigned.  */
   bool unsigned_char, unsigned_wchar;
 
+  /* True if the most significant byte in a word has the lowest
+     address in memory.  */
+  bool bytes_big_endian;
+
   /* Nonzero means __STDC__ should have the value 0 in system headers.  */
   unsigned char stdc_0_in_system_headers;
 };
 
-/* Call backs.  */
+/* Call backs to cpplib client.  */
 struct cpp_callbacks
 {
   /* Called when a new line of preprocessed output is started.  */
-  void (*line_change) PARAMS ((cpp_reader *, const cpp_token *, int));
-  void (*file_change) PARAMS ((cpp_reader *, const struct line_map *));
-  void (*include) PARAMS ((cpp_reader *, unsigned int,
-                          const unsigned char *, const cpp_token *));
-  void (*define) PARAMS ((cpp_reader *, unsigned int, cpp_hashnode *));
-  void (*undef) PARAMS ((cpp_reader *, unsigned int, cpp_hashnode *));
-  void (*ident) PARAMS ((cpp_reader *, unsigned int, const cpp_string *));
-  void (*def_pragma) PARAMS ((cpp_reader *, unsigned int));
-  /* Called when the client has a chance to properly register
-     built-ins with cpp_define() and cpp_assert().  */
-  void (*register_builtins) PARAMS ((cpp_reader *));
+  void (*line_change) (cpp_reader *, const cpp_token *, int);
+
+  /* Called when switching to/from a new file.
+     The line_map is for the new file.  It is NULL if there is no new file.
+     (In C this happens when done with <built-in>+<command line> and also
+     when done with a main file.)  This can be used for resource cleanup.  */
+  void (*file_change) (cpp_reader *, const struct line_map *);
+
+  void (*dir_change) (cpp_reader *, const char *);
+  void (*include) (cpp_reader *, unsigned int, const unsigned char *,
+                  const char *, int);
+  void (*define) (cpp_reader *, unsigned int, cpp_hashnode *);
+  void (*undef) (cpp_reader *, unsigned int, cpp_hashnode *);
+  void (*ident) (cpp_reader *, unsigned int, const cpp_string *);
+  void (*def_pragma) (cpp_reader *, unsigned int);
+  int (*valid_pch) (cpp_reader *, const char *, int);
+  void (*read_pch) (cpp_reader *, const char *, int, const char *);
+};
+
+/* Chain of directories to look for include files in.  */
+struct cpp_dir
+{
+  /* NULL-terminated singly-linked list.  */
+  struct cpp_dir *next;
+
+  /* NAME of the directory, NUL-terminated.  */
+  char *name;
+  unsigned int len;
+
+  /* One if a system header, two if a system header that has extern
+     "C" guards for C++.  */
+  unsigned char sysp;
+
+  /* Mapping of file names for this directory for MS-DOS and related
+     platforms.  A NULL-terminated array of (from, to) pairs.  */
+  const char **name_map;
+
+  /* The C front end uses these to recognize duplicated
+     directories in the search path.  */
+  ino_t ino;
+  dev_t dev;
 };
 
 /* Name under which this program was invoked.  */
@@ -468,7 +448,7 @@ extern const char *progname;
    entries for all identifiers: either macros defined by #define
    commands (type NT_MACRO), assertions created with #assert
    (NT_ASSERTION), or neither of the above (NT_VOID).  Builtin macros
-   like __LINE__ are flagged NODE_BUILTIN.  Poisioned identifiers are
+   like __LINE__ are flagged NODE_BUILTIN.  Poisoned identifiers are
    flagged NODE_POISONED.  NODE_OPERATOR (C++ only) indicates an
    identifier that behaves like an operator such as "xor".
    NODE_DIAGNOSTIC is for speed in lex_token: it indicates a
@@ -482,6 +462,7 @@ extern const char *progname;
 #define NODE_DIAGNOSTIC (1 << 3)       /* Possible diagnostic when lexed.  */
 #define NODE_WARN      (1 << 4)        /* Warn if redefined or undefined.  */
 #define NODE_DISABLED  (1 << 5)        /* A disabled macro.  */
+#define NODE_MACRO_ARG (1 << 6)        /* Used during #define processing.  */
 
 /* Different flavors of hash node.  */
 enum node_type
@@ -513,124 +494,127 @@ enum builtin_type
 /* The common part of an identifier node shared amongst all 3 C front
    ends.  Also used to store CPP identifiers, which are a superset of
    identifiers in the grammatical sense.  */
-struct cpp_hashnode
+struct cpp_hashnode GTY(())
 {
   struct ht_identifier ident;
-  unsigned short arg_index;            /* Macro argument index.  */
-  unsigned char directive_index;       /* Index into directive table.  */
+  unsigned int is_directive : 1;
+  unsigned int directive_index : 7;    /* If is_directive,
+                                          then index into directive table.
+                                          Otherwise, a NODE_OPERATOR.  */
   unsigned char rid_code;              /* Rid code - for front ends.  */
   ENUM_BITFIELD(node_type) type : 8;   /* CPP node type.  */
   unsigned char flags;                 /* CPP flags.  */
 
-  union
+  union _cpp_hashnode_value
   {
-    cpp_macro *macro;                  /* If a macro.  */
-    struct answer *answers;            /* Answers to an assertion.  */
-    enum cpp_ttype operator;           /* Code for a named operator.  */
-    enum builtin_type builtin;         /* Code for a builtin macro.  */
-  } value;
+    /* If a macro.  */
+    cpp_macro * GTY((skip (""))) macro;
+    /* Answers to an assertion.  */
+    struct answer * GTY ((skip (""))) answers;
+    /* Code for a builtin macro.  */
+    enum builtin_type GTY ((tag ("1"))) builtin;
+    /* Macro argument index.  */
+    unsigned short GTY ((tag ("0"))) arg_index;
+  } GTY ((desc ("0"))) value;
 };
 
-/* Call this first to get a handle to pass to other functions.  */
-extern cpp_reader *cpp_create_reader PARAMS ((enum c_lang));
+/* Call this first to get a handle to pass to other functions.
+
+   If you want cpplib to manage its own hashtable, pass in a NULL
+   pointer.  Otherwise you should pass in an initialized hash table
+   that cpplib will share; this technique is used by the C front
+   ends.  */
+extern cpp_reader *cpp_create_reader (enum c_lang, struct ht *);
 
 /* Call this to change the selected language standard (e.g. because of
    command line options).  */
-extern void cpp_set_lang PARAMS ((cpp_reader *, enum c_lang));
+extern void cpp_set_lang (cpp_reader *, enum c_lang);
 
 /* Add a dependency TARGET.  Quote it for "make" if QUOTE.  Can be
    called any number of times before cpp_read_main_file().  If no
    targets have been added before cpp_read_main_file(), then the
    default target is used.  */
-extern void cpp_add_dependency_target PARAMS ((cpp_reader *,
-                                              const char * target,
-                                              int quote));
+extern void cpp_add_dependency_target (cpp_reader *, const char *, int);
+
+/* Set the include paths.  */
+extern void cpp_set_include_chains (cpp_reader *, cpp_dir *, cpp_dir *, int);
 
 /* Call these to get pointers to the options and callback structures
    for a given reader.  These pointers are good until you call
    cpp_finish on that reader.  You can either edit the callbacks
    through the pointer returned from cpp_get_callbacks, or set them
    with cpp_set_callbacks.  */
-extern cpp_options *cpp_get_options PARAMS ((cpp_reader *));
-extern const struct line_maps *cpp_get_line_maps PARAMS ((cpp_reader *));
-extern cpp_callbacks *cpp_get_callbacks PARAMS ((cpp_reader *));
-extern void cpp_set_callbacks PARAMS ((cpp_reader *, cpp_callbacks *));
-
-/* Now call cpp_handle_option[s] to handle 1[or more] switches.  The
-   return value is the number of arguments used.  If
-   cpp_handle_options returns without using all arguments, it couldn't
-   understand the next switch.  Options processing is not completed
-   until you call cpp_finish_options.  */
-extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **));
-extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **));
+extern cpp_options *cpp_get_options (cpp_reader *);
+extern struct line_maps *cpp_get_line_maps (cpp_reader *);
+extern cpp_callbacks *cpp_get_callbacks (cpp_reader *);
+extern void cpp_set_callbacks (cpp_reader *, cpp_callbacks *);
 
 /* This function reads the file, but does not start preprocessing.  It
    returns the name of the original file; this is the same as the
    input file, except for preprocessed input.  This will generate at
    least one file change callback, and possibly a line change callback
-   too.  If there was an error opening the file, it returns NULL.
+   too.  If there was an error opening the file, it returns NULL. */
+extern const char *cpp_read_main_file (cpp_reader *, const char *);
 
-   If you want cpplib to manage its own hashtable, pass in a NULL
-   pointer.  Otherise you should pass in an initialized hash table
-   that cpplib will share; this technique is used by the C front
-   ends.  */
-extern const char *cpp_read_main_file PARAMS ((cpp_reader *, const char *,
-                                              struct ht *));
+/* Set up built-ins like __FILE__.  */
+extern void cpp_init_builtins (cpp_reader *, int);
+
+/* This is called after options have been parsed, and partially
+   processed.  */
+extern void cpp_post_options (cpp_reader *);
 
-/* Deferred handling of command line options that can generate debug
-   callbacks, such as -D and -imacros.  Call this after
-   cpp_read_main_file.  The front ends need this separation so they
-   can initialize debug output with the original file name, returned
-   from cpp_read_main_file, before they get debug callbacks.  */
-extern void cpp_finish_options PARAMS ((cpp_reader *));
+/* Set up translation to the target character set.  */
+extern void cpp_init_iconv (cpp_reader *);
 
 /* Call this to finish preprocessing.  If you requested dependency
    generation, pass an open stream to write the information to,
    otherwise NULL.  It is your responsibility to close the stream.
 
    Returns cpp_errors (pfile).  */
-extern int cpp_finish PARAMS ((cpp_reader *, FILE *deps_stream));
+extern int cpp_finish (cpp_reader *, FILE *deps_stream);
 
 /* Call this to release the handle at the end of preprocessing.  Any
    use of the handle after this function returns is invalid.  Returns
    cpp_errors (pfile).  */
-extern void cpp_destroy PARAMS ((cpp_reader *));
+extern void cpp_destroy (cpp_reader *);
 
 /* Error count.  */
-extern unsigned int cpp_errors PARAMS ((cpp_reader *));
-
-extern unsigned int cpp_token_len PARAMS ((const cpp_token *));
-extern unsigned char *cpp_token_as_text PARAMS ((cpp_reader *,
-                                                const cpp_token *));
-extern unsigned char *cpp_spell_token PARAMS ((cpp_reader *, const cpp_token *,
-                                              unsigned char *));
-extern void cpp_register_pragma PARAMS ((cpp_reader *,
-                                        const char *, const char *,
-                                        void (*) PARAMS ((cpp_reader *))));
-
-extern int cpp_avoid_paste PARAMS ((cpp_reader *, const cpp_token *,
-                                   const cpp_token *));
-extern const cpp_token *cpp_get_token PARAMS ((cpp_reader *));
-extern const unsigned char *cpp_macro_definition PARAMS ((cpp_reader *,
-                                                 const cpp_hashnode *));
-extern void _cpp_backup_tokens PARAMS ((cpp_reader *, unsigned int));
+extern unsigned int cpp_errors (cpp_reader *);
+
+extern unsigned int cpp_token_len (const cpp_token *);
+extern unsigned char *cpp_token_as_text (cpp_reader *, const cpp_token *);
+extern unsigned char *cpp_spell_token (cpp_reader *, const cpp_token *,
+                                      unsigned char *);
+extern void cpp_register_pragma (cpp_reader *, const char *, const char *,
+                                void (*) (cpp_reader *));
+extern int cpp_avoid_paste (cpp_reader *, const cpp_token *,
+                           const cpp_token *);
+extern const cpp_token *cpp_get_token (cpp_reader *);
+extern const unsigned char *cpp_macro_definition (cpp_reader *,
+                                                 const cpp_hashnode *);
+extern void _cpp_backup_tokens (cpp_reader *, unsigned int);
 
 /* Evaluate a CPP_CHAR or CPP_WCHAR token.  */
-extern cppchar_t
-cpp_interpret_charconst PARAMS ((cpp_reader *, const cpp_token *,
-                                unsigned int *, int *));
-
-/* Used to register builtins during the register_builtins callback.
+extern cppchar_t cpp_interpret_charconst (cpp_reader *, const cpp_token *,
+                                         unsigned int *, int *);
+/* Evaluate a vector of CPP_STRING or CPP_WSTRING tokens.  */
+extern bool cpp_interpret_string (cpp_reader *,
+                                 const cpp_string *, size_t,
+                                 cpp_string *, bool);
+
+/* Used to register macros and assertions, perhaps from the command line.
    The text is the same as the command line argument.  */
-extern void cpp_define PARAMS ((cpp_reader *, const char *));
-extern void cpp_assert PARAMS ((cpp_reader *, const char *));
-extern void cpp_undef  PARAMS ((cpp_reader *, const char *));
-extern void cpp_unassert PARAMS ((cpp_reader *, const char *));
+extern void cpp_define (cpp_reader *, const char *);
+extern void cpp_assert (cpp_reader *, const char *);
+extern void cpp_undef (cpp_reader *, const char *);
+extern void cpp_unassert (cpp_reader *, const char *);
+
+/* Undefine all macros and assertions.  */
+extern void cpp_undef_all (cpp_reader *);
 
-extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
-                                           const unsigned char *, size_t,
-                                           int, int));
-extern int cpp_defined PARAMS ((cpp_reader *, const unsigned char *, int));
+extern cpp_buffer *cpp_push_buffer (cpp_reader *, const unsigned char *,
+                                   size_t, int);
+extern int cpp_defined (cpp_reader *, const unsigned char *, int);
 
 /* A preprocessing number.  Code assumes that any unused high bits of
    the double integer are set to zero.  */
@@ -671,36 +655,36 @@ struct cpp_num
 
 /* Classify a CPP_NUMBER token.  The return value is a combination of
    the flags from the above sets.  */
-extern unsigned cpp_classify_number PARAMS ((cpp_reader *, const cpp_token *));
+extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *);
 
 /* Evaluate a token classified as category CPP_N_INTEGER.  */
-extern cpp_num cpp_interpret_integer PARAMS ((cpp_reader *, const cpp_token *,
-                                             unsigned int type));
+extern cpp_num cpp_interpret_integer (cpp_reader *, const cpp_token *,
+                                     unsigned int type);
 
 /* Sign extend a number, with PRECISION significant bits and all
    others assumed clear, to fill out a cpp_num structure.  */
-cpp_num cpp_num_sign_extend PARAMS ((cpp_num, size_t));
+cpp_num cpp_num_sign_extend (cpp_num, size_t);
 
-/* Diagnostic levels.  To get a dianostic without associating a
+/* Diagnostic levels.  To get a diagnostic without associating a
    position in the translation unit with it, use cpp_error_with_line
    with a line number of zero.  */
 
 /* Warning, an error with -Werror.  */
-#define DL_WARNING             0x00
-/* Same as DL_WARNING, except it is not suppressed in system headers.  */
-#define DL_WARNING_SYSHDR      0x01
+#define CPP_DL_WARNING         0x00
+/* Same as CPP_DL_WARNING, except it is not suppressed in system headers.  */
+#define CPP_DL_WARNING_SYSHDR  0x01
 /* Warning, an error with -pedantic-errors or -Werror.  */
-#define DL_PEDWARN             0x02
+#define CPP_DL_PEDWARN         0x02
 /* An error.  */
-#define DL_ERROR               0x03
+#define CPP_DL_ERROR           0x03
 /* An internal consistency check failed.  Prints "internal error: ",
-   otherwise the same as DL_ERROR.  */
-#define DL_ICE                 0x04
+   otherwise the same as CPP_DL_ERROR.  */
+#define CPP_DL_ICE             0x04
 /* Extracts a diagnostic level from an int.  */
-#define DL_EXTRACT(l)          (l & 0xf)
+#define CPP_DL_EXTRACT(l)      (l & 0xf)
 /* Nonzero if a diagnostic level is one of the warnings.  */
-#define DL_WARNING_P(l)                (DL_EXTRACT (l) >= DL_WARNING \
-                                && DL_EXTRACT (l) <= DL_PEDWARN)
+#define CPP_DL_WARNING_P(l)    (CPP_DL_EXTRACT (l) >= CPP_DL_WARNING \
+                                && CPP_DL_EXTRACT (l) <= CPP_DL_PEDWARN)
 
 /* N.B. The error-message-printer prototypes have not been nicely
    formatted because exgettext needs to see 'msgid' on the same line
@@ -709,60 +693,63 @@ cpp_num cpp_num_sign_extend PARAMS ((cpp_num, size_t));
    getting ridiculously oversized.  */
 
 /* Output a diagnostic of some kind.  */
-extern void cpp_error PARAMS ((cpp_reader *, int, const char *msgid, ...))
+extern void cpp_error (cpp_reader *, int, const char *msgid, ...)
   ATTRIBUTE_PRINTF_3;
 
-/* Output a diagnostic of severity LEVEL, with "MSG: " preceding the
+/* Output a diagnostic with "MSGID: " preceding the
    error string of errno.  No location is printed.  */
-extern void cpp_errno PARAMS ((cpp_reader *, int level, const char *msg));
+extern void cpp_errno (cpp_reader *, int, const char *msgid);
 
 /* Same as cpp_error, except additionally specifies a position as a
    (translation unit) physical line and physical column.  If the line is
    zero, then no location is printed.  */
-extern void cpp_error_with_line PARAMS ((cpp_reader *, int, unsigned, unsigned, const char *msgid, ...))
-  ATTRIBUTE_PRINTF_5;
+extern void cpp_error_with_line (cpp_reader *, int, fileline, unsigned,
+                                const char *msgid, ...) ATTRIBUTE_PRINTF_5;
 
 /* In cpplex.c */
-extern int cpp_ideq                    PARAMS ((const cpp_token *,
-                                                const char *));
-extern void cpp_output_line            PARAMS ((cpp_reader *, FILE *));
-extern void cpp_output_token           PARAMS ((const cpp_token *, FILE *));
-extern const char *cpp_type2name       PARAMS ((enum cpp_ttype));
+extern int cpp_ideq (const cpp_token *, const char *);
+extern void cpp_output_line (cpp_reader *, FILE *);
+extern void cpp_output_token (const cpp_token *, FILE *);
+extern const char *cpp_type2name (enum cpp_ttype);
 /* Returns the value of an escape sequence, truncated to the correct
    target precision.  PSTR points to the input pointer, which is just
    after the backslash.  LIMIT is how much text we have.  WIDE is true
    if the escape sequence is part of a wide character constant or
    string literal.  Handles all relevant diagnostics.  */
-extern cppchar_t cpp_parse_escape      PARAMS ((cpp_reader *,
-                                                const unsigned char ** pstr,
-                                                const unsigned char *limit,
-                                                int wide));
+extern cppchar_t cpp_parse_escape (cpp_reader *, const unsigned char ** pstr,
+                                  const unsigned char *limit, int wide);
 
 /* In cpphash.c */
 
 /* Lookup an identifier in the hashtable.  Puts the identifier in the
    table if it is not already there.  */
-extern cpp_hashnode *cpp_lookup                PARAMS ((cpp_reader *,
-                                                const unsigned char *,
-                                                unsigned int));
+extern cpp_hashnode *cpp_lookup (cpp_reader *, const unsigned char *,
+                                unsigned int);
 
-typedef int (*cpp_cb) PARAMS ((cpp_reader *, cpp_hashnode *, void *));
-extern void cpp_forall_identifiers     PARAMS ((cpp_reader *,
-                                                cpp_cb, void *));
+typedef int (*cpp_cb) (cpp_reader *, cpp_hashnode *, void *);
+extern void cpp_forall_identifiers (cpp_reader *, cpp_cb, void *);
 
 /* In cppmacro.c */
-extern void cpp_scan_nooutput          PARAMS ((cpp_reader *));
-extern int  cpp_sys_macro_p            PARAMS ((cpp_reader *));
-extern unsigned char *cpp_quote_string PARAMS ((unsigned char *,
-                                                const unsigned char *,
-                                                unsigned int));
+extern void cpp_scan_nooutput (cpp_reader *);
+extern int  cpp_sys_macro_p (cpp_reader *);
+extern unsigned char *cpp_quote_string (unsigned char *, const unsigned char *,
+                                       unsigned int);
 
 /* In cppfiles.c */
-extern int cpp_included        PARAMS ((cpp_reader *, const char *));
-extern void cpp_make_system_header PARAMS ((cpp_reader *, int, int));
-
-/* In cppmain.c */
-extern void cpp_preprocess_file PARAMS ((cpp_reader *, const char *, FILE *));
+extern bool cpp_included (cpp_reader *, const char *);
+extern void cpp_make_system_header (cpp_reader *, int, int);
+extern bool cpp_push_include (cpp_reader *, const char *);
+extern void cpp_change_file (cpp_reader *, enum lc_reason, const char *);
+
+/* In cpppch.c */
+struct save_macro_data;
+extern int cpp_save_state (cpp_reader *, FILE *);
+extern int cpp_write_pch_deps (cpp_reader *, FILE *);
+extern int cpp_write_pch_state (cpp_reader *, FILE *);
+extern int cpp_valid_state (cpp_reader *, const char *, int);
+extern void cpp_prepare_state (cpp_reader *, struct save_macro_data **);
+extern int cpp_read_state (cpp_reader *, const char *, FILE *,
+                          struct save_macro_data *);
 
 #ifdef __cplusplus
 }
index 60646bce20eeaa97a1ee8785a55c33cff3496caf..59e3f582359c8596ace49e286424f85e1884c8ca 100644 (file)
@@ -1,6 +1,6 @@
 /* Part of CPP library.  (Macro and #define handling.)
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Written by Per Bothner, 1994.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -40,57 +40,48 @@ struct macro_arg
 
 /* Macro expansion.  */
 
-static int enter_macro_context PARAMS ((cpp_reader *, cpp_hashnode *));
-static int builtin_macro PARAMS ((cpp_reader *, cpp_hashnode *));
-static void push_token_context
-  PARAMS ((cpp_reader *, cpp_hashnode *, const cpp_token *, unsigned int));
-static void push_ptoken_context
-  PARAMS ((cpp_reader *, cpp_hashnode *, _cpp_buff *,
-          const cpp_token **, unsigned int));
-static _cpp_buff *collect_args PARAMS ((cpp_reader *, const cpp_hashnode *));
-static cpp_context *next_context PARAMS ((cpp_reader *));
-static const cpp_token *padding_token
-  PARAMS ((cpp_reader *, const cpp_token *));
-static void expand_arg PARAMS ((cpp_reader *, macro_arg *));
-static const cpp_token *new_string_token PARAMS ((cpp_reader *, uchar *,
-                                                 unsigned int));
-static const cpp_token *stringify_arg PARAMS ((cpp_reader *, macro_arg *));
-static void paste_all_tokens PARAMS ((cpp_reader *, const cpp_token *));
-static bool paste_tokens PARAMS ((cpp_reader *, const cpp_token **,
-                                 const cpp_token *));
-static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, cpp_macro *,
-                                 macro_arg *));
-static _cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
-static bool create_iso_definition PARAMS ((cpp_reader *, cpp_macro *));
+static int enter_macro_context (cpp_reader *, cpp_hashnode *);
+static int builtin_macro (cpp_reader *, cpp_hashnode *);
+static void push_token_context (cpp_reader *, cpp_hashnode *,
+                               const cpp_token *, unsigned int);
+static void push_ptoken_context (cpp_reader *, cpp_hashnode *, _cpp_buff *,
+                                const cpp_token **, unsigned int);
+static _cpp_buff *collect_args (cpp_reader *, const cpp_hashnode *);
+static cpp_context *next_context (cpp_reader *);
+static const cpp_token *padding_token (cpp_reader *, const cpp_token *);
+static void expand_arg (cpp_reader *, macro_arg *);
+static const cpp_token *new_string_token (cpp_reader *, uchar *, unsigned int);
+static const cpp_token *stringify_arg (cpp_reader *, macro_arg *);
+static void paste_all_tokens (cpp_reader *, const cpp_token *);
+static bool paste_tokens (cpp_reader *, const cpp_token **, const cpp_token *);
+static void replace_args (cpp_reader *, cpp_hashnode *, cpp_macro *,
+                         macro_arg *);
+static _cpp_buff *funlike_invocation_p (cpp_reader *, cpp_hashnode *);
+static bool create_iso_definition (cpp_reader *, cpp_macro *);
 
 /* #define directive parsing and handling.  */
 
-static cpp_token *alloc_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
-static cpp_token *lex_expansion_token PARAMS ((cpp_reader *, cpp_macro *));
-static bool warn_of_redefinition PARAMS ((cpp_reader *, const cpp_hashnode *,
-                                         const cpp_macro *));
-static bool parse_params PARAMS ((cpp_reader *, cpp_macro *));
-static void check_trad_stringification PARAMS ((cpp_reader *,
-                                               const cpp_macro *,
-                                               const cpp_string *));
+static cpp_token *alloc_expansion_token (cpp_reader *, cpp_macro *);
+static cpp_token *lex_expansion_token (cpp_reader *, cpp_macro *);
+static bool warn_of_redefinition (cpp_reader *, const cpp_hashnode *,
+                                 const cpp_macro *);
+static bool parse_params (cpp_reader *, cpp_macro *);
+static void check_trad_stringification (cpp_reader *, const cpp_macro *,
+                                       const cpp_string *);
 
 /* Emits a warning if NODE is a macro defined in the main file that
    has not been used.  */
 int
-_cpp_warn_if_unused_macro (pfile, node, v)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
-     void *v ATTRIBUTE_UNUSED;
+_cpp_warn_if_unused_macro (cpp_reader *pfile, cpp_hashnode *node,
+                          void *v ATTRIBUTE_UNUSED)
 {
   if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
     {
       cpp_macro *macro = node->value.macro;
 
       if (!macro->used
-         /* Skip front-end built-ins and command line macros.  */
-         && macro->line >= pfile->first_unused_line
-         && MAIN_FILE_P (lookup_line (&pfile->line_maps, macro->line)))
-       cpp_error_with_line (pfile, DL_WARNING, macro->line, 0,
+         && MAIN_FILE_P (linemap_lookup (&pfile->line_maps, macro->line)))
+       cpp_error_with_line (pfile, CPP_DL_WARNING, macro->line, 0,
                             "macro \"%s\" is not used", NODE_NAME (node));
     }
 
@@ -100,10 +91,7 @@ _cpp_warn_if_unused_macro (pfile, node, v)
 /* Allocates and returns a CPP_STRING token, containing TEXT of length
    LEN, after null-terminating it.  TEXT must be in permanent storage.  */
 static const cpp_token *
-new_string_token (pfile, text, len)
-     cpp_reader *pfile;
-     unsigned char *text;
-     unsigned int len;
+new_string_token (cpp_reader *pfile, unsigned char *text, unsigned int len)
 {
   cpp_token *token = _cpp_temp_token (pfile);
 
@@ -126,9 +114,7 @@ static const char * const monthnames[] =
    is created.  Returns 1 if it generates a new token context, 0 to
    return the token to the caller.  */
 const uchar *
-_cpp_builtin_macro_text (pfile, node)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
+_cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node)
 {
   const uchar *result = NULL;
   unsigned int number = 1;
@@ -136,7 +122,7 @@ _cpp_builtin_macro_text (pfile, node)
   switch (node->value.builtin)
     {
     default:
-      cpp_error (pfile, DL_ICE, "invalid built-in macro \"%s\"",
+      cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"",
                 NODE_NAME (node));
       break;
 
@@ -221,7 +207,8 @@ _cpp_builtin_macro_text (pfile, node)
              pfile->date = _cpp_unaligned_alloc (pfile,
                                                  sizeof ("\"Oct 11 1347\""));
              sprintf ((char *) pfile->date, "\"%s %2d %4d\"",
-                      monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
+                      monthnames[tb->tm_mon], tb->tm_mday,
+                      tb->tm_year + 1900);
 
              pfile->time = _cpp_unaligned_alloc (pfile,
                                                  sizeof ("\"12:34:56\""));
@@ -230,7 +217,7 @@ _cpp_builtin_macro_text (pfile, node)
            }
          else
            {
-             cpp_errno (pfile, DL_WARNING,
+             cpp_errno (pfile, CPP_DL_WARNING,
                         "could not determine date and time");
                
              pfile->date = U"\"??? ?? ????\"";
@@ -260,11 +247,11 @@ _cpp_builtin_macro_text (pfile, node)
    created.  Returns 1 if it generates a new token context, 0 to
    return the token to the caller.  */
 static int
-builtin_macro (pfile, node)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
+builtin_macro (cpp_reader *pfile, cpp_hashnode *node)
 {
   const uchar *buf;
+  size_t len;
+  char *nbuf;
 
   if (node->value.builtin == BT_PRAGMA)
     {
@@ -278,20 +265,19 @@ builtin_macro (pfile, node)
     }
 
   buf = _cpp_builtin_macro_text (pfile, node);
+  len = ustrlen (buf);
+  nbuf = alloca (len + 1);
+  memcpy (nbuf, buf, len);
+  nbuf[len]='\n';
 
-  cpp_push_buffer (pfile, buf, ustrlen (buf), /* from_stage3 */ true, 1);
-
-  /* Tweak the column number the lexer will report.  */
-  pfile->buffer->col_adjust = pfile->cur_token[-1].col - 1;
-
-  /* We don't want a leading # to be interpreted as a directive.  */
-  pfile->buffer->saved_flags = 0;
+  cpp_push_buffer (pfile, (uchar *) nbuf, len, /* from_stage3 */ true);
+  _cpp_clean_line (pfile);
 
   /* Set pfile->cur_token as required by _cpp_lex_direct.  */
   pfile->cur_token = _cpp_temp_token (pfile);
   push_token_context (pfile, NULL, _cpp_lex_direct (pfile), 1);
   if (pfile->buffer->cur != pfile->buffer->rlimit)
-    cpp_error (pfile, DL_ICE, "invalid built-in macro \"%s\"",
+    cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"",
               NODE_NAME (node));
   _cpp_pop_buffer (pfile);
 
@@ -303,10 +289,7 @@ builtin_macro (pfile, node)
    converted to octal.  DEST must be of sufficient size.  Returns
    a pointer to the end of the string.  */
 uchar *
-cpp_quote_string (dest, src, len)
-     uchar *dest;
-     const uchar *src;
-     unsigned int len;
+cpp_quote_string (uchar *dest, const uchar *src, unsigned int len)
 {
   while (len--)
     {
@@ -335,15 +318,18 @@ cpp_quote_string (dest, src, len)
 /* Convert a token sequence ARG to a single string token according to
    the rules of the ISO C #-operator.  */
 static const cpp_token *
-stringify_arg (pfile, arg)
-     cpp_reader *pfile;
-     macro_arg *arg;
+stringify_arg (cpp_reader *pfile, macro_arg *arg)
 {
-  unsigned char *dest = BUFF_FRONT (pfile->u_buff);
+  unsigned char *dest;
   unsigned int i, escape_it, backslash_count = 0;
   const cpp_token *source = NULL;
   size_t len;
 
+  if (BUFF_ROOM (pfile->u_buff) < 3)
+    _cpp_extend_buff (pfile, &pfile->u_buff, 3);
+  dest = BUFF_FRONT (pfile->u_buff);
+  *dest++ = '"';
+
   /* Loop, reading in the argument's tokens.  */
   for (i = 0; i < arg->count; i++)
     {
@@ -360,11 +346,11 @@ stringify_arg (pfile, arg)
                   || token->type == CPP_CHAR || token->type == CPP_WCHAR);
 
       /* Room for each char being written in octal, initial space and
-        final NUL.  */
+        final quote and NUL.  */
       len = cpp_token_len (token);
       if (escape_it)
        len *= 4;
-      len += 2;
+      len += 3;
 
       if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len)
        {
@@ -374,7 +360,7 @@ stringify_arg (pfile, arg)
        }
 
       /* Leading white space?  */
-      if (dest != BUFF_FRONT (pfile->u_buff))
+      if (dest - 1 != BUFF_FRONT (pfile->u_buff))
        {
          if (source == NULL)
            source = token;
@@ -394,7 +380,7 @@ stringify_arg (pfile, arg)
       else
        dest = cpp_spell_token (pfile, token, dest);
 
-      if (token->type == CPP_OTHER && token->val.c == '\\')
+      if (token->type == CPP_OTHER && token->val.str.text[0] == '\\')
        backslash_count++;
       else
        backslash_count = 0;
@@ -403,18 +389,13 @@ stringify_arg (pfile, arg)
   /* Ignore the final \ of invalid string literals.  */
   if (backslash_count & 1)
     {
-      cpp_error (pfile, DL_WARNING,
+      cpp_error (pfile, CPP_DL_WARNING,
                 "invalid string literal, ignoring final '\\'");
       dest--;
     }
 
   /* Commit the memory, including NUL, and return the token.  */
-  if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < 1)
-    {
-      size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff);
-      _cpp_extend_buff (pfile, &pfile->u_buff, 1);
-      dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
-    }
+  *dest++ = '"';
   len = dest - BUFF_FRONT (pfile->u_buff);
   BUFF_FRONT (pfile->u_buff) = dest + 1;
   return new_string_token (pfile, dest - len, len);
@@ -424,9 +405,7 @@ stringify_arg (pfile, arg)
    case, PLHS is updated to point to the pasted token, which is
    guaranteed to not have the PASTE_LEFT flag set.  */
 static bool
-paste_tokens (pfile, plhs, rhs)
-     cpp_reader *pfile;
-     const cpp_token **plhs, *rhs;
+paste_tokens (cpp_reader *pfile, const cpp_token **plhs, const cpp_token *rhs)
 {
   unsigned char *buf, *end;
   const cpp_token *lhs;
@@ -435,7 +414,7 @@ paste_tokens (pfile, plhs, rhs)
 
   lhs = *plhs;
   len = cpp_token_len (lhs) + cpp_token_len (rhs) + 1;
-  buf = (unsigned char *) alloca (len);
+  buf = alloca (len);
   end = cpp_spell_token (pfile, lhs, buf);
 
   /* Avoid comment headers, since they are still processed in stage 3.
@@ -445,15 +424,10 @@ paste_tokens (pfile, plhs, rhs)
   if (lhs->type == CPP_DIV && rhs->type != CPP_EQ)
     *end++ = ' ';
   end = cpp_spell_token (pfile, rhs, end);
-  *end = '\0';
-
-  cpp_push_buffer (pfile, buf, end - buf, /* from_stage3 */ true, 1);
+  *end = '\n';
 
-  /* Tweak the column number the lexer will report.  */
-  pfile->buffer->col_adjust = pfile->cur_token[-1].col - 1;
-
-  /* We don't want a leading # to be interpreted as a directive.  */
-  pfile->buffer->saved_flags = 0;
+  cpp_push_buffer (pfile, buf, end - buf, /* from_stage3 */ true);
+  _cpp_clean_line (pfile);
 
   /* Set pfile->cur_token as required by _cpp_lex_direct.  */
   pfile->cur_token = _cpp_temp_token (pfile);
@@ -472,9 +446,7 @@ paste_tokens (pfile, plhs, rhs)
    successful pastes, with the effect that the RHS appears in the
    output stream after the pasted LHS normally.  */
 static void
-paste_all_tokens (pfile, lhs)
-     cpp_reader *pfile;
-     const cpp_token *lhs;
+paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs)
 {
   const cpp_token *rhs;
   cpp_context *context = pfile->context;
@@ -500,7 +472,7 @@ paste_all_tokens (pfile, lhs)
 
          /* Mandatory error for all apart from assembler.  */
          if (CPP_OPTION (pfile, lang) != CLK_ASM)
-           cpp_error (pfile, DL_ERROR,
+           cpp_error (pfile, CPP_DL_ERROR,
         "pasting \"%s\" and \"%s\" does not give a valid preprocessing token",
                       cpp_token_as_text (pfile, lhs),
                       cpp_token_as_text (pfile, rhs));
@@ -520,11 +492,7 @@ paste_all_tokens (pfile, lhs)
    Note that MACRO cannot necessarily be deduced from NODE, in case
    NODE was redefined whilst collecting arguments.  */
 bool
-_cpp_arguments_ok (pfile, macro, node, argc)
-     cpp_reader *pfile;
-     cpp_macro *macro;
-     const cpp_hashnode *node;
-     unsigned int argc;
+_cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node, unsigned int argc)
 {
   if (argc == macro->paramc)
     return true;
@@ -542,17 +510,17 @@ _cpp_arguments_ok (pfile, macro, node, argc)
       if (argc + 1 == macro->paramc && macro->variadic)
        {
          if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
-           cpp_error (pfile, DL_PEDWARN,
+           cpp_error (pfile, CPP_DL_PEDWARN,
                       "ISO C99 requires rest arguments to be used");
          return true;
        }
 
-      cpp_error (pfile, DL_ERROR,
+      cpp_error (pfile, CPP_DL_ERROR,
                 "macro \"%s\" requires %u arguments, but only %u given",
                 NODE_NAME (node), macro->paramc, argc);
     }
   else
-    cpp_error (pfile, DL_ERROR,
+    cpp_error (pfile, CPP_DL_ERROR,
               "macro \"%s\" passed %u arguments, but takes just %u",
               NODE_NAME (node), argc, macro->paramc);
 
@@ -565,9 +533,7 @@ _cpp_arguments_ok (pfile, macro, node, argc)
    NULL.  Each argument is terminated by a CPP_EOF token, for the
    future benefit of expand_arg().  */
 static _cpp_buff *
-collect_args (pfile, node)
-     cpp_reader *pfile;
-     const cpp_hashnode *node;
+collect_args (cpp_reader *pfile, const cpp_hashnode *node)
 {
   _cpp_buff *buff, *base_buff;
   cpp_macro *macro;
@@ -665,7 +631,7 @@ collect_args (pfile, node)
         callers at the end of an -include-d file.  */
       if (pfile->context->prev || pfile->state.in_directive)
        _cpp_backup_tokens (pfile, 1);
-      cpp_error (pfile, DL_ERROR,
+      cpp_error (pfile, CPP_DL_ERROR,
                 "unterminated argument list invoking macro \"%s\"",
                 NODE_NAME (node));
     }
@@ -701,9 +667,7 @@ collect_args (pfile, node)
    intervening padding tokens.  If we find the parenthesis, collect
    the arguments and return the buffer containing them.  */
 static _cpp_buff *
-funlike_invocation_p (pfile, node)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
+funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node)
 {
   const cpp_token *token, *padding = NULL;
 
@@ -743,9 +707,7 @@ funlike_invocation_p (pfile, node)
    containing its yet-to-be-rescanned replacement list and return one.
    Otherwise, we don't push a context and return zero.  */
 static int
-enter_macro_context (pfile, node)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
+enter_macro_context (cpp_reader *pfile, cpp_hashnode *node)
 {
   /* The presence of a macro invalidates a file's controlling macro.  */
   pfile->mi_valid = false;
@@ -772,7 +734,7 @@ enter_macro_context (pfile, node)
          if (buff == NULL)
            {
              if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
-               cpp_error (pfile, DL_WARNING,
+               cpp_error (pfile, CPP_DL_WARNING,
  "function-like macro \"%s\" must be used with arguments in traditional C",
                           NODE_NAME (node));
 
@@ -804,11 +766,7 @@ enter_macro_context (pfile, node)
    Expand each argument before replacing, unless it is operated upon
    by the # or ## operators.  */
 static void
-replace_args (pfile, node, macro, args)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
-     cpp_macro *macro;
-     macro_arg *args;
+replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg *args)
 {
   unsigned int i, total;
   const cpp_token *src, *limit;
@@ -940,9 +898,7 @@ replace_args (pfile, node, macro, args)
 
 /* Return a special padding token, with padding inherited from SOURCE.  */
 static const cpp_token *
-padding_token (pfile, source)
-     cpp_reader *pfile;
-     const cpp_token *source;
+padding_token (cpp_reader *pfile, const cpp_token *source)
 {
   cpp_token *result = _cpp_temp_token (pfile);
 
@@ -955,8 +911,7 @@ padding_token (pfile, source)
 /* Get a new uninitialized context.  Create a new one if we cannot
    re-use an old one.  */
 static cpp_context *
-next_context (pfile)
-     cpp_reader *pfile;
+next_context (cpp_reader *pfile)
 {
   cpp_context *result = pfile->context->next;
 
@@ -974,12 +929,8 @@ next_context (pfile)
 
 /* Push a list of pointers to tokens.  */
 static void
-push_ptoken_context (pfile, macro, buff, first, count)
-     cpp_reader *pfile;
-     cpp_hashnode *macro;
-     _cpp_buff *buff;
-     const cpp_token **first;
-     unsigned int count;
+push_ptoken_context (cpp_reader *pfile, cpp_hashnode *macro, _cpp_buff *buff,
+                    const cpp_token **first, unsigned int count)
 {
   cpp_context *context = next_context (pfile);
 
@@ -992,11 +943,8 @@ push_ptoken_context (pfile, macro, buff, first, count)
 
 /* Push a list of tokens.  */
 static void
-push_token_context (pfile, macro, first, count)
-     cpp_reader *pfile;
-     cpp_hashnode *macro;
-     const cpp_token *first;
-     unsigned int count;
+push_token_context (cpp_reader *pfile, cpp_hashnode *macro,
+                   const cpp_token *first, unsigned int count)
 {
   cpp_context *context = next_context (pfile);
 
@@ -1009,11 +957,8 @@ push_token_context (pfile, macro, first, count)
 
 /* Push a traditional macro's replacement text.  */
 void
-_cpp_push_text_context (pfile, macro, start, len)
-     cpp_reader *pfile;
-     cpp_hashnode *macro;
-     const uchar *start;
-     size_t len;
+_cpp_push_text_context (cpp_reader *pfile, cpp_hashnode *macro,
+                       const uchar *start, size_t len)
 {
   cpp_context *context = next_context (pfile);
 
@@ -1032,9 +977,7 @@ _cpp_push_text_context (pfile, macro, start, len)
    has terminated the argument's tokens with a CPP_EOF so that we know
    when we have fully expanded the argument.  */
 static void
-expand_arg (pfile, arg)
-     cpp_reader *pfile;
-     macro_arg *arg;
+expand_arg (cpp_reader *pfile, macro_arg *arg)
 {
   unsigned int capacity;
   bool saved_warn_trad;
@@ -1048,8 +991,7 @@ expand_arg (pfile, arg)
 
   /* Loop, reading in the arguments.  */
   capacity = 256;
-  arg->expanded = (const cpp_token **)
-    xmalloc (capacity * sizeof (cpp_token *));
+  arg->expanded = xmalloc (capacity * sizeof (cpp_token *));
 
   push_ptoken_context (pfile, NULL, NULL, arg->first, arg->count + 1);
   for (;;)
@@ -1059,8 +1001,8 @@ expand_arg (pfile, arg)
       if (arg->expanded_count + 1 >= capacity)
        {
          capacity *= 2;
-         arg->expanded = (const cpp_token **)
-           xrealloc (arg->expanded, capacity * sizeof (cpp_token *));
+         arg->expanded = xrealloc (arg->expanded,
+                                   capacity * sizeof (cpp_token *));
        }
 
       token = cpp_get_token (pfile);
@@ -1080,8 +1022,7 @@ expand_arg (pfile, arg)
    context represented a macro's replacement list.  The context
    structure is not freed so that we can re-use it later.  */
 void
-_cpp_pop_context (pfile)
-     cpp_reader *pfile;
+_cpp_pop_context (cpp_reader *pfile)
 {
   cpp_context *context = pfile->context;
 
@@ -1094,9 +1035,9 @@ _cpp_pop_context (pfile)
   pfile->context = context->prev;
 }
 
-/* Eternal routine to get a token.  Also used nearly everywhere
+/* External routine to get a token.  Also used nearly everywhere
    internally, except for places where we know we can safely call
-   the lexer directly, such as lexing a directive name.
+   _cpp_lex_token directly, such as lexing a directive name.
 
    Macro expansions and directives are transparently handled,
    including entering included files.  Thus tokens are post-macro
@@ -1106,8 +1047,7 @@ _cpp_pop_context (pfile)
    state.in_directive is still 1, and at the end of argument
    pre-expansion.  */
 const cpp_token *
-cpp_get_token (pfile)
-     cpp_reader *pfile;
+cpp_get_token (cpp_reader *pfile)
 {
   const cpp_token *result;
 
@@ -1184,8 +1124,7 @@ cpp_get_token (pfile)
    defined in a system header.  Just checks the macro at the top of
    the stack.  Used for diagnostic suppression.  */
 int
-cpp_sys_macro_p (pfile)
-     cpp_reader *pfile;
+cpp_sys_macro_p (cpp_reader *pfile)
 {
   cpp_hashnode *node = pfile->context->macro;
 
@@ -1195,8 +1134,7 @@ cpp_sys_macro_p (pfile)
 /* Read each token in, until end of the current file.  Directives are
    transparently processed.  */
 void
-cpp_scan_nooutput (pfile)
-     cpp_reader *pfile;
+cpp_scan_nooutput (cpp_reader *pfile)
 {
   /* Request a CPP_EOF token at the end of this file, rather than
      transparently continuing with the including file.  */
@@ -1213,9 +1151,7 @@ cpp_scan_nooutput (pfile)
 /* Step back one (or more) tokens.  Can only step mack more than 1 if
    they are from the lexer, and not from macro expansion.  */
 void
-_cpp_backup_tokens (pfile, count)
-     cpp_reader *pfile;
-     unsigned int count;
+_cpp_backup_tokens (cpp_reader *pfile, unsigned int count)
 {
   if (pfile->context->prev == NULL)
     {
@@ -1247,10 +1183,8 @@ _cpp_backup_tokens (pfile, count)
 
 /* Returns nonzero if a macro redefinition warning is required.  */
 static bool
-warn_of_redefinition (pfile, node, macro2)
-     cpp_reader *pfile;
-     const cpp_hashnode *node;
-     const cpp_macro *macro2;
+warn_of_redefinition (cpp_reader *pfile, const cpp_hashnode *node,
+                     const cpp_macro *macro2)
 {
   const cpp_macro *macro1;
   unsigned int i;
@@ -1291,8 +1225,7 @@ warn_of_redefinition (pfile, node, macro2)
 
 /* Free the definition of hashnode H.  */
 void
-_cpp_free_definition (h)
-     cpp_hashnode *h;
+_cpp_free_definition (cpp_hashnode *h)
 {
   /* Macros and assertions no longer have anything to free.  */
   h->type = NT_VOID;
@@ -1303,15 +1236,13 @@ _cpp_free_definition (h)
 /* Save parameter NODE to the parameter list of macro MACRO.  Returns
    zero on success, nonzero if the parameter is a duplicate.  */
 bool
-_cpp_save_parameter (pfile, macro, node)
-     cpp_reader *pfile;
-     cpp_macro *macro;
-     cpp_hashnode *node;
+_cpp_save_parameter (cpp_reader *pfile, cpp_macro *macro, cpp_hashnode *node)
 {
+  unsigned int len;
   /* Constraint 6.10.3.6 - duplicate parameter names.  */
-  if (node->arg_index)
+  if (node->flags & NODE_MACRO_ARG)
     {
-      cpp_error (pfile, DL_ERROR, "duplicate macro parameter \"%s\"",
+      cpp_error (pfile, CPP_DL_ERROR, "duplicate macro parameter \"%s\"",
                 NODE_NAME (node));
       return true;
     }
@@ -1321,16 +1252,24 @@ _cpp_save_parameter (pfile, macro, node)
     _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *));
 
   ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node;
-  node->arg_index = macro->paramc;
+  node->flags |= NODE_MACRO_ARG;
+  len = macro->paramc * sizeof (union _cpp_hashnode_value);
+  if (len > pfile->macro_buffer_len)
+    {
+      pfile->macro_buffer = xrealloc (pfile->macro_buffer, len);
+      pfile->macro_buffer_len = len;
+    }
+  ((union _cpp_hashnode_value *) pfile->macro_buffer)[macro->paramc - 1]
+    = node->value;
+  
+  node->value.arg_index  = macro->paramc;
   return false;
 }
 
 /* Check the syntax of the parameters in a MACRO definition.  Returns
    false if an error occurs.  */
 static bool
-parse_params (pfile, macro)
-     cpp_reader *pfile;
-     cpp_macro *macro;
+parse_params (cpp_reader *pfile, cpp_macro *macro)
 {
   unsigned int prev_ident = 0;
 
@@ -1347,7 +1286,7 @@ parse_params (pfile, macro)
              && ! CPP_OPTION (pfile, discard_comments_in_macro_exp))
            continue;
 
-         cpp_error (pfile, DL_ERROR,
+         cpp_error (pfile, CPP_DL_ERROR,
                     "\"%s\" may not appear in macro parameter list",
                     cpp_token_as_text (pfile, token));
          return false;
@@ -1355,7 +1294,7 @@ parse_params (pfile, macro)
        case CPP_NAME:
          if (prev_ident)
            {
-             cpp_error (pfile, DL_ERROR,
+             cpp_error (pfile, CPP_DL_ERROR,
                         "macro parameters must be comma-separated");
              return false;
            }
@@ -1373,7 +1312,7 @@ parse_params (pfile, macro)
        case CPP_COMMA:
          if (!prev_ident)
            {
-             cpp_error (pfile, DL_ERROR, "parameter name missing");
+             cpp_error (pfile, CPP_DL_ERROR, "parameter name missing");
              return false;
            }
          prev_ident = 0;
@@ -1387,11 +1326,11 @@ parse_params (pfile, macro)
                                   pfile->spec_nodes.n__VA_ARGS__);
              pfile->state.va_args_ok = 1;
              if (! CPP_OPTION (pfile, c99) && CPP_OPTION (pfile, pedantic))
-               cpp_error (pfile, DL_PEDWARN,
+               cpp_error (pfile, CPP_DL_PEDWARN,
                           "anonymous variadic macros were introduced in C99");
            }
          else if (CPP_OPTION (pfile, pedantic))
-           cpp_error (pfile, DL_PEDWARN,
+           cpp_error (pfile, CPP_DL_PEDWARN,
                       "ISO C does not permit named variadic macros");
 
          /* We're at the end, and just expect a closing parenthesis.  */
@@ -1401,7 +1340,7 @@ parse_params (pfile, macro)
          /* Fall through.  */
 
        case CPP_EOF:
-         cpp_error (pfile, DL_ERROR, "missing ')' in macro parameter list");
+         cpp_error (pfile, CPP_DL_ERROR, "missing ')' in macro parameter list");
          return false;
        }
     }
@@ -1409,9 +1348,7 @@ parse_params (pfile, macro)
 
 /* Allocate room for a token from a macro's replacement list.  */
 static cpp_token *
-alloc_expansion_token (pfile, macro)
-     cpp_reader *pfile;
-     cpp_macro *macro;
+alloc_expansion_token (cpp_reader *pfile, cpp_macro *macro)
 {
   if (BUFF_ROOM (pfile->a_buff) < (macro->count + 1) * sizeof (cpp_token))
     _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_token));
@@ -1422,9 +1359,7 @@ alloc_expansion_token (pfile, macro)
 /* Lex a token from the expansion of MACRO, but mark parameters as we
    find them and warn of traditional stringification.  */
 static cpp_token *
-lex_expansion_token (pfile, macro)
-     cpp_reader *pfile;
-     cpp_macro *macro;
+lex_expansion_token (cpp_reader *pfile, cpp_macro *macro)
 {
   cpp_token *token;
 
@@ -1432,10 +1367,11 @@ lex_expansion_token (pfile, macro)
   token = _cpp_lex_direct (pfile);
 
   /* Is this a parameter?  */
-  if (token->type == CPP_NAME && token->val.node->arg_index)
+  if (token->type == CPP_NAME
+      && (token->val.node->flags & NODE_MACRO_ARG) != 0)
     {
       token->type = CPP_MACRO_ARG;
-      token->val.arg_no = token->val.node->arg_index;
+      token->val.arg_no = token->val.node->value.arg_index;
     }
   else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0
           && (token->type == CPP_STRING || token->type == CPP_CHAR))
@@ -1445,9 +1381,7 @@ lex_expansion_token (pfile, macro)
 }
 
 static bool
-create_iso_definition (pfile, macro)
-     cpp_reader *pfile;
-     cpp_macro *macro;
+create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
 {
   cpp_token *token;
   const cpp_token *ctoken;
@@ -1468,7 +1402,7 @@ create_iso_definition (pfile, macro)
       macro->fun_like = 1;
     }
   else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE))
-    cpp_error (pfile, DL_PEDWARN,
+    cpp_error (pfile, CPP_DL_PEDWARN,
               "ISO C requires whitespace after the macro name");
 
   if (macro->fun_like)
@@ -1497,7 +1431,7 @@ create_iso_definition (pfile, macro)
          else if ((CPP_OPTION (pfile, lang) != CLK_ASM)
                && (!CPP_OPTION(pfile, allow_naked_hash)))
            {
-             cpp_error (pfile, DL_ERROR,
+             cpp_error (pfile, CPP_DL_ERROR,
                         "'#' is not followed by a macro parameter");
              return false;
            }
@@ -1516,8 +1450,8 @@ create_iso_definition (pfile, macro)
 
          if (macro->count == 0 || token->type == CPP_EOF)
            {
-             cpp_error (pfile, DL_ERROR,
-                        "'##' cannot appear at either end of a macro expansion");
+             cpp_error (pfile, CPP_DL_ERROR,
+                "'##' cannot appear at either end of a macro expansion");
              return false;
            }
 
@@ -1544,9 +1478,7 @@ create_iso_definition (pfile, macro)
 
 /* Parse a macro and save its expansion.  Returns nonzero on success.  */
 bool
-_cpp_create_definition (pfile, node)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
+_cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node)
 {
   cpp_macro *macro;
   unsigned int i;
@@ -1557,7 +1489,7 @@ _cpp_create_definition (pfile, node)
   macro->params = 0;
   macro->paramc = 0;
   macro->variadic = 0;
-  macro->used = 0;
+  macro->used = !CPP_OPTION (pfile, warn_unused_macros);
   macro->count = 0;
   macro->fun_like = 0;
   /* To suppress some diagnostics.  */
@@ -1586,7 +1518,11 @@ _cpp_create_definition (pfile, node)
 
   /* Clear the fast argument lookup indices.  */
   for (i = macro->paramc; i-- > 0; )
-    macro->params[i]->arg_index = 0;
+    {
+      struct cpp_hashnode *node = macro->params[i];
+      node->flags &= ~ NODE_MACRO_ARG;
+      node->value = ((union _cpp_hashnode_value *) pfile->macro_buffer)[i];
+    }
 
   if (!ok)
     return ok;
@@ -1598,11 +1534,11 @@ _cpp_create_definition (pfile, node)
 
       if (warn_of_redefinition (pfile, node, macro))
        {
-         cpp_error_with_line (pfile, DL_PEDWARN, pfile->directive_line, 0,
+         cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->directive_line, 0,
                               "\"%s\" redefined", NODE_NAME (node));
 
          if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
-           cpp_error_with_line (pfile, DL_PEDWARN,
+           cpp_error_with_line (pfile, CPP_DL_PEDWARN,
                                 node->value.macro->line, 0,
                         "this is the location of the previous definition");
        }
@@ -1623,16 +1559,15 @@ _cpp_create_definition (pfile, node)
 /* Warn if a token in STRING matches one of a function-like MACRO's
    parameters.  */
 static void
-check_trad_stringification (pfile, macro, string)
-     cpp_reader *pfile;
-     const cpp_macro *macro;
-     const cpp_string *string;
+check_trad_stringification (cpp_reader *pfile, const cpp_macro *macro,
+                           const cpp_string *string)
 {
   unsigned int i, len;
-  const uchar *p, *q, *limit = string->text + string->len;
+  const uchar *p, *q, *limit;
 
   /* Loop over the string.  */
-  for (p = string->text; p < limit; p = q)
+  limit = string->text + string->len - 1;
+  for (p = string->text + 1; p < limit; p = q)
     {
       /* Find the start of an identifier.  */
       while (p < limit && !is_idstart (*p))
@@ -1654,7 +1589,7 @@ check_trad_stringification (pfile, macro, string)
          if (NODE_LEN (node) == len
              && !memcmp (p, NODE_NAME (node), len))
            {
-             cpp_error (pfile, DL_WARNING,
+             cpp_error (pfile, CPP_DL_WARNING,
           "macro argument \"%s\" would be stringified in traditional C",
                         NODE_NAME (node));
              break;
@@ -1669,9 +1604,7 @@ check_trad_stringification (pfile, macro, string)
    Caller is expected to generate the "#define" bit if needed.  The
    returned text is temporary, and automatically freed later.  */
 const unsigned char *
-cpp_macro_definition (pfile, node)
-     cpp_reader *pfile;
-     const cpp_hashnode *node;
+cpp_macro_definition (cpp_reader *pfile, const cpp_hashnode *node)
 {
   unsigned int i, len;
   const cpp_macro *macro = node->value.macro;
@@ -1679,7 +1612,7 @@ cpp_macro_definition (pfile, node)
 
   if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
     {
-      cpp_error (pfile, DL_ICE,
+      cpp_error (pfile, CPP_DL_ICE,
                 "invalid hash type %d in cpp_macro_definition", node->type);
       return 0;
     }
@@ -1694,6 +1627,7 @@ cpp_macro_definition (pfile, node)
        len += NODE_LEN (macro->params[i]) + 1; /* "," */
     }
 
+  /* This should match below where we fill in the buffer.  */
   if (CPP_OPTION (pfile, traditional))
     len += _cpp_replacement_text_len (macro);
   else
@@ -1705,17 +1639,20 @@ cpp_macro_definition (pfile, node)
          if (token->type == CPP_MACRO_ARG)
            len += NODE_LEN (macro->params[token->val.arg_no - 1]);
          else
-           len += cpp_token_len (token); /* Includes room for ' '.  */
+           len += cpp_token_len (token);
+
          if (token->flags & STRINGIFY_ARG)
            len++;                      /* "#" */
          if (token->flags & PASTE_LEFT)
            len += 3;           /* " ##" */
+         if (token->flags & PREV_WHITE)
+           len++;              /* " " */
        }
     }
 
   if (len > pfile->macro_buffer_len)
     {
-      pfile->macro_buffer = (uchar *) xrealloc (pfile->macro_buffer, len);
+      pfile->macro_buffer = xrealloc (pfile->macro_buffer, len);
       pfile->macro_buffer_len = len;
     }
 
@@ -1769,10 +1706,10 @@ cpp_macro_definition (pfile, node)
 
          if (token->type == CPP_MACRO_ARG)
            {
-             len = NODE_LEN (macro->params[token->val.arg_no - 1]);
              memcpy (buffer,
-                     NODE_NAME (macro->params[token->val.arg_no - 1]), len);
-             buffer += len;
+                     NODE_NAME (macro->params[token->val.arg_no - 1]),
+                     NODE_LEN (macro->params[token->val.arg_no - 1]));
+             buffer += NODE_LEN (macro->params[token->val.arg_no - 1]);
            }
          else
            buffer = cpp_spell_token (pfile, token, buffer);
index 27cce2f6e280cf3de8dc45e420abe68658d45638..6315b1074f5131599a0ff2cc47ff5a678767bb84 100644 (file)
@@ -1,5 +1,5 @@
 /* CPP Library - traditional lexical analysis and macro expansion.
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
    Contributed by Neil Booth, May 2002
 
 This program is free software; you can redistribute it and/or modify it
@@ -79,33 +79,24 @@ enum ls {ls_none = 0,               /* Normal state.  */
 /* Lexing TODO: Maybe handle space in escaped newlines.  Stop cpplex.c
    from recognizing comments and directives during its lexing pass.  */
 
-static const uchar *handle_newline PARAMS ((cpp_reader *, const uchar *));
-static const uchar *skip_escaped_newlines PARAMS ((cpp_reader *,
-                                                  const uchar *));
-static const uchar *skip_whitespace PARAMS ((cpp_reader *, const uchar *,
-                                            int));
-static cpp_hashnode *lex_identifier PARAMS ((cpp_reader *, const uchar *));
-static const uchar *copy_comment PARAMS ((cpp_reader *, const uchar *, int));
-static void scan_out_logical_line PARAMS ((cpp_reader *pfile, cpp_macro *));
-static void check_output_buffer PARAMS ((cpp_reader *, size_t));
-static void push_replacement_text PARAMS ((cpp_reader *, cpp_hashnode *));
-static bool scan_parameters PARAMS ((cpp_reader *, cpp_macro *));
-static bool recursive_macro PARAMS ((cpp_reader *, cpp_hashnode *));
-static void save_replacement_text PARAMS ((cpp_reader *, cpp_macro *,
-                                          unsigned int));
-static void maybe_start_funlike PARAMS ((cpp_reader *, cpp_hashnode *,
-                                        const uchar *, struct fun_macro *));
-static void save_argument PARAMS ((struct fun_macro *, size_t));
-static void replace_args_and_push PARAMS ((cpp_reader *, struct fun_macro *));
-static size_t canonicalize_text PARAMS ((uchar *, const uchar *, size_t,
-                                        uchar *));
+static const uchar *skip_whitespace (cpp_reader *, const uchar *, int);
+static cpp_hashnode *lex_identifier (cpp_reader *, const uchar *);
+static const uchar *copy_comment (cpp_reader *, const uchar *, int);
+static void check_output_buffer (cpp_reader *, size_t);
+static void push_replacement_text (cpp_reader *, cpp_hashnode *);
+static bool scan_parameters (cpp_reader *, cpp_macro *);
+static bool recursive_macro (cpp_reader *, cpp_hashnode *);
+static void save_replacement_text (cpp_reader *, cpp_macro *, unsigned int);
+static void maybe_start_funlike (cpp_reader *, cpp_hashnode *, const uchar *,
+                                struct fun_macro *);
+static void save_argument (struct fun_macro *, size_t);
+static void replace_args_and_push (cpp_reader *, struct fun_macro *);
+static size_t canonicalize_text (uchar *, const uchar *, size_t, uchar *);
 
 /* Ensures we have N bytes' space in the output buffer, and
    reallocates it if not.  */
 static void
-check_output_buffer (pfile, n)
-     cpp_reader *pfile;
-     size_t n;
+check_output_buffer (cpp_reader *pfile, size_t n)
 {
   /* We might need two bytes to terminate an unterminated comment, and
      one more to terminate the line with a NUL.  */
@@ -116,48 +107,29 @@ check_output_buffer (pfile, n)
       size_t size = pfile->out.cur - pfile->out.base;
       size_t new_size = (size + n) * 3 / 2;
 
-      pfile->out.base
-       = (uchar *) xrealloc (pfile->out.base, new_size);
+      pfile->out.base = xrealloc (pfile->out.base, new_size);
       pfile->out.limit = pfile->out.base + new_size;
       pfile->out.cur = pfile->out.base + size;
     }
 }
 
-/* To be called whenever a newline character is encountered in the
-   input file, at CUR.  Handles DOS, Mac and Unix ends of line, and
-   increments pfile->line.
-
-   Returns a pointer the character after the newline sequence.  */
-static const uchar *
-handle_newline (pfile, cur)
-     cpp_reader *pfile;
-     const uchar *cur;
-{
-  pfile->line++;
-  if (cur[0] + cur[1] == '\r' + '\n')
-    cur++;
-  return cur + 1;
-}
-
-/* CUR points to any character in the current context, not necessarily
-   a backslash.  Advances CUR until all escaped newlines are skipped,
-   and returns the new position without updating the context.
-
-   Warns if a file buffer ends in an escaped newline.  */
-static const uchar *
-skip_escaped_newlines (pfile, cur)
-     cpp_reader *pfile;
-     const uchar *cur;
+/* Skip a C-style block comment in a macro as a result of -CC.
+   Buffer->cur points to the initial asterisk of the comment.  */
+static void
+skip_macro_block_comment (cpp_reader *pfile)
 {
-  const uchar *orig_cur = cur;
+  const uchar *cur = pfile->buffer->cur;
 
-  while (*cur == '\\' && is_vspace (cur[1]))
-    cur = handle_newline (pfile, cur + 1);
+  cur++;
+  if (*cur == '/')
+    cur++;
 
-  if (cur != orig_cur && cur == RLIMIT (pfile->context) && pfile->buffer->inc)
-    cpp_error (pfile, DL_PEDWARN, "backslash-newline at end of file");
+  /* People like decorating comments with '*', so check for '/'
+     instead for efficiency.  */
+  while(! (*cur++ == '/' && cur[-2] == '*') )
+    ;
 
-  return cur;
+  pfile->buffer->cur = cur;
 }
 
 /* CUR points to the asterisk introducing a comment in the current
@@ -173,48 +145,22 @@ skip_escaped_newlines (pfile, cur)
    Returns a pointer to the first character after the comment in the
    input buffer.  */
 static const uchar *
-copy_comment (pfile, cur, in_define)
-     cpp_reader *pfile;
-     const uchar *cur;
-     int in_define;
+copy_comment (cpp_reader *pfile, const uchar *cur, int in_define)
 {
+  bool unterminated, copy = false;
   unsigned int from_line = pfile->line;
-  const uchar *limit = RLIMIT (pfile->context);
-  uchar *out = pfile->out.cur;
-
-  do
-    {
-      unsigned int c = *cur++;
-      *out++ = c;
-
-      if (c == '/')
-       {
-         /* An immediate slash does not terminate the comment.  */
-         if (out[-2] == '*' && out - 2 > pfile->out.cur)
-           goto done;
-
-         if (*cur == '*' && cur[1] != '/'
-             && CPP_OPTION (pfile, warn_comments))
-           cpp_error_with_line (pfile, DL_WARNING, pfile->line, 0,
-                                "\"/*\" within comment");
-       }
-      else if (is_vspace (c))
-       {
-         cur = handle_newline (pfile, cur - 1);
-         /* Canonicalize newline sequences and skip escaped ones.  */
-         if (out[-2] == '\\')
-           out -= 2;
-         else
-           out[-1] = '\n';
-       }
-    }
-  while (cur < limit);
+  cpp_buffer *buffer = pfile->buffer;
 
-  cpp_error_with_line (pfile, DL_ERROR, from_line, 0, "unterminated comment");
-  *out++ = '*';
-  *out++ = '/';
+  buffer->cur = cur;
+  if (pfile->context->prev)
+    unterminated = false, skip_macro_block_comment (pfile);
+  else
+    unterminated = _cpp_skip_block_comment (pfile);
+    
+  if (unterminated)
+    cpp_error_with_line (pfile, CPP_DL_ERROR, from_line, 0,
+                        "unterminated comment");
 
- done:
   /* Comments in directives become spaces so that tokens are properly
      separated when the ISO preprocessor re-lexes the line.  The
      exception is #define.  */
@@ -225,7 +171,7 @@ copy_comment (pfile, cur, in_define)
          if (CPP_OPTION (pfile, discard_comments_in_macro_exp))
            pfile->out.cur--;
          else
-           pfile->out.cur = out;
+           copy = true;
        }
       else
        pfile->out.cur[-1] = ' ';
@@ -233,9 +179,21 @@ copy_comment (pfile, cur, in_define)
   else if (CPP_OPTION (pfile, discard_comments))
     pfile->out.cur--;
   else
-    pfile->out.cur = out;
+    copy = true;
+
+  if (copy)
+    {
+      size_t len = (size_t) (buffer->cur - cur);
+      memcpy (pfile->out.cur, cur, len);
+      pfile->out.cur += len;
+      if (unterminated)
+       {
+         *pfile->out.cur++ = '*';
+         *pfile->out.cur++ = '/';
+       }
+    }
 
-  return cur;
+  return buffer->cur;
 }
 
 /* CUR points to any character in the input buffer.  Skips over all
@@ -251,10 +209,7 @@ copy_comment (pfile, cur, in_define)
    Returns a pointer to the first character after the whitespace in
    the input buffer.  */
 static const uchar *
-skip_whitespace (pfile, cur, skip_comments)
-     cpp_reader *pfile;
-     const uchar *cur;
-     int skip_comments;
+skip_whitespace (cpp_reader *pfile, const uchar *cur, int skip_comments)
 {
   uchar *out = pfile->out.cur;
 
@@ -263,31 +218,18 @@ skip_whitespace (pfile, cur, skip_comments)
       unsigned int c = *cur++;
       *out++ = c;
 
-      if (is_nvspace (c) && c)
+      if (is_nvspace (c))
        continue;
 
-      if (!c && cur - 1 != RLIMIT (pfile->context))
-       continue;
-
-      if (c == '/' && skip_comments)
-       {
-         const uchar *tmp = skip_escaped_newlines (pfile, cur);
-         if (*tmp == '*')
-           {
-             pfile->out.cur = out;
-             cur = copy_comment (pfile, tmp, false /* in_define */);
-             out = pfile->out.cur;
-             continue;
-           }
-       }
-
-      out--;
-      if (c == '\\' && is_vspace (*cur))
+      if (c == '/' && *cur == '*' && skip_comments)
        {
-         cur = skip_escaped_newlines (pfile, cur - 1);
+         pfile->out.cur = out;
+         cur = copy_comment (pfile, cur, false /* in_define */);
+         out = pfile->out.cur;
          continue;
        }
 
+      out--;
       break;
     }
 
@@ -299,21 +241,14 @@ skip_whitespace (pfile, cur, skip_comments)
    to point to a valid first character of an identifier.  Returns
    the hashnode, and updates out.cur.  */
 static cpp_hashnode *
-lex_identifier (pfile, cur)
-     cpp_reader *pfile;
-     const uchar *cur;
+lex_identifier (cpp_reader *pfile, const uchar *cur)
 {
   size_t len;
   uchar *out = pfile->out.cur;
   cpp_hashnode *result;
 
   do
-    {
-      do
-       *out++ = *cur++;
-      while (is_numchar (*cur));
-      cur = skip_escaped_newlines (pfile, cur);
-    }
+    *out++ = *cur++;
   while (is_numchar (*cur));
 
   CUR (pfile->context) = cur;
@@ -328,74 +263,54 @@ lex_identifier (pfile, cur)
    starting at START.  The true buffer is restored upon calling
    restore_buff().  */
 void
-_cpp_overlay_buffer (pfile, start, len)
-     cpp_reader *pfile;
-     const uchar *start;
-     size_t len;
+_cpp_overlay_buffer (cpp_reader *pfile, const uchar *start, size_t len)
 {
   cpp_buffer *buffer = pfile->buffer;
 
   pfile->overlaid_buffer = buffer;
   buffer->saved_cur = buffer->cur;
   buffer->saved_rlimit = buffer->rlimit;
+  /* Prevent the ISO lexer from scanning a fresh line.  */
+  pfile->saved_line = pfile->line--;
+  buffer->need_line = false;
 
   buffer->cur = start;
   buffer->rlimit = start + len;
-
-  pfile->saved_line = pfile->line;
 }
 
 /* Restores a buffer overlaid by _cpp_overlay_buffer().  */
 void
-_cpp_remove_overlay (pfile)
-     cpp_reader *pfile;
+_cpp_remove_overlay (cpp_reader *pfile)
 {
   cpp_buffer *buffer = pfile->overlaid_buffer;
 
   buffer->cur = buffer->saved_cur;
   buffer->rlimit = buffer->saved_rlimit;
+  buffer->need_line = true;
 
+  pfile->overlaid_buffer = NULL;
   pfile->line = pfile->saved_line;
 }
 
 /* Reads a logical line into the output buffer.  Returns TRUE if there
    is more text left in the buffer.  */
 bool
-_cpp_read_logical_line_trad (pfile)
-     cpp_reader *pfile;
+_cpp_read_logical_line_trad (cpp_reader *pfile)
 {
   do
     {
-      if (pfile->buffer->cur == pfile->buffer->rlimit)
-       {
-         bool stop = true;
-
-         /* Don't pop the last buffer.  */
-         if (pfile->buffer->prev)
-           {
-             stop = pfile->buffer->return_at_eof;
-             _cpp_pop_buffer (pfile);
-           }
-
-         if (stop)
-           return false;
-       }
-
-      scan_out_logical_line (pfile, NULL);
+      if (pfile->buffer->need_line && !_cpp_get_fresh_line (pfile))
+       return false;
     }
-  while (pfile->state.skipping);
+  while (!_cpp_scan_out_logical_line (pfile, NULL) || pfile->state.skipping);
 
-  return true;
+  return pfile->buffer != NULL;
 }
 
 /* Set up state for finding the opening '(' of a function-like
    macro.  */
 static void
-maybe_start_funlike (pfile, node, start, macro)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
-     const uchar *start;
-     struct fun_macro *macro;
+maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start, struct fun_macro *macro)
 {
   unsigned int n = node->value.macro->paramc + 1;
 
@@ -410,9 +325,7 @@ maybe_start_funlike (pfile, node, start, macro)
 
 /* Save the OFFSET of the start of the next argument to MACRO.  */
 static void
-save_argument (macro, offset)
-     struct fun_macro *macro;
-     size_t offset;
+save_argument (struct fun_macro *macro, size_t offset)
 {
   macro->argc++;
   if (macro->argc <= macro->node->value.macro->paramc)
@@ -426,11 +339,10 @@ save_argument (macro, offset)
    If MACRO is non-NULL, then we are scanning the replacement list of
    MACRO, and we call save_replacement_text() every time we meet an
    argument.  */
-static void
-scan_out_logical_line (pfile, macro)
-     cpp_reader *pfile;
-     cpp_macro *macro;
+bool
+_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
 {
+  bool result = true;
   cpp_context *context;
   const uchar *cur;
   uchar *out;
@@ -442,7 +354,6 @@ scan_out_logical_line (pfile, macro)
 
   fmacro.buff = NULL;
 
- start_logical_line:
   quote = 0;
   header_ok = pfile->state.angled_headers;
   CUR (pfile->context) = pfile->buffer->cur;
@@ -450,7 +361,7 @@ scan_out_logical_line (pfile, macro)
   pfile->out.cur = pfile->out.base;
   pfile->out.first_line = pfile->line;
   /* start_of_input_line is needed to make sure that directives really,
-     really start at the first character of the line. */
+     really start at the first character of the line.  */
   start_of_input_line = pfile->buffer->cur;
  new_context:
   context = pfile->context;
@@ -460,6 +371,12 @@ scan_out_logical_line (pfile, macro)
 
   for (;;)
     {
+      if (!context->prev
+         && cur >= pfile->buffer->notes[pfile->buffer->cur_note].pos)
+       {
+         pfile->buffer->cur = cur;
+         _cpp_process_line_notes (pfile, false);
+       }
       c = *cur++;
       *out++ = c;
 
@@ -471,12 +388,10 @@ scan_out_logical_line (pfile, macro)
        case '\t':
        case '\f':
        case '\v':
-         continue;
-
        case '\0':
-         if (cur - 1 != RLIMIT (context))
-           continue;
+         continue;
 
+       case '\n':
          /* If this is a macro's expansion, pop it.  */
          if (context->prev)
            {
@@ -485,22 +400,21 @@ scan_out_logical_line (pfile, macro)
              goto new_context;
            }
 
-         /* Premature end of file.  Fake a new line.  */
-         cur--;
-         if (!pfile->buffer->from_stage3)
-           cpp_error (pfile, DL_PEDWARN, "no newline at end of file");
+         /* Omit the newline from the output buffer.  */
+         pfile->out.cur = out - 1;
+         pfile->buffer->cur = cur;
+         pfile->buffer->need_line = true;
          pfile->line++;
-         goto done;
 
-       case '\r': case '\n':
-         cur = handle_newline (pfile, cur - 1);
          if ((lex_state == ls_fun_open || lex_state == ls_fun_close)
-             && !pfile->state.in_directive)
+             && !pfile->state.in_directive
+             && _cpp_get_fresh_line (pfile))
            {
              /* Newlines in arguments become a space, but we don't
                 clear any in-progress quote.  */
              if (lex_state == ls_fun_close)
                out[-1] = ' ';
+             cur = pfile->buffer->cur;
              continue;
            }
          goto done;
@@ -523,35 +437,20 @@ scan_out_logical_line (pfile, macro)
          break;
 
        case '\\':
-         if (is_vspace (*cur))
-           {
-             out--;
-             cur = skip_escaped_newlines (pfile, cur - 1);
-             continue;
-           }
-         else
-           {
-             /* Skip escaped quotes here, it's easier than above, but
-                take care to first skip escaped newlines.  */
-             cur = skip_escaped_newlines (pfile, cur);
-             if (*cur == '\\' || *cur == '"' || *cur == '\'')
-               *out++ = *cur++;
-           }
+         /* Skip escaped quotes here, it's easier than above.  */
+         if (*cur == '\\' || *cur == '"' || *cur == '\'')
+           *out++ = *cur++;
          break;
 
        case '/':
          /* Traditional CPP does not recognize comments within
             literals.  */
-         if (!quote)
+         if (!quote && *cur == '*')
            {
-             cur = skip_escaped_newlines (pfile, cur);
-             if (*cur == '*')
-               {
-                 pfile->out.cur = out;
-                 cur = copy_comment (pfile, cur, macro != 0);
-                 out = pfile->out.cur;
-                 continue;
-               }
+             pfile->out.cur = out;
+             cur = copy_comment (pfile, cur, macro != 0);
+             out = pfile->out.cur;
+             continue;
            }
          break;
 
@@ -601,12 +500,12 @@ scan_out_logical_line (pfile, macro)
                      goto new_context;
                    }
                }
-             else if (macro && node->arg_index)
+             else if (macro && (node->flags & NODE_MACRO_ARG) != 0)
                {
                  /* Found a parameter in the replacement text of a
                     #define.  Remove its name from the output.  */
                  pfile->out.cur = out_start;
-                 save_replacement_text (pfile, macro, node->arg_index);
+                 save_replacement_text (pfile, macro, node->value.arg_index);
                  out = pfile->out.base;
                }
              else if (lex_state == ls_hash)
@@ -701,12 +600,14 @@ scan_out_logical_line (pfile, macro)
              cur = skip_whitespace (pfile, cur, true /* skip_comments */);
              out = pfile->out.cur;
 
-             if (is_vspace (*cur))
+             if (*cur == '\n')
                {
                  /* Null directive.  Ignore it and don't invalidate
                     the MI optimization.  */
-                 out = pfile->out.base;
-                 continue;
+                 pfile->buffer->need_line = true;
+                 pfile->line++;
+                 result = false;
+                 goto done;
                }
              else
                {
@@ -718,7 +619,7 @@ scan_out_logical_line (pfile, macro)
                  else if (is_idstart (*cur))
                    /* Check whether we know this directive, but don't
                       advance.  */
-                   do_it = lex_identifier (pfile, cur)->directive_index != 0;
+                   do_it = lex_identifier (pfile, cur)->is_directive;
 
                  if (do_it || CPP_OPTION (pfile, lang) != CLK_ASM)
                    {
@@ -726,9 +627,8 @@ scan_out_logical_line (pfile, macro)
                         preprocessor lex the next token.  */
                      pfile->buffer->cur = cur;
                      _cpp_handle_directive (pfile, false /* indented */);
-                     /* #include changes pfile->buffer so we need to
-                        update the limits of the current context.  */
-                     goto start_logical_line;
+                     result = false;
+                     goto done;
                    }
                }
            }
@@ -767,33 +667,34 @@ scan_out_logical_line (pfile, macro)
     }
 
  done:
-  out[-1] = '\0';
-  pfile->buffer->cur = cur;
-  pfile->out.cur = out - 1;
   if (fmacro.buff)
     _cpp_release_buff (pfile, fmacro.buff);
 
   if (lex_state == ls_fun_close)
-    cpp_error_with_line (pfile, DL_ERROR, fmacro.line, 0,
+    cpp_error_with_line (pfile, CPP_DL_ERROR, fmacro.line, 0,
                         "unterminated argument list invoking macro \"%s\"",
                         NODE_NAME (fmacro.node));
+  return result;
 }
 
 /* Push a context holding the replacement text of the macro NODE on
    the context stack.  NODE is either object-like, or a function-like
    macro with no arguments.  */
 static void
-push_replacement_text (pfile, node)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
+push_replacement_text (cpp_reader *pfile, cpp_hashnode *node)
 {
   size_t len;
   const uchar *text;
+  uchar *buf;
 
   if (node->flags & NODE_BUILTIN)
     {
       text = _cpp_builtin_macro_text (pfile, node);
       len = ustrlen (text);
+      buf = _cpp_unaligned_alloc (pfile, len + 1);
+      memcpy (buf, text, len);
+      buf[len]='\n';
+      text = buf;
     }
   else
     {
@@ -808,9 +709,7 @@ push_replacement_text (pfile, node)
 
 /* Returns TRUE if traditional macro recursion is detected.  */
 static bool
-recursive_macro (pfile, node)
-     cpp_reader *pfile;
-     cpp_hashnode *node;
+recursive_macro (cpp_reader *pfile, cpp_hashnode *node)
 {
   bool recursing = !!(node->flags & NODE_DISABLED);
 
@@ -841,7 +740,7 @@ recursive_macro (pfile, node)
     }
 
   if (recursing)
-    cpp_error (pfile, DL_ERROR,
+    cpp_error (pfile, CPP_DL_ERROR,
               "detected recursion whilst expanding macro \"%s\"",
               NODE_NAME (node));
 
@@ -851,8 +750,7 @@ recursive_macro (pfile, node)
 /* Return the length of the replacement text of a function-like or
    object-like non-builtin macro.  */
 size_t
-_cpp_replacement_text_len (macro)
-     const cpp_macro *macro;
+_cpp_replacement_text_len (const cpp_macro *macro)
 {
   size_t len;
 
@@ -882,9 +780,7 @@ _cpp_replacement_text_len (macro)
    sufficient size.  It is not NUL-terminated.  The next character is
    returned.  */
 uchar *
-_cpp_copy_replacement_text (macro, dest)
-     const cpp_macro *macro;
-     uchar *dest;
+_cpp_copy_replacement_text (const cpp_macro *macro, uchar *dest)
 {
   if (macro->fun_like && (macro->paramc != 0))
     {
@@ -918,9 +814,7 @@ _cpp_copy_replacement_text (macro, dest)
    the context stack.  NODE is either object-like, or a function-like
    macro with no arguments.  */
 static void
-replace_args_and_push (pfile, fmacro)
-     cpp_reader *pfile;
-     struct fun_macro *fmacro;
+replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
 {
   cpp_macro *macro = fmacro->node->value.macro;
 
@@ -946,7 +840,7 @@ replace_args_and_push (pfile, fmacro)
          exp += BLOCK_LEN (b->text_len);
        }
 
-      /* Allocate room for the expansion plus NUL.  */
+      /* Allocate room for the expansion plus \n.  */
       buff = _cpp_get_buff (pfile, len + 1);
 
       /* Copy the expansion and replace arguments.  */
@@ -968,8 +862,8 @@ replace_args_and_push (pfile, fmacro)
          exp += BLOCK_LEN (b->text_len);
        }
 
-      /* NUL-terminate.  */
-      *p = '\0';
+      /* \n-terminate.  */
+      *p = '\n';
       _cpp_push_text_context (pfile, fmacro->node, BUFF_FRONT (buff), len);
 
       /* So we free buffer allocation when macro is left.  */
@@ -984,9 +878,7 @@ replace_args_and_push (pfile, fmacro)
    duplicate parameter).  On success, CUR (pfile->context) is just
    past the closing parenthesis.  */
 static bool
-scan_parameters (pfile, macro)
-     cpp_reader *pfile;
-     cpp_macro *macro;
+scan_parameters (cpp_reader *pfile, cpp_macro *macro)
 {
   const uchar *cur = CUR (pfile->context) + 1;
   bool ok;
@@ -1015,6 +907,9 @@ scan_parameters (pfile, macro)
       break;
     }
 
+  if (!ok)
+    cpp_error (pfile, CPP_DL_ERROR, "syntax error in macro parameter list");
+
   CUR (pfile->context) = cur + (*cur == ')');
 
   return ok;
@@ -1025,10 +920,8 @@ scan_parameters (pfile, macro)
    ARG_INDEX, with zero indicating the end of the replacement
    text.  */
 static void
-save_replacement_text (pfile, macro, arg_index)
-     cpp_reader *pfile;
-     cpp_macro *macro;
-     unsigned int arg_index;
+save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
+                      unsigned int arg_index)
 {
   size_t len = pfile->out.cur - pfile->out.base;
   uchar *exp;
@@ -1036,10 +929,10 @@ save_replacement_text (pfile, macro, arg_index)
   if (macro->paramc == 0)
     {
       /* Object-like and function-like macros without parameters
-        simply store their NUL-terminated replacement text.  */
+        simply store their \n-terminated replacement text.  */
       exp = _cpp_unaligned_alloc (pfile, len + 1);
       memcpy (exp, pfile->out.base, len);
-      exp[len] = '\0';
+      exp[len] = '\n';
       macro->exp.text = exp;
       macro->count = len;
     }
@@ -1076,9 +969,7 @@ save_replacement_text (pfile, macro, arg_index)
 /* Analyze and save the replacement text of a macro.  Returns true on
    success.  */
 bool
-_cpp_create_trad_definition (pfile, macro)
-     cpp_reader *pfile;
-     cpp_macro *macro;
+_cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro)
 {
   const uchar *cur;
   uchar *limit;
@@ -1094,14 +985,17 @@ _cpp_create_trad_definition (pfile, macro)
   /* Is this a function-like macro?  */
   if (* CUR (context) == '(')
     {
+      bool ok = scan_parameters (pfile, macro);
+
+      /* Remember the params so we can clear NODE_MACRO_ARG flags.  */
+      macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
+
       /* Setting macro to NULL indicates an error occurred, and
-        prevents unnecessary work in scan_out_logical_line.  */
-      if (!scan_parameters (pfile, macro))
+        prevents unnecessary work in _cpp_scan_out_logical_line.  */
+      if (!ok)
        macro = NULL;
       else
        {
-         /* Success.  Commit the parameter array.  */
-         macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
          BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc];
          macro->fun_like = 1;
        }
@@ -1113,7 +1007,7 @@ _cpp_create_trad_definition (pfile, macro)
                       CPP_OPTION (pfile, discard_comments_in_macro_exp));
 
   pfile->state.prevent_expansion++;
-  scan_out_logical_line (pfile, macro);
+  _cpp_scan_out_logical_line (pfile, macro);
   pfile->state.prevent_expansion--;
 
   if (!macro)
@@ -1135,11 +1029,7 @@ _cpp_create_trad_definition (pfile, macro)
    quote currently in effect is pointed to by PQUOTE, and is updated
    by the function.  Returns the number of bytes copied.  */
 static size_t
-canonicalize_text (dest, src, len, pquote)
-     uchar *dest;
-     const uchar *src;
-     size_t len;
-     uchar *pquote;
+canonicalize_text (uchar *dest, const uchar *src, size_t len, uchar *pquote)
 {
   uchar *orig_dest = dest;
   uchar quote = *pquote;
@@ -1173,8 +1063,8 @@ canonicalize_text (dest, src, len, pquote)
 /* Returns true if MACRO1 and MACRO2 have expansions different other
    than in the form of their whitespace.  */
 bool
-_cpp_expansions_different_trad (macro1, macro2)
-     const cpp_macro *macro1, *macro2;
+_cpp_expansions_different_trad (const cpp_macro *macro1,
+                               const cpp_macro *macro2)
 {
   uchar *p1 = xmalloc (macro1->count + macro2->count);
   uchar *p2 = p1 + macro1->count;
diff --git a/support/cpp2/cppucnid.h b/support/cpp2/cppucnid.h
new file mode 100644 (file)
index 0000000..1cac7df
--- /dev/null
@@ -0,0 +1,336 @@
+/* Table of UCNs which are valid in identifiers.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Automatically generated from cppucnid.tab, do not edit */
+
+/* This file reproduces the table in ISO/IEC 9899:1999 (C99) Annex
+   D, which is itself a reproduction from ISO/IEC TR 10176:1998, and
+   the similar table from ISO/IEC 14882:1988 (C++98) Annex E, which is
+   a reproduction of ISO/IEC PDTR 10176.  Unfortunately these tables
+   are not identical.  */
+
+#ifndef CPPUCNID_H
+#define CPPUCNID_H
+
+#define C99 1
+#define CXX 2
+#define DIG 4
+
+struct ucnrange
+{
+  unsigned short lo, hi;
+  unsigned short flags;
+};
+
+static const struct ucnrange ucnranges[] = {
+  { 0x00aa, 0x00aa,     C99     },  /* Latin */
+  { 0x00b5, 0x00b5,     C99     },  /* Special characters */
+  { 0x00b7, 0x00b7,     C99     },
+  { 0x00ba, 0x00ba,     C99     },  /* Latin */
+  { 0x00c0, 0x00d6, CXX|C99     },
+  { 0x00d8, 0x00f6, CXX|C99     },
+  { 0x00f8, 0x01f5, CXX|C99     },
+  { 0x01fa, 0x0217, CXX|C99     },
+  { 0x0250, 0x02a8, CXX|C99     },
+  { 0x02b0, 0x02b8,     C99     },  /* Special characters */
+  { 0x02bb, 0x02bb,     C99     },
+  { 0x02bd, 0x02c1,     C99     },
+  { 0x02d0, 0x02d1,     C99     },
+  { 0x02e0, 0x02e4,     C99     },
+  { 0x037a, 0x037a,     C99     },
+  { 0x0384, 0x0384, CXX         },  /* Greek */
+  { 0x0386, 0x0386,     C99     },
+  { 0x0388, 0x038a, CXX|C99     },
+  { 0x038c, 0x038c, CXX|C99     },
+  { 0x038e, 0x03a1, CXX|C99     },
+  { 0x03a3, 0x03ce, CXX|C99     },
+  { 0x03d0, 0x03d6, CXX|C99     },
+  { 0x03da, 0x03da, CXX|C99     },
+  { 0x03dc, 0x03dc, CXX|C99     },
+  { 0x03de, 0x03de, CXX|C99     },
+  { 0x03e0, 0x03e0, CXX|C99     },
+  { 0x03e2, 0x03f3, CXX|C99     },
+  { 0x0401, 0x040c, CXX|C99     },  /* Cyrillic */
+  { 0x040d, 0x040d, CXX         },
+  { 0x040e, 0x040e,     C99     },
+  { 0x040f, 0x044f, CXX|C99     },
+  { 0x0451, 0x045c, CXX|C99     },
+  { 0x045e, 0x0481, CXX|C99     },
+  { 0x0490, 0x04c4, CXX|C99     },
+  { 0x04c7, 0x04c8, CXX|C99     },
+  { 0x04cb, 0x04cc, CXX|C99     },
+  { 0x04d0, 0x04eb, CXX|C99     },
+  { 0x04ee, 0x04f5, CXX|C99     },
+  { 0x04f8, 0x04f9, CXX|C99     },
+  { 0x0531, 0x0556, CXX|C99     },  /* Armenian */
+  { 0x0559, 0x0559,     C99     },  /* Special characters */
+  { 0x0561, 0x0587, CXX|C99     },  /* Armenian */
+  { 0x05b0, 0x05b9,     C99     },  /* Hebrew */
+  { 0x05bb, 0x05bd,     C99     },
+  { 0x05bf, 0x05bf,     C99     },
+  { 0x05c1, 0x05c2,     C99     },
+  { 0x05d0, 0x05ea, CXX|C99     },
+  { 0x05f0, 0x05f2, CXX|C99     },
+  { 0x05f3, 0x05f4, CXX         },
+  { 0x0621, 0x063a, CXX|C99     },  /* Arabic */
+  { 0x0640, 0x0652, CXX|C99     },
+  { 0x0660, 0x0669,     C99|DIG },  /* Digits */
+  { 0x0670, 0x06b7, CXX|C99     },  /* Arabic */
+  { 0x06ba, 0x06be, CXX|C99     },
+  { 0x06c0, 0x06ce, CXX|C99     },
+  { 0x06d0, 0x06dc,     C99     },
+  { 0x06e5, 0x06e7, CXX|C99     },
+  { 0x06e8, 0x06e8,     C99     },
+  { 0x06ea, 0x06ed,     C99     },
+  { 0x06f0, 0x06f9,     C99|DIG },  /* Digits */
+  { 0x0901, 0x0903,     C99     },  /* Devanagari */
+  { 0x0905, 0x0939, CXX|C99     },
+  { 0x093d, 0x093d,     C99     },  /* Special characters */
+  { 0x093e, 0x094d,     C99     },  /* Devanagari */
+  { 0x0950, 0x0952,     C99     },
+  { 0x0958, 0x0962, CXX|C99     },
+  { 0x0963, 0x0963,     C99     },
+  { 0x0966, 0x096f,     C99|DIG },  /* Digits */
+  { 0x0981, 0x0983,     C99     },  /* Bengali */
+  { 0x0985, 0x098c, CXX|C99     },
+  { 0x098f, 0x0990, CXX|C99     },
+  { 0x0993, 0x09a8, CXX|C99     },
+  { 0x09aa, 0x09b0, CXX|C99     },
+  { 0x09b2, 0x09b2, CXX|C99     },
+  { 0x09b6, 0x09b9, CXX|C99     },
+  { 0x09be, 0x09c4,     C99     },
+  { 0x09c7, 0x09c8,     C99     },
+  { 0x09cb, 0x09cd,     C99     },
+  { 0x09dc, 0x09dd, CXX|C99     },
+  { 0x09df, 0x09e1, CXX|C99     },
+  { 0x09e2, 0x09e3,     C99     },
+  { 0x09e6, 0x09ef,     C99|DIG },  /* Digits */
+  { 0x09f0, 0x09f1, CXX|C99     },  /* Bengali */
+  { 0x0a02, 0x0a02,     C99     },  /* Gurmukhi */
+  { 0x0a05, 0x0a0a, CXX|C99     },
+  { 0x0a0f, 0x0a10, CXX|C99     },
+  { 0x0a13, 0x0a28, CXX|C99     },
+  { 0x0a2a, 0x0a30, CXX|C99     },
+  { 0x0a32, 0x0a33, CXX|C99     },
+  { 0x0a35, 0x0a36, CXX|C99     },
+  { 0x0a38, 0x0a39, CXX|C99     },
+  { 0x0a3e, 0x0a42,     C99     },
+  { 0x0a47, 0x0a48,     C99     },
+  { 0x0a4b, 0x0a4d,     C99     },
+  { 0x0a59, 0x0a5c, CXX|C99     },
+  { 0x0a5e, 0x0a5e, CXX|C99     },
+  { 0x0a66, 0x0a6f,     C99|DIG },  /* Digits */
+  { 0x0a74, 0x0a74,     C99     },  /* Gurmukhi */
+  { 0x0a81, 0x0a83,     C99     },  /* Gujarati */
+  { 0x0a85, 0x0a8b, CXX|C99     },
+  { 0x0a8d, 0x0a8d, CXX|C99     },
+  { 0x0a8f, 0x0a91, CXX|C99     },
+  { 0x0a93, 0x0aa8, CXX|C99     },
+  { 0x0aaa, 0x0ab0, CXX|C99     },
+  { 0x0ab2, 0x0ab3, CXX|C99     },
+  { 0x0ab5, 0x0ab9, CXX|C99     },
+  { 0x0abd, 0x0ac5,     C99     },
+  { 0x0ac7, 0x0ac9,     C99     },
+  { 0x0acb, 0x0acd,     C99     },
+  { 0x0ad0, 0x0ad0,     C99     },
+  { 0x0ae0, 0x0ae0, CXX|C99     },
+  { 0x0ae6, 0x0aef,     C99|DIG },  /* Digits */
+  { 0x0b01, 0x0b03,     C99     },  /* Oriya */
+  { 0x0b05, 0x0b0c, CXX|C99     },
+  { 0x0b0f, 0x0b10, CXX|C99     },
+  { 0x0b13, 0x0b28, CXX|C99     },
+  { 0x0b2a, 0x0b30, CXX|C99     },
+  { 0x0b32, 0x0b33, CXX|C99     },
+  { 0x0b36, 0x0b39, CXX|C99     },
+  { 0x0b3d, 0x0b3d,     C99     },  /* Special characters */
+  { 0x0b3e, 0x0b43,     C99     },  /* Oriya */
+  { 0x0b47, 0x0b48,     C99     },
+  { 0x0b4b, 0x0b4d,     C99     },
+  { 0x0b5c, 0x0b5d, CXX|C99     },
+  { 0x0b5f, 0x0b61, CXX|C99     },
+  { 0x0b66, 0x0b6f,     C99|DIG },  /* Digits */
+  { 0x0b82, 0x0b83,     C99     },  /* Tamil */
+  { 0x0b85, 0x0b8a, CXX|C99     },
+  { 0x0b8e, 0x0b90, CXX|C99     },
+  { 0x0b92, 0x0b95, CXX|C99     },
+  { 0x0b99, 0x0b9a, CXX|C99     },
+  { 0x0b9c, 0x0b9c, CXX|C99     },
+  { 0x0b9e, 0x0b9f, CXX|C99     },
+  { 0x0ba3, 0x0ba4, CXX|C99     },
+  { 0x0ba8, 0x0baa, CXX|C99     },
+  { 0x0bae, 0x0bb5, CXX|C99     },
+  { 0x0bb7, 0x0bb9, CXX|C99     },
+  { 0x0bbe, 0x0bc2,     C99     },
+  { 0x0bc6, 0x0bc8,     C99     },
+  { 0x0bca, 0x0bcd,     C99     },
+  { 0x0be7, 0x0bef,     C99|DIG },  /* Digits */
+  { 0x0c01, 0x0c03,     C99     },  /* Telugu */
+  { 0x0c05, 0x0c0c, CXX|C99     },
+  { 0x0c0e, 0x0c10, CXX|C99     },
+  { 0x0c12, 0x0c28, CXX|C99     },
+  { 0x0c2a, 0x0c33, CXX|C99     },
+  { 0x0c35, 0x0c39, CXX|C99     },
+  { 0x0c3e, 0x0c44,     C99     },
+  { 0x0c46, 0x0c48,     C99     },
+  { 0x0c4a, 0x0c4d,     C99     },
+  { 0x0c60, 0x0c61, CXX|C99     },
+  { 0x0c66, 0x0c6f,     C99|DIG },  /* Digits */
+  { 0x0c82, 0x0c83,     C99     },  /* Kannada */
+  { 0x0c85, 0x0c8c, CXX|C99     },
+  { 0x0c8e, 0x0c90, CXX|C99     },
+  { 0x0c92, 0x0ca8, CXX|C99     },
+  { 0x0caa, 0x0cb3, CXX|C99     },
+  { 0x0cb5, 0x0cb9, CXX|C99     },
+  { 0x0cbe, 0x0cc4,     C99     },
+  { 0x0cc6, 0x0cc8,     C99     },
+  { 0x0cca, 0x0ccd,     C99     },
+  { 0x0cde, 0x0cde,     C99     },
+  { 0x0ce0, 0x0ce1, CXX|C99     },
+  { 0x0ce6, 0x0cef,     C99|DIG },  /* Digits */
+  { 0x0d02, 0x0d03,     C99     },  /* Malayalam */
+  { 0x0d05, 0x0d0c, CXX|C99     },
+  { 0x0d0e, 0x0d10, CXX|C99     },
+  { 0x0d12, 0x0d28, CXX|C99     },
+  { 0x0d2a, 0x0d39, CXX|C99     },
+  { 0x0d3e, 0x0d43,     C99     },
+  { 0x0d46, 0x0d48,     C99     },
+  { 0x0d4a, 0x0d4d,     C99     },
+  { 0x0d60, 0x0d61, CXX|C99     },
+  { 0x0d66, 0x0d6f,     C99|DIG },  /* Digits */
+  { 0x0e01, 0x0e30, CXX|C99     },  /* Thai */
+  { 0x0e31, 0x0e31,     C99     },
+  { 0x0e32, 0x0e33, CXX|C99     },
+  { 0x0e34, 0x0e3a,     C99     },
+  { 0x0e40, 0x0e46, CXX|C99     },
+  { 0x0e47, 0x0e49,     C99     },
+  { 0x0e50, 0x0e59, CXX|C99|DIG },  /* Digits */
+  { 0x0e5a, 0x0e5b, CXX|C99     },  /* Thai */
+  { 0x0e81, 0x0e82, CXX|C99     },  /* Lao */
+  { 0x0e84, 0x0e84, CXX|C99     },
+  { 0x0e87, 0x0e88, CXX|C99     },
+  { 0x0e8a, 0x0e8a, CXX|C99     },
+  { 0x0e8d, 0x0e8d, CXX|C99     },
+  { 0x0e94, 0x0e97, CXX|C99     },
+  { 0x0e99, 0x0e9f, CXX|C99     },
+  { 0x0ea1, 0x0ea3, CXX|C99     },
+  { 0x0ea5, 0x0ea5, CXX|C99     },
+  { 0x0ea7, 0x0ea7, CXX|C99     },
+  { 0x0eaa, 0x0eab, CXX|C99     },
+  { 0x0ead, 0x0eae, CXX|C99     },
+  { 0x0eaf, 0x0eaf, CXX         },
+  { 0x0eb0, 0x0eb0, CXX|C99     },
+  { 0x0eb1, 0x0eb1,     C99     },
+  { 0x0eb2, 0x0eb3, CXX|C99     },
+  { 0x0eb4, 0x0eb9,     C99     },
+  { 0x0ebb, 0x0ebc,     C99     },
+  { 0x0ebd, 0x0ebd, CXX|C99     },
+  { 0x0ec0, 0x0ec4, CXX|C99     },
+  { 0x0ec6, 0x0ec6, CXX|C99     },
+  { 0x0ec8, 0x0ecd,     C99     },
+  { 0x0ed0, 0x0ed9,     C99|DIG },  /* Digits */
+  { 0x0edc, 0x0edd,     C99     },  /* Lao */
+  { 0x0f00, 0x0f00,     C99     },  /* Tibetan */
+  { 0x0f18, 0x0f19,     C99     },
+  { 0x0f20, 0x0f33,     C99|DIG },  /* Digits */
+  { 0x0f35, 0x0f35,     C99     },  /* Tibetan */
+  { 0x0f37, 0x0f37,     C99     },
+  { 0x0f39, 0x0f39,     C99     },
+  { 0x0f3e, 0x0f47,     C99     },
+  { 0x0f49, 0x0f69,     C99     },
+  { 0x0f71, 0x0f84,     C99     },
+  { 0x0f86, 0x0f8b,     C99     },
+  { 0x0f90, 0x0f95,     C99     },
+  { 0x0f97, 0x0f97,     C99     },
+  { 0x0f99, 0x0fad,     C99     },
+  { 0x0fb1, 0x0fb7,     C99     },
+  { 0x0fb9, 0x0fb9,     C99     },
+  { 0x10a0, 0x10c5, CXX|C99     },  /* Georgian */
+  { 0x10d0, 0x10f6, CXX|C99     },
+  { 0x1100, 0x1159, CXX         },  /* Hangul */
+  { 0x1161, 0x11a2, CXX         },
+  { 0x11a8, 0x11f9, CXX         },
+  { 0x1e00, 0x1e9a, CXX|C99     },  /* Latin */
+  { 0x1e9b, 0x1e9b,     C99     },
+  { 0x1ea0, 0x1ef9, CXX|C99     },
+  { 0x1f00, 0x1f15, CXX|C99     },  /* Greek */
+  { 0x1f18, 0x1f1d, CXX|C99     },
+  { 0x1f20, 0x1f45, CXX|C99     },
+  { 0x1f48, 0x1f4d, CXX|C99     },
+  { 0x1f50, 0x1f57, CXX|C99     },
+  { 0x1f59, 0x1f59, CXX|C99     },
+  { 0x1f5b, 0x1f5b, CXX|C99     },
+  { 0x1f5d, 0x1f5d, CXX|C99     },
+  { 0x1f5f, 0x1f7d, CXX|C99     },
+  { 0x1f80, 0x1fb4, CXX|C99     },
+  { 0x1fb6, 0x1fbc, CXX|C99     },
+  { 0x1fbe, 0x1fbe,     C99     },  /* Special characters */
+  { 0x1fc2, 0x1fc4, CXX|C99     },  /* Greek */
+  { 0x1fc6, 0x1fcc, CXX|C99     },
+  { 0x1fd0, 0x1fd3, CXX|C99     },
+  { 0x1fd6, 0x1fdb, CXX|C99     },
+  { 0x1fe0, 0x1fec, CXX|C99     },
+  { 0x1ff2, 0x1ff4, CXX|C99     },
+  { 0x1ff6, 0x1ffc, CXX|C99     },
+  { 0x203f, 0x2040,     C99     },  /* Special characters */
+  { 0x207f, 0x207f,     C99     },  /* Latin */
+  { 0x2102, 0x2102,     C99     },  /* Special characters */
+  { 0x2107, 0x2107,     C99     },
+  { 0x210a, 0x2113,     C99     },
+  { 0x2115, 0x2115,     C99     },
+  { 0x2118, 0x211d,     C99     },
+  { 0x2124, 0x2124,     C99     },
+  { 0x2126, 0x2126,     C99     },
+  { 0x2128, 0x2128,     C99     },
+  { 0x212a, 0x2131,     C99     },
+  { 0x2133, 0x2138,     C99     },
+  { 0x2160, 0x2182,     C99     },
+  { 0x3005, 0x3007,     C99     },
+  { 0x3021, 0x3029,     C99     },
+  { 0x3041, 0x3093, CXX|C99     },  /* Hiragana */
+  { 0x3094, 0x3094, CXX         },
+  { 0x309b, 0x309c, CXX|C99     },
+  { 0x309d, 0x309e, CXX         },
+  { 0x30a1, 0x30f6, CXX|C99     },  /* Katakana */
+  { 0x30f7, 0x30fa, CXX         },
+  { 0x30fb, 0x30fc, CXX|C99     },
+  { 0x30fd, 0x30fe, CXX         },
+  { 0x3105, 0x312c, CXX|C99     },  /* Bopomofo */
+  { 0x4e00, 0x9fa5, CXX|C99     },  /* CJK Unified Ideographs */
+  { 0xac00, 0xd7a3,     C99     },  /* Hangul */
+  { 0xf900, 0xfa2d, CXX         },  /* CJK Unified Ideographs */
+  { 0xfb1f, 0xfb36, CXX         },
+  { 0xfb38, 0xfb3c, CXX         },
+  { 0xfb3e, 0xfb3e, CXX         },
+  { 0xfb40, 0xfb44, CXX         },
+  { 0xfb46, 0xfbb1, CXX         },
+  { 0xfbd3, 0xfd3f, CXX         },
+  { 0xfd50, 0xfd8f, CXX         },
+  { 0xfd92, 0xfdc7, CXX         },
+  { 0xfdf0, 0xfdfb, CXX         },
+  { 0xfe70, 0xfe72, CXX         },
+  { 0xfe74, 0xfe74, CXX         },
+  { 0xfe76, 0xfefc, CXX         },
+  { 0xff21, 0xff3a, CXX         },
+  { 0xff41, 0xff5a, CXX         },
+  { 0xff66, 0xffbe, CXX         },
+  { 0xffc2, 0xffc7, CXX         },
+  { 0xffca, 0xffcf, CXX         },
+  { 0xffd2, 0xffd7, CXX         },
+  { 0xffda, 0xffdc, CXX         },
+};
+
+#endif /* cppucnid.h */
diff --git a/support/cpp2/diagnostic.c b/support/cpp2/diagnostic.c
new file mode 100644 (file)
index 0000000..7b1155b
--- /dev/null
@@ -0,0 +1,589 @@
+/* Language-independent diagnostic subroutines for the GNU Compiler Collection
+   Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+
+/* This file implements the language independent aspect of diagnostic
+   message module.  */
+
+#include "config.h"
+#undef FLOAT /* This is for hpux. They should change hpux.  */
+#undef FFS  /* Some systems define this in param.h.  */
+#include "system.h"
+#include "input.h"
+#include "version.h"
+#include "input.h"
+#include "intl.h"
+#include "diagnostic.h"
+
+
+/* Prototypes.  */
+static char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1;
+
+static void default_diagnostic_starter (diagnostic_context *,
+                                       diagnostic_info *);
+static void default_diagnostic_finalizer (diagnostic_context *,
+                                         diagnostic_info *);
+
+static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
+static bool text_specifies_location (text_info *, location_t *);
+static bool diagnostic_count_diagnostic (diagnostic_context *,
+                                        diagnostic_info *);
+static void diagnostic_action_after_output (diagnostic_context *,
+                                           diagnostic_info *);
+static void real_abort (void) ATTRIBUTE_NORETURN;
+
+extern int rtl_dump_and_exit;
+
+/* A diagnostic_context surrogate for stderr.  */
+static diagnostic_context global_diagnostic_context;
+diagnostic_context *global_dc = &global_diagnostic_context;
+
+/* Boilerplate text used in two locations.  */
+#define bug_report_request \
+"Please submit a full bug report,\n\
+with preprocessed source if appropriate.\n\
+See %s for instructions.\n"
+
+\f
+/* Return a malloc'd string containing MSG formatted a la printf.  The
+   caller is responsible for freeing the memory.  */
+static char *
+build_message_string (const char *msg, ...)
+{
+  char *str;
+  va_list ap;
+
+  va_start (ap, msg);
+  vasprintf (&str, msg, ap);
+  va_end (ap);
+
+  return str;
+}
+
+/* Same as diagnostic_build_prefix, but only the source FILE is given.  */
+char *
+file_name_as_prefix (const char *f)
+{
+  return build_message_string ("%s: ", f);
+}
+
+
+\f
+/* Initialize the diagnostic message outputting machinery.  */
+void
+diagnostic_initialize (diagnostic_context *context)
+{
+  /* Allocate a basic pretty-printer.  Clients will replace this a
+     much more elaborated pretty-printer if they wish.  */
+  context->printer = xmalloc (sizeof (pretty_printer));
+  pp_construct (context->printer, NULL, 0);
+  /* By default, diagnostics are sent to stderr.  */
+  context->printer->buffer->stream = stderr;
+  /* By default, we emit prefixes once per message.  */
+  context->printer->prefixing_rule = DIAGNOSTICS_SHOW_PREFIX_ONCE;
+
+  memset (context->diagnostic_count, 0, sizeof context->diagnostic_count);
+  context->warnings_are_errors_message = warnings_are_errors;
+  context->abort_on_error = false;
+  context->internal_error = NULL;
+  diagnostic_starter (context) = default_diagnostic_starter;
+  diagnostic_finalizer (context) = default_diagnostic_finalizer;
+  context->last_module = 0;
+  context->last_function = NULL;
+  context->lock = 0;
+  context->x_data = NULL;
+}
+
+/* Returns true if the next format specifier in TEXT is a format specifier
+   for a location_t.  If so, update the object pointed by LOCUS to reflect
+   the specified location in *TEXT->args_ptr.  */
+static bool
+text_specifies_location (text_info *text, location_t *locus)
+{
+  const char *p;
+  /* Skip any leading text.  */
+  for (p = text->format_spec; *p && *p != '%'; ++p)
+    ;
+
+  /* Extract the location information if any.  */
+  if (p[0] == '%' && p[1] == 'H')
+    {
+      *locus = *va_arg (*text->args_ptr, location_t *);
+      text->format_spec = p + 2;
+      return true;
+    }
+  else if (p[0] == '%' && p[1] == 'J')
+    {
+      tree t = va_arg (*text->args_ptr, tree);
+      *locus = DECL_SOURCE_LOCATION (t);
+      text->format_spec = p + 2;
+      return true;
+    }
+
+  return false;
+}
+
+void
+diagnostic_set_info (diagnostic_info *diagnostic, const char *msgid,
+                    va_list *args, location_t location,
+                    diagnostic_t kind)
+{
+  diagnostic->message.err_no = errno;
+  diagnostic->message.args_ptr = args;
+  diagnostic->message.format_spec = _(msgid);
+  /* If the diagnostic message doesn't specify a location,
+     use LOCATION.  */
+  if (!text_specifies_location (&diagnostic->message, &diagnostic->location))
+    diagnostic->location = location;
+  diagnostic->kind = kind;
+}
+
+/* Return a malloc'd string describing a location.  The caller is
+   responsible for freeing the memory.  */
+char *
+diagnostic_build_prefix (diagnostic_info *diagnostic)
+{
+  static const char *const diagnostic_kind_text[] = {
+#define DEFINE_DIAGNOSTIC_KIND(K, T) (T),
+#include "diagnostic.def"
+#undef DEFINE_DIAGNOSTIC_KIND
+    "must-not-happen"
+  };
+   if (diagnostic->kind >= DK_LAST_DIAGNOSTIC_KIND)
+     abort();
+
+  return diagnostic->location.file
+    ? build_message_string ("%s:%d: %s",
+                            diagnostic->location.file,
+                            diagnostic->location.line,
+                            _(diagnostic_kind_text[diagnostic->kind]))
+    : build_message_string ("%s: %s", progname,
+                            _(diagnostic_kind_text[diagnostic->kind]));
+}
+
+/* Count a diagnostic.  Return true if the message should be printed.  */
+static bool
+diagnostic_count_diagnostic (diagnostic_context *context,
+                            diagnostic_info *diagnostic)
+{
+  diagnostic_t kind = diagnostic->kind;
+  switch (kind)
+    {
+    default:
+      abort();
+      break;
+
+    case DK_ICE:
+#ifndef ENABLE_CHECKING
+      /* When not checking, ICEs are converted to fatal errors when an
+        error has already occurred.  This is counteracted by
+        abort_on_error.  */
+      if ((diagnostic_kind_count (context, DK_ERROR) > 0
+          || diagnostic_kind_count (context, DK_SORRY) > 0)
+         && !context->abort_on_error)
+       {
+         fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n",
+                  diagnostic->location.file, diagnostic->location.line);
+         exit (FATAL_EXIT_CODE);
+       }
+#endif
+      if (context->internal_error)
+       (*context->internal_error) (diagnostic->message.format_spec,
+                                   diagnostic->message.args_ptr);
+      /* Fall through.  */
+
+    case DK_FATAL: case DK_SORRY:
+    case DK_ANACHRONISM: case DK_NOTE:
+      ++diagnostic_kind_count (context, kind);
+      break;
+
+    case DK_WARNING:
+      if (!diagnostic_report_warnings_p ())
+        return false;
+
+      if (!warnings_are_errors)
+        {
+          ++diagnostic_kind_count (context, DK_WARNING);
+          break;
+        }
+
+      if (context->warnings_are_errors_message)
+        {
+         pp_verbatim (context->printer,
+                       "%s: warnings being treated as errors\n", progname);
+          context->warnings_are_errors_message = false;
+        }
+
+      /* And fall through.  */
+    case DK_ERROR:
+      ++diagnostic_kind_count (context, DK_ERROR);
+      break;
+    }
+
+  return true;
+}
+
+/* Take any action which is expected to happen after the diagnostic
+   is written out.  This function does not always return.  */
+static void
+diagnostic_action_after_output (diagnostic_context *context,
+                               diagnostic_info *diagnostic)
+{
+  switch (diagnostic->kind)
+    {
+    case DK_DEBUG:
+    case DK_NOTE:
+    case DK_ANACHRONISM:
+    case DK_WARNING:
+      break;
+
+    case DK_ERROR:
+    case DK_SORRY:
+      if (context->abort_on_error)
+       real_abort ();
+      break;
+
+    case DK_ICE:
+      if (context->abort_on_error)
+       real_abort ();
+
+      fnotice (stderr, bug_report_request, bug_report_url);
+      exit (FATAL_EXIT_CODE);
+
+    case DK_FATAL:
+      if (context->abort_on_error)
+       real_abort ();
+
+      fnotice (stderr, "compilation terminated.\n");
+      exit (FATAL_EXIT_CODE);
+
+    default:
+      real_abort ();
+    }
+}
+
+/* Prints out, if necessary, the name of the current function
+  that caused an error.  Called from all error and warning functions.
+  We ignore the FILE parameter, as it cannot be relied upon.  */
+
+void
+diagnostic_report_current_function (diagnostic_context *context)
+{
+  diagnostic_report_current_module (context);
+  (*lang_hooks.print_error_function) (context, input_filename);
+}
+
+void
+diagnostic_report_current_module (diagnostic_context *context)
+{
+  struct file_stack *p;
+
+  if (pp_needs_newline (context->printer))
+    {
+      pp_newline (context->printer);
+      pp_needs_newline (context->printer) = false;
+    }
+
+  if (input_file_stack && diagnostic_last_module_changed (context))
+    {
+      p = input_file_stack;
+      pp_verbatim (context->printer,
+                   "In file included from %s:%d",
+                   p->location.file, p->location.line);
+      while ((p = p->next) != NULL)
+       pp_verbatim (context->printer,
+                     ",\n                 from %s:%d",
+                     p->location.file, p->location.line);
+      pp_verbatim (context->printer, ":\n");
+      diagnostic_set_last_module (context);
+    }
+}
+
+static void
+default_diagnostic_starter (diagnostic_context *context,
+                           diagnostic_info *diagnostic)
+{
+  diagnostic_report_current_function (context);
+  pp_set_prefix (context->printer, diagnostic_build_prefix (diagnostic));
+}
+
+static void
+default_diagnostic_finalizer (diagnostic_context *context,
+                             diagnostic_info *diagnostic __attribute__((unused)))
+{
+  pp_destroy_prefix (context->printer);
+}
+
+/* Report a diagnostic message (an error or a warning) as specified by
+   DC.  This function is *the* subroutine in terms of which front-ends
+   should implement their specific diagnostic handling modules.  The
+   front-end independent format specifiers are exactly those described
+   in the documentation of output_format.  */
+
+void
+diagnostic_report_diagnostic (diagnostic_context *context,
+                             diagnostic_info *diagnostic)
+{
+  if (context->lock++ && diagnostic->kind < DK_SORRY)
+    error_recursion (context);
+
+  if (diagnostic_count_diagnostic (context, diagnostic))
+    {
+      (*diagnostic_starter (context)) (context, diagnostic);
+      pp_format_text (context->printer, &diagnostic->message);
+      (*diagnostic_finalizer (context)) (context, diagnostic);
+      pp_flush (context->printer);
+      diagnostic_action_after_output (context, diagnostic);
+    }
+
+  context->lock--;
+}
+
+/* Given a partial pathname as input, return another pathname that
+   shares no directory elements with the pathname of __FILE__.  This
+   is used by fancy_abort() to print `Internal compiler error in expr.c'
+   instead of `Internal compiler error in ../../GCC/gcc/expr.c'.  */
+
+const char *
+trim_filename (const char *name)
+{
+  static const char this_file[] = __FILE__;
+  const char *p = name, *q = this_file;
+
+  /* First skip any "../" in each filename.  This allows us to give a proper
+     reference to a file in a subdirectory.  */
+  while (p[0] == '.' && p[1] == '.'
+        && (p[2] == DIR_SEPARATOR
+#ifdef DIR_SEPARATOR_2
+            || p[2] == DIR_SEPARATOR_2
+#endif
+            ))
+    p += 3;
+
+  while (q[0] == '.' && q[1] == '.'
+        && (q[2] == DIR_SEPARATOR
+#ifdef DIR_SEPARATOR_2
+            || p[2] == DIR_SEPARATOR_2
+#endif
+            ))
+    q += 3;
+
+  /* Now skip any parts the two filenames have in common.  */
+  while (*p == *q && *p != 0 && *q != 0)
+    p++, q++;
+
+  /* Now go backwards until the previous directory separator.  */
+  while (p > name && p[-1] != DIR_SEPARATOR
+#ifdef DIR_SEPARATOR_2
+        && p[-1] != DIR_SEPARATOR_2
+#endif
+        )
+    p--;
+
+  return p;
+}
+\f
+/* Standard error reporting routines in increasing order of severity.
+   All of these take arguments like printf.  */
+
+/* Text to be emitted verbatim to the error message stream; this
+   produces no prefix and disables line-wrapping.  Use rarely.  */
+void
+verbatim (const char *msgid, ...)
+{
+  text_info text;
+  va_list ap;
+
+  va_start (ap, msgid);
+  text.err_no = errno;
+  text.args_ptr = &ap;
+  text.format_spec = _(msgid);
+  pp_format_verbatim (global_dc->printer, &text);
+  pp_flush (global_dc->printer);
+  va_end (ap);
+}
+
+/* An informative note.  Use this for additional details on an error
+   message.  */
+void
+inform (const char *msgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+
+  va_start (ap, msgid);
+  diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_NOTE);
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+}
+
+/* A warning.  Use this for code which is correct according to the
+   relevant language specification but is likely to be buggy anyway.  */
+void
+warning (const char *msgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+
+  va_start (ap, msgid);
+  diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_WARNING);
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+}
+
+/* A "pedantic" warning: issues a warning unless -pedantic-errors was
+   given on the command line, in which case it issues an error.  Use
+   this for diagnostics required by the relevant language standard,
+   if you have chosen not to make them errors.
+
+   Note that these diagnostics are issued independent of the setting
+   of the -pedantic command-line switch.  To get a warning enabled
+   only with that switch, write "if (pedantic) pedwarn (...);"  */
+void
+pedwarn (const char *msgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+
+  va_start (ap, msgid);
+  diagnostic_set_info (&diagnostic, msgid, &ap, input_location,
+                      pedantic_error_kind ());
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+}
+
+/* A hard error: the code is definitely ill-formed, and an object file
+   will not be produced.  */
+void
+error (const char *msgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+
+  va_start (ap, msgid);
+  diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_ERROR);
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+}
+
+/* "Sorry, not implemented."  Use for a language feature which is
+   required by the relevant specification but not implemented by GCC.
+   An object file will not be produced.  */
+void
+sorry (const char *msgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+
+  va_start (ap, msgid);
+  diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_SORRY);
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+}
+
+/* An error which is severe enough that we make no attempt to
+   continue.  Do not use this for internal consistency checks; that's
+   internal_error.  Use of this function should be rare.  */
+void
+fatal_error (const char *msgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+
+  va_start (ap, msgid);
+  diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_FATAL);
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+
+  /* NOTREACHED */
+  real_abort ();
+}
+
+/* An internal consistency check has failed.  We make no attempt to
+   continue.  Note that unless there is debugging value to be had from
+   a more specific message, or some other good reason, you should use
+   abort () instead of calling this function directly.  */
+void
+internal_error (const char *msgid, ...)
+{
+  diagnostic_info diagnostic;
+  va_list ap;
+
+  va_start (ap, msgid);
+  diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_ICE);
+  report_diagnostic (&diagnostic);
+  va_end (ap);
+
+  /* NOTREACHED */
+  real_abort ();
+}
+\f
+/* Special case error functions.  Most are implemented in terms of the
+   above, or should be.  */
+
+/* Print a diagnostic MSGID on FILE.  This is just fprintf, except it
+   runs its second argument through gettext.  */
+void
+fnotice (FILE *file, const char *msgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, msgid);
+  vfprintf (file, _(msgid), ap);
+  va_end (ap);
+}
+
+/* Inform the user that an error occurred while trying to report some
+   other error.  This indicates catastrophic internal inconsistencies,
+   so give up now.  But do try to flush out the previous error.
+   This mustn't use internal_error, that will cause infinite recursion.  */
+
+static void
+error_recursion (diagnostic_context *context)
+{
+  if (context->lock < 3)
+    pp_flush (context->printer);
+
+  fnotice (stderr,
+          "Internal compiler error: Error reporting routines re-entered.\n");
+  fnotice (stderr, bug_report_request, bug_report_url);
+  exit (FATAL_EXIT_CODE);
+}
+
+/* Report an internal compiler error in a friendly manner.  This is
+   the function that gets called upon use of abort() in the source
+   code generally, thanks to a special macro.  */
+
+void
+fancy_abort (const char *file, int line, const char *function)
+{
+  internal_error ("in %s, at %s:%d", function, trim_filename (file), line);
+}
+
+/* Really call the system 'abort'.  This has to go right at the end of
+   this file, so that there are no functions after it that call abort
+   and get the system abort instead of our macro.  */
+#undef abort
+static void
+real_abort (void)
+{
+  abort ();
+}
diff --git a/support/cpp2/diagnostic.def b/support/cpp2/diagnostic.def
new file mode 100644 (file)
index 0000000..a401310
--- /dev/null
@@ -0,0 +1,9 @@
+DEFINE_DIAGNOSTIC_KIND (DK_FATAL, "fatal error: ")\r
+DEFINE_DIAGNOSTIC_KIND (DK_ICE, "internal compiler error: ")\r
+DEFINE_DIAGNOSTIC_KIND (DK_ERROR, "error: ")\r
+DEFINE_DIAGNOSTIC_KIND (DK_SORRY, "sorry, unimplemented: ")\r
+DEFINE_DIAGNOSTIC_KIND (DK_WARNING, "warning: ")\r
+DEFINE_DIAGNOSTIC_KIND (DK_ANACHRONISM, "anachronism: ")\r
+DEFINE_DIAGNOSTIC_KIND (DK_NOTE, "note: ")\r
+DEFINE_DIAGNOSTIC_KIND (DK_DEBUG, "debug: ")\r
+\r
diff --git a/support/cpp2/diagnostic.h b/support/cpp2/diagnostic.h
new file mode 100644 (file)
index 0000000..daf2427
--- /dev/null
@@ -0,0 +1,185 @@
+/* Various declarations for language-independent diagnostics subroutines.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef GCC_DIAGNOSTIC_H
+#define GCC_DIAGNOSTIC_H
+
+#include "pretty-print.h"
+
+/* Constants used to discriminate diagnostics.  */
+typedef enum
+{
+#define DEFINE_DIAGNOSTIC_KIND(K, msgid) K,  
+#include "diagnostic.def"
+#undef DEFINE_DIAGNOSTIC_KIND
+  DK_LAST_DIAGNOSTIC_KIND
+} diagnostic_t;
+
+/* A diagnostic is described by the MESSAGE to send, the FILE and LINE of
+   its context and its KIND (ice, error, warning, note, ...)  See complete
+   list in diagnostic.def.  */
+typedef struct
+{
+  text_info message;
+  location_t location;
+  /* The kind of diagnostic it is about.  */
+  diagnostic_t kind;
+} diagnostic_info;
+
+#define pedantic_error_kind() (flag_pedantic_errors ? DK_ERROR : DK_WARNING)
+
+
+/*  Forward declarations.  */
+typedef struct diagnostic_context diagnostic_context;
+typedef void (*diagnostic_starter_fn) (diagnostic_context *,
+                                      diagnostic_info *);
+typedef diagnostic_starter_fn diagnostic_finalizer_fn;
+
+/* This data structure bundles altogether any information relevant to
+   the context of a diagnostic message.  */
+struct diagnostic_context
+{
+  /* Where most of the diagnostic formatting work is done.  */
+  pretty_printer *printer;
+
+  /* The number of times we have issued diagnostics.  */
+  int diagnostic_count[DK_LAST_DIAGNOSTIC_KIND];
+
+  /* True if we should display the "warnings are being tread as error"
+     message, usually displayed once per compiler run.  */
+  bool warnings_are_errors_message;
+
+  /* True if we should raise a SIGABRT on errors.  */
+  bool abort_on_error;
+
+  /* This function is called before any message is printed out.  It is
+     responsible for preparing message prefix and such.  For example, it
+     might say:
+     In file included from "/usr/local/include/curses.h:5:
+                      from "/home/gdr/src/nifty_printer.h:56:
+                      ...
+  */
+  diagnostic_starter_fn begin_diagnostic;
+
+  /* This function is called after the diagnostic message is printed.  */
+  diagnostic_finalizer_fn end_diagnostic;
+
+  /* Client hook to report an internal error.  */
+  void (*internal_error) (const char *, va_list *);
+
+  /* Function of last diagnostic message; more generally, function such that
+     if next diagnostic message is in it then we don't have to mention the
+     function name.  */
+  tree last_function;
+
+  /* Used to detect when input_file_stack has changed since last described.  */
+  int last_module;
+
+  int lock;
+  
+  /* Hook for front-end extensions.  */
+  void *x_data;
+};
+
+/* Client supplied function to announce a diagnostic.  */
+#define diagnostic_starter(DC) (DC)->begin_diagnostic
+
+/* Client supplied function called after a diagnostic message is
+   displayed.  */
+#define diagnostic_finalizer(DC) (DC)->end_diagnostic
+
+/* Extension hook for client.  */
+#define diagnostic_auxiliary_data(DC) (DC)->x_data
+
+/* Same as pp_format_decoder.  Works on 'diagnostic_context *'.  */
+#define diagnostic_format_decoder(DC) ((DC)->printer->format_decoder)
+
+/* Same as output_prefixing_rule.  Works on 'diagnostic_context *'.  */
+#define diagnostic_prefixing_rule(DC) ((DC)->printer->prefixing_rule)
+
+/* Maximum characters per line in automatic line wrapping mode.
+   Zero means don't wrap lines.  */
+#define diagnostic_line_cutoff(DC) ((DC)->printer->ideal_maximum_length)
+
+#define diagnostic_flush_buffer(DC) pp_base_flush ((DC)->printer)
+
+/* True if the last function in which a diagnostic was reported is
+   different from the current one.  */
+#define diagnostic_last_function_changed(DC) \
+  ((DC)->last_function != current_function_decl)
+
+/* Remember the current function as being the last one in which we report
+   a diagnostic.  */
+#define diagnostic_set_last_function(DC) \
+  (DC)->last_function = current_function_decl
+
+/* True if the last module or file in which a diagnostic was reported is
+   different from the current one.  */
+#define diagnostic_last_module_changed(DC) \
+  ((DC)->last_module != input_file_stack_tick)
+
+/* Remember the current module or file as being the last one in which we
+   report a diagnostic.  */
+#define diagnostic_set_last_module(DC) \
+  (DC)->last_module = input_file_stack_tick
+
+/* Raise SIGABRT on any diagnostic of severity DK_ERROR or higher.  */
+#define diagnostic_abort_on_error(DC) \
+  (DC)->abort_on_error = true
+
+/* This diagnostic_context is used by front-ends that directly output
+   diagnostic messages without going through `error', `warning',
+   and similar functions.  */
+extern diagnostic_context *global_dc;
+
+/* The total count of a KIND of diagnostics emitted so far.  */
+#define diagnostic_kind_count(DC, DK) (DC)->diagnostic_count[(int) (DK)]
+
+/* The number of errors that have been issued so far.  Ideally, these
+   would take a diagnostic_context as an argument.  */
+#define errorcount diagnostic_kind_count (global_dc, DK_ERROR)
+/* Similarly, but for warnings.  */
+#define warningcount diagnostic_kind_count (global_dc, DK_WARNING)
+/* Similarly, but for sorrys.  */
+#define sorrycount diagnostic_kind_count (global_dc, DK_SORRY)
+
+/* Returns nonzero if warnings should be emitted.  */
+#define diagnostic_report_warnings_p()                 \
+  (!inhibit_warnings                                   \
+   && !(in_system_header && !warn_system_headers))
+
+#define report_diagnostic(D) diagnostic_report_diagnostic (global_dc, D)
+
+/* Diagnostic related functions.  */
+extern void diagnostic_initialize (diagnostic_context *);
+extern void diagnostic_report_current_module (diagnostic_context *);
+extern void diagnostic_report_current_function (diagnostic_context *);
+extern void diagnostic_report_diagnostic (diagnostic_context *,
+                                         diagnostic_info *);
+extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *,
+                                location_t, diagnostic_t);
+extern char *diagnostic_build_prefix (diagnostic_info *);
+
+/* Pure text formatting support functions.  */
+extern void verbatim (const char *, ...);
+extern char *file_name_as_prefix (const char *);
+
+#endif /* ! GCC_DIAGNOSTIC_H */
index 320552c5b7c5251dd9df4f0eee3cb210339b3c06..5093a65059a8fbd1316886a8c563c3911089ddab 100644 (file)
@@ -1,5 +1,5 @@
 /* Exception Handling interface routines.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
    Contributed by Mike Stump <mrs@cygnus.com>.
 
@@ -21,11 +21,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 02111-1307, USA.  */
 
 
-#ifndef GCC_VARRAY_H
-struct varray_head_tag;
-#define varray_type struct varray_head_tag *
-#endif
-
 struct function;
 
 struct inline_remap;
@@ -38,95 +33,95 @@ struct eh_status;
 struct eh_region;
 
 /* Test: is exception handling turned on?  */
-extern int doing_eh                            PARAMS ((int));
+extern int doing_eh (int);
 
 /* Start an exception handling region.  All instructions emitted after
    this point are considered to be part of the region until an
    expand_eh_region_end variant is invoked.  */
-extern void expand_eh_region_start             PARAMS ((void));
+extern void expand_eh_region_start (void);
 
 /* End an exception handling region for a cleanup.  HANDLER is an
    expression to expand for the cleanup.  */
-extern void expand_eh_region_end_cleanup       PARAMS ((tree));
+extern void expand_eh_region_end_cleanup (tree);
 
 /* End an exception handling region for a try block, and prepares
    for subsequent calls to expand_start_catch.  */
-extern void expand_start_all_catch             PARAMS ((void));
+extern void expand_start_all_catch (void);
 
 /* Begin a catch clause.  TYPE is an object to be matched by the
    runtime, or a list of such objects, or null if this is a catch-all
    clause.  */
-extern void expand_start_catch                 PARAMS ((tree));
+extern void expand_start_catch (tree);
 
 /* End a catch clause.  Control will resume after the try/catch block.  */
-extern void expand_end_catch                   PARAMS ((void));
+extern void expand_end_catch (void);
 
 /* End a sequence of catch handlers for a try block.  */
-extern void expand_end_all_catch               PARAMS ((void));
+extern void expand_end_all_catch (void);
 
 /* End an exception region for an exception type filter.  ALLOWED is a
    TREE_LIST of TREE_VALUE objects to be matched by the runtime.
    FAILURE is a function to invoke if a mismatch occurs.  */
-extern void expand_eh_region_end_allowed       PARAMS ((tree, tree));
+extern void expand_eh_region_end_allowed (tree, tree);
 
 /* End an exception region for a must-not-throw filter.  FAILURE is a
    function to invoke if an uncaught exception propagates this far.  */
-extern void expand_eh_region_end_must_not_throw        PARAMS ((tree));
+extern void expand_eh_region_end_must_not_throw (tree);
 
 /* End an exception region for a throw.  No handling goes on here,
    but it's the easiest way for the front-end to indicate what type
    is being thrown.  */
-extern void expand_eh_region_end_throw         PARAMS ((tree));
+extern void expand_eh_region_end_throw (tree);
 
 /* End a fixup region.  Within this region the cleanups for the immediately
    enclosing region are _not_ run.  This is used for goto cleanup to avoid
    destroying an object twice.  */
-extern void expand_eh_region_end_fixup         PARAMS ((tree));
+extern void expand_eh_region_end_fixup (tree);
 
 /* Note that the current EH region (if any) may contain a throw, or a
    call to a function which itself may contain a throw.  */
-extern void note_eh_region_may_contain_throw    PARAMS ((void));
+extern void note_eh_region_may_contain_throw (void);
 
 /* Invokes CALLBACK for every exception handler label.  Only used by old
    loop hackery; should not be used by new code.  */
-extern void for_each_eh_label                  PARAMS ((void (*) (rtx)));
+extern void for_each_eh_label (void (*) (rtx));
 
 /* Determine if the given INSN can throw an exception.  */
-extern bool can_throw_internal                 PARAMS ((rtx));
-extern bool can_throw_external                 PARAMS ((rtx));
+extern bool can_throw_internal (rtx);
+extern bool can_throw_external (rtx);
 
 /* Set current_function_nothrow and cfun->all_throwers_are_sibcalls.  */
-extern void set_nothrow_function_flags         PARAMS ((void));
+extern void set_nothrow_function_flags (void);
 
 /* After initial rtl generation, call back to finish generating
    exception support code.  */
-extern void finish_eh_generation               PARAMS ((void));
+extern void finish_eh_generation (void);
 
-extern void init_eh                            PARAMS ((void));
-extern void init_eh_for_function               PARAMS ((void));
+extern void init_eh (void);
+extern void init_eh_for_function (void);
 
-extern rtx reachable_handlers                  PARAMS ((rtx));
-extern void maybe_remove_eh_handler            PARAMS ((rtx));
+extern rtx reachable_handlers (rtx);
+extern void maybe_remove_eh_handler (rtx);
 
-extern void convert_from_eh_region_ranges      PARAMS ((void));
-extern void convert_to_eh_region_ranges                PARAMS ((void));
-extern void find_exception_handler_labels      PARAMS ((void));
-extern bool current_function_has_exception_handlers PARAMS ((void));
-extern void output_function_exception_table    PARAMS ((void));
+extern void convert_from_eh_region_ranges (void);
+extern void convert_to_eh_region_ranges (void);
+extern void find_exception_handler_labels (void);
+extern bool current_function_has_exception_handlers (void);
+extern void output_function_exception_table (void);
 
-extern void expand_builtin_unwind_init         PARAMS ((void));
-extern rtx expand_builtin_eh_return_data_regno PARAMS ((tree));
-extern rtx expand_builtin_extract_return_addr  PARAMS ((tree));
-extern void expand_builtin_init_dwarf_reg_sizes PARAMS ((tree));
-extern rtx expand_builtin_frob_return_addr     PARAMS ((tree));
-extern rtx expand_builtin_dwarf_sp_column      PARAMS ((void));
-extern void expand_builtin_eh_return           PARAMS ((tree, tree));
-extern void expand_eh_return                   PARAMS ((void));
-extern rtx get_exception_pointer               PARAMS ((struct function *));
-extern int duplicate_eh_regions                        PARAMS ((struct function *,
-                                                struct inline_remap *));
+extern void expand_builtin_unwind_init (void);
+extern rtx expand_builtin_eh_return_data_regno (tree);
+extern rtx expand_builtin_extract_return_addr (tree);
+extern void expand_builtin_init_dwarf_reg_sizes (tree);
+extern rtx expand_builtin_frob_return_addr (tree);
+extern rtx expand_builtin_dwarf_sp_column (void);
+extern void expand_builtin_eh_return (tree, tree);
+extern void expand_eh_return (void);
+extern rtx expand_builtin_extend_pointer (tree);
+extern rtx get_exception_pointer (struct function *);
+extern int duplicate_eh_regions (struct function *, struct inline_remap *);
 
-extern void sjlj_emit_function_exit_after      PARAMS ((rtx));
+extern void sjlj_emit_function_exit_after (rtx);
 
 
 /* If non-NULL, this is a function that returns an expression to be
@@ -135,31 +130,29 @@ extern void sjlj_emit_function_exit_after PARAMS ((rtx));
    during stack unwinding is required to result in a call to
    `std::terminate', so the C++ version of this function returns a
    CALL_EXPR for `std::terminate'.  */
-extern tree (*lang_protect_cleanup_actions) PARAMS ((void));
+extern tree (*lang_protect_cleanup_actions) (void);
 
 /* Return true if type A catches type B.  */
-extern int (*lang_eh_type_covers) PARAMS ((tree a, tree b));
+extern int (*lang_eh_type_covers) (tree a, tree b);
 
 /* Map a type to a runtime object to match type.  */
-extern tree (*lang_eh_runtime_type) PARAMS ((tree));
-
-#ifndef GCC_VARRAY_H
-#undef varray_type
-#endif
+extern tree (*lang_eh_runtime_type) (tree);
 
 
 /* Just because the user configured --with-sjlj-exceptions=no doesn't
    mean that we can use call frame exceptions.  Detect that the target
    has appropriate support.  */
 
-#if ! (defined (EH_RETURN_DATA_REGNO)                  \
+#ifndef MUST_USE_SJLJ_EXCEPTIONS
+# if !(defined (EH_RETURN_DATA_REGNO)                  \
        && (defined (IA64_UNWIND_INFO)                  \
           || (DWARF2_UNWIND_INFO                       \
               && (defined (EH_RETURN_HANDLER_RTX)      \
                   || defined (HAVE_eh_return)))))
-#define MUST_USE_SJLJ_EXCEPTIONS       1
-#else
-#define MUST_USE_SJLJ_EXCEPTIONS       0
+#  define MUST_USE_SJLJ_EXCEPTIONS     1
+# else
+#  define MUST_USE_SJLJ_EXCEPTIONS     0
+# endif
 #endif
 
 #ifdef CONFIG_SJLJ_EXCEPTIONS
diff --git a/support/cpp2/hashtab.c b/support/cpp2/hashtab.c
new file mode 100644 (file)
index 0000000..231fbc0
--- /dev/null
@@ -0,0 +1,853 @@
+/* An expandable hash tables datatype.  
+   Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Vladimir Makarov (vmakarov@cygnus.com).
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* This package implements basic hash table functionality.  It is possible
+   to search for an entry, create an entry and destroy an entry.
+
+   Elements in the table are generic pointers.
+
+   The size of the table is not fixed; if the occupancy of the table
+   grows too high the hash table will be expanded.
+
+   The abstract data implementation is based on generalized Algorithm D
+   from Knuth's book "The art of computer programming".  Hash table is
+   expanded by creation of new hash table and transferring elements from
+   the old table to the new table. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#include <stdio.h>
+
+#include "libiberty.h"
+#include "hashtab.h"
+
+/* This macro defines reserved value for empty table entry. */
+
+#define EMPTY_ENTRY    ((PTR) 0)
+
+/* This macro defines reserved value for table entry which contained
+   a deleted element. */
+
+#define DELETED_ENTRY  ((PTR) 1)
+
+static unsigned long higher_prime_number PARAMS ((unsigned long));
+static hashval_t hash_pointer PARAMS ((const void *));
+static int eq_pointer PARAMS ((const void *, const void *));
+static int htab_expand PARAMS ((htab_t));
+static PTR *find_empty_slot_for_expand  PARAMS ((htab_t, hashval_t));
+
+/* At some point, we could make these be NULL, and modify the
+   hash-table routines to handle NULL specially; that would avoid
+   function-call overhead for the common case of hashing pointers.  */
+htab_hash htab_hash_pointer = hash_pointer;
+htab_eq htab_eq_pointer = eq_pointer;
+
+/* The following function returns a nearest prime number which is
+   greater than N, and near a power of two. */
+
+static unsigned long
+higher_prime_number (n)
+     unsigned long n;
+{
+  /* These are primes that are near, but slightly smaller than, a
+     power of two.  */
+  static const unsigned long primes[] = {
+    (unsigned long) 7,
+    (unsigned long) 13,
+    (unsigned long) 31,
+    (unsigned long) 61,
+    (unsigned long) 127,
+    (unsigned long) 251,
+    (unsigned long) 509,
+    (unsigned long) 1021,
+    (unsigned long) 2039,
+    (unsigned long) 4093,
+    (unsigned long) 8191,
+    (unsigned long) 16381,
+    (unsigned long) 32749,
+    (unsigned long) 65521,
+    (unsigned long) 131071,
+    (unsigned long) 262139,
+    (unsigned long) 524287,
+    (unsigned long) 1048573,
+    (unsigned long) 2097143,
+    (unsigned long) 4194301,
+    (unsigned long) 8388593,
+    (unsigned long) 16777213,
+    (unsigned long) 33554393,
+    (unsigned long) 67108859,
+    (unsigned long) 134217689,
+    (unsigned long) 268435399,
+    (unsigned long) 536870909,
+    (unsigned long) 1073741789,
+    (unsigned long) 2147483647,
+                                       /* 4294967291L */
+    ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
+  };
+
+  const unsigned long *low = &primes[0];
+  const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])];
+
+  while (low != high)
+    {
+      const unsigned long *mid = low + (high - low) / 2;
+      if (n > *mid)
+       low = mid + 1;
+      else
+       high = mid;
+    }
+
+  /* If we've run out of primes, abort.  */
+  if (n > *low)
+    {
+      fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+      abort ();
+    }
+
+  return *low;
+}
+
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_pointer (p)
+     const PTR p;
+{
+  return (hashval_t) ((long)p >> 3);
+}
+
+/* Returns non-zero if P1 and P2 are equal.  */
+
+static int
+eq_pointer (p1, p2)
+     const PTR p1;
+     const PTR p2;
+{
+  return p1 == p2;
+}
+
+/* This function creates table with length slightly longer than given
+   source length.  Created hash table is initiated as empty (all the
+   hash table entries are EMPTY_ENTRY).  The function returns the
+   created hash table, or NULL if memory allocation fails.  */
+
+htab_t
+htab_create_alloc (size, hash_f, eq_f, del_f, alloc_f, free_f)
+     size_t size;
+     htab_hash hash_f;
+     htab_eq eq_f;
+     htab_del del_f;
+     htab_alloc alloc_f;
+     htab_free free_f;
+{
+  htab_t result;
+
+  size = higher_prime_number (size);
+  result = (htab_t) (*alloc_f) (1, sizeof (struct htab));
+  if (result == NULL)
+    return NULL;
+  result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR));
+  if (result->entries == NULL)
+    {
+      if (free_f != NULL)
+       (*free_f) (result);
+      return NULL;
+    }
+  result->size = size;
+  result->hash_f = hash_f;
+  result->eq_f = eq_f;
+  result->del_f = del_f;
+  result->alloc_f = alloc_f;
+  result->free_f = free_f;
+  return result;
+}
+
+/* As above, but use the variants of alloc_f and free_f which accept
+   an extra argument.  */
+
+htab_t
+htab_create_alloc_ex (size, hash_f, eq_f, del_f, alloc_arg, alloc_f,
+                     free_f)
+     size_t size;
+     htab_hash hash_f;
+     htab_eq eq_f;
+     htab_del del_f;
+     PTR alloc_arg;
+     htab_alloc_with_arg alloc_f;
+     htab_free_with_arg free_f;
+{
+  htab_t result;
+
+  size = higher_prime_number (size);
+  result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab));
+  if (result == NULL)
+    return NULL;
+  result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR));
+  if (result->entries == NULL)
+    {
+      if (free_f != NULL)
+       (*free_f) (alloc_arg, result);
+      return NULL;
+    }
+  result->size = size;
+  result->hash_f = hash_f;
+  result->eq_f = eq_f;
+  result->del_f = del_f;
+  result->alloc_arg = alloc_arg;
+  result->alloc_with_arg_f = alloc_f;
+  result->free_with_arg_f = free_f;
+  return result;
+}
+
+/* Update the function pointers and allocation parameter in the htab_t.  */
+
+void
+htab_set_functions_ex (htab, hash_f, eq_f, del_f, alloc_arg, alloc_f, free_f)
+     htab_t htab;
+     htab_hash hash_f;
+     htab_eq eq_f;
+     htab_del del_f;
+     PTR alloc_arg;
+     htab_alloc_with_arg alloc_f;
+     htab_free_with_arg free_f;
+{
+  htab->hash_f = hash_f;
+  htab->eq_f = eq_f;
+  htab->del_f = del_f;
+  htab->alloc_arg = alloc_arg;
+  htab->alloc_with_arg_f = alloc_f;
+  htab->free_with_arg_f = free_f;
+}
+
+/* These functions exist solely for backward compatibility.  */
+
+#undef htab_create
+htab_t
+htab_create (size, hash_f, eq_f, del_f)
+     size_t size;
+     htab_hash hash_f;
+     htab_eq eq_f;
+     htab_del del_f;
+{
+  return htab_create_alloc (size, hash_f, eq_f, del_f, xcalloc, free);
+}
+
+htab_t
+htab_try_create (size, hash_f, eq_f, del_f)
+     size_t size;
+     htab_hash hash_f;
+     htab_eq eq_f;
+     htab_del del_f;
+{
+  return htab_create_alloc (size, hash_f, eq_f, del_f, calloc, free);
+}
+
+/* This function frees all memory allocated for given hash table.
+   Naturally the hash table must already exist. */
+
+void
+htab_delete (htab)
+     htab_t htab;
+{
+  int i;
+
+  if (htab->del_f)
+    for (i = htab->size - 1; i >= 0; i--)
+      if (htab->entries[i] != EMPTY_ENTRY
+         && htab->entries[i] != DELETED_ENTRY)
+       (*htab->del_f) (htab->entries[i]);
+
+  if (htab->free_f != NULL)
+    {
+      (*htab->free_f) (htab->entries);
+      (*htab->free_f) (htab);
+    }
+  else if (htab->free_with_arg_f != NULL)
+    {
+      (*htab->free_with_arg_f) (htab->alloc_arg, htab->entries);
+      (*htab->free_with_arg_f) (htab->alloc_arg, htab);
+    }
+}
+
+/* This function clears all entries in the given hash table.  */
+
+void
+htab_empty (htab)
+     htab_t htab;
+{
+  int i;
+
+  if (htab->del_f)
+    for (i = htab->size - 1; i >= 0; i--)
+      if (htab->entries[i] != EMPTY_ENTRY
+         && htab->entries[i] != DELETED_ENTRY)
+       (*htab->del_f) (htab->entries[i]);
+
+  memset (htab->entries, 0, htab->size * sizeof (PTR));
+}
+
+/* Similar to htab_find_slot, but without several unwanted side effects:
+    - Does not call htab->eq_f when it finds an existing entry.
+    - Does not change the count of elements/searches/collisions in the
+      hash table.
+   This function also assumes there are no deleted entries in the table.
+   HASH is the hash value for the element to be inserted.  */
+
+static PTR *
+find_empty_slot_for_expand (htab, hash)
+     htab_t htab;
+     hashval_t hash;
+{
+  size_t size = htab->size;
+  unsigned int index = hash % size;
+  PTR *slot = htab->entries + index;
+  hashval_t hash2;
+
+  if (*slot == EMPTY_ENTRY)
+    return slot;
+  else if (*slot == DELETED_ENTRY)
+    abort ();
+
+  hash2 = 1 + hash % (size - 2);
+  for (;;)
+    {
+      index += hash2;
+      if (index >= size)
+       index -= size;
+
+      slot = htab->entries + index;
+      if (*slot == EMPTY_ENTRY)
+       return slot;
+      else if (*slot == DELETED_ENTRY)
+       abort ();
+    }
+}
+
+/* The following function changes size of memory allocated for the
+   entries and repeatedly inserts the table elements.  The occupancy
+   of the table after the call will be about 50%.  Naturally the hash
+   table must already exist.  Remember also that the place of the
+   table entries is changed.  If memory allocation failures are allowed,
+   this function will return zero, indicating that the table could not be
+   expanded.  If all goes well, it will return a non-zero value.  */
+
+static int
+htab_expand (htab)
+     htab_t htab;
+{
+  PTR *oentries;
+  PTR *olimit;
+  PTR *p;
+  PTR *nentries;
+  size_t nsize;
+
+  oentries = htab->entries;
+  olimit = oentries + htab->size;
+
+  /* Resize only when table after removal of unused elements is either
+     too full or too empty.  */
+  if ((htab->n_elements - htab->n_deleted) * 2 > htab->size
+      || ((htab->n_elements - htab->n_deleted) * 8 < htab->size
+         && htab->size > 32))
+    nsize = higher_prime_number ((htab->n_elements - htab->n_deleted) * 2);
+  else
+    nsize = htab->size;
+
+  if (htab->alloc_with_arg_f != NULL)
+    nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize,
+                                                 sizeof (PTR *));
+  else
+    nentries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *));
+  if (nentries == NULL)
+    return 0;
+  htab->entries = nentries;
+  htab->size = nsize;
+
+  htab->n_elements -= htab->n_deleted;
+  htab->n_deleted = 0;
+
+  p = oentries;
+  do
+    {
+      PTR x = *p;
+
+      if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+       {
+         PTR *q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x));
+
+         *q = x;
+       }
+
+      p++;
+    }
+  while (p < olimit);
+
+  if (htab->free_f != NULL)
+    (*htab->free_f) (oentries);
+  else if (htab->free_with_arg_f != NULL)
+    (*htab->free_with_arg_f) (htab->alloc_arg, oentries);
+  return 1;
+}
+
+/* This function searches for a hash table entry equal to the given
+   element.  It cannot be used to insert or delete an element.  */
+
+PTR
+htab_find_with_hash (htab, element, hash)
+     htab_t htab;
+     const PTR element;
+     hashval_t hash;
+{
+  unsigned int index;
+  hashval_t hash2;
+  size_t size;
+  PTR entry;
+
+  htab->searches++;
+  size = htab->size;
+  index = hash % size;
+
+  entry = htab->entries[index];
+  if (entry == EMPTY_ENTRY
+      || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+    return entry;
+
+  hash2 = 1 + hash % (size - 2);
+
+  for (;;)
+    {
+      htab->collisions++;
+      index += hash2;
+      if (index >= size)
+       index -= size;
+
+      entry = htab->entries[index];
+      if (entry == EMPTY_ENTRY
+         || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+       return entry;
+    }
+}
+
+/* Like htab_find_slot_with_hash, but compute the hash value from the
+   element.  */
+
+PTR
+htab_find (htab, element)
+     htab_t htab;
+     const PTR element;
+{
+  return htab_find_with_hash (htab, element, (*htab->hash_f) (element));
+}
+
+/* This function searches for a hash table slot containing an entry
+   equal to the given element.  To delete an entry, call this with
+   INSERT = 0, then call htab_clear_slot on the slot returned (possibly
+   after doing some checks).  To insert an entry, call this with
+   INSERT = 1, then write the value you want into the returned slot.
+   When inserting an entry, NULL may be returned if memory allocation
+   fails.  */
+
+PTR *
+htab_find_slot_with_hash (htab, element, hash, insert)
+     htab_t htab;
+     const PTR element;
+     hashval_t hash;
+     enum insert_option insert;
+{
+  PTR *first_deleted_slot;
+  unsigned int index;
+  hashval_t hash2;
+  size_t size;
+  PTR entry;
+
+  if (insert == INSERT && htab->size * 3 <= htab->n_elements * 4
+      && htab_expand (htab) == 0)
+    return NULL;
+
+  size = htab->size;
+  index = hash % size;
+
+  htab->searches++;
+  first_deleted_slot = NULL;
+
+  entry = htab->entries[index];
+  if (entry == EMPTY_ENTRY)
+    goto empty_entry;
+  else if (entry == DELETED_ENTRY)
+    first_deleted_slot = &htab->entries[index];
+  else if ((*htab->eq_f) (entry, element))
+    return &htab->entries[index];
+      
+  hash2 = 1 + hash % (size - 2);
+  for (;;)
+    {
+      htab->collisions++;
+      index += hash2;
+      if (index >= size)
+       index -= size;
+      
+      entry = htab->entries[index];
+      if (entry == EMPTY_ENTRY)
+       goto empty_entry;
+      else if (entry == DELETED_ENTRY)
+       {
+         if (!first_deleted_slot)
+           first_deleted_slot = &htab->entries[index];
+       }
+      else if ((*htab->eq_f) (entry, element))
+       return &htab->entries[index];
+    }
+
+ empty_entry:
+  if (insert == NO_INSERT)
+    return NULL;
+
+  if (first_deleted_slot)
+    {
+      htab->n_deleted--;
+      *first_deleted_slot = EMPTY_ENTRY;
+      return first_deleted_slot;
+    }
+
+  htab->n_elements++;
+  return &htab->entries[index];
+}
+
+/* Like htab_find_slot_with_hash, but compute the hash value from the
+   element.  */
+
+PTR *
+htab_find_slot (htab, element, insert)
+     htab_t htab;
+     const PTR element;
+     enum insert_option insert;
+{
+  return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element),
+                                  insert);
+}
+
+/* This function deletes an element with the given value from hash
+   table.  If there is no matching element in the hash table, this
+   function does nothing.  */
+
+void
+htab_remove_elt (htab, element)
+     htab_t htab;
+     PTR element;
+{
+  PTR *slot;
+
+  slot = htab_find_slot (htab, element, NO_INSERT);
+  if (*slot == EMPTY_ENTRY)
+    return;
+
+  if (htab->del_f)
+    (*htab->del_f) (*slot);
+
+  *slot = DELETED_ENTRY;
+  htab->n_deleted++;
+}
+
+/* This function clears a specified slot in a hash table.  It is
+   useful when you've already done the lookup and don't want to do it
+   again.  */
+
+void
+htab_clear_slot (htab, slot)
+     htab_t htab;
+     PTR *slot;
+{
+  if (slot < htab->entries || slot >= htab->entries + htab->size
+      || *slot == EMPTY_ENTRY || *slot == DELETED_ENTRY)
+    abort ();
+
+  if (htab->del_f)
+    (*htab->del_f) (*slot);
+
+  *slot = DELETED_ENTRY;
+  htab->n_deleted++;
+}
+
+/* This function scans over the entire hash table calling
+   CALLBACK for each live entry.  If CALLBACK returns false,
+   the iteration stops.  INFO is passed as CALLBACK's second
+   argument.  */
+
+void
+htab_traverse_noresize (htab, callback, info)
+     htab_t htab;
+     htab_trav callback;
+     PTR info;
+{
+  PTR *slot;
+  PTR *limit;
+
+  slot = htab->entries;
+  limit = slot + htab->size;
+
+  do
+    {
+      PTR x = *slot;
+
+      if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+       if (!(*callback) (slot, info))
+         break;
+    }
+  while (++slot < limit);
+}
+
+/* Like htab_traverse_noresize, but does resize the table when it is
+   too empty to improve effectivity of subsequent calls.  */
+
+void
+htab_traverse (htab, callback, info)
+     htab_t htab;
+     htab_trav callback;
+     PTR info;
+{
+  if ((htab->n_elements - htab->n_deleted) * 8 < htab->size)
+    htab_expand (htab);
+
+  htab_traverse_noresize (htab, callback, info);
+}
+
+/* Return the current size of given hash table. */
+
+size_t
+htab_size (htab)
+     htab_t htab;
+{
+  return htab->size;
+}
+
+/* Return the current number of elements in given hash table. */
+
+size_t
+htab_elements (htab)
+     htab_t htab;
+{
+  return htab->n_elements - htab->n_deleted;
+}
+
+/* Return the fraction of fixed collisions during all work with given
+   hash table. */
+
+double
+htab_collisions (htab)
+     htab_t htab;
+{
+  if (htab->searches == 0)
+    return 0.0;
+
+  return (double) htab->collisions / (double) htab->searches;
+}
+
+/* Hash P as a null-terminated string.
+
+   Copied from gcc/hashtable.c.  Zack had the following to say with respect
+   to applicability, though note that unlike hashtable.c, this hash table
+   implementation re-hashes rather than chain buckets.
+
+   http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01021.html
+   From: Zack Weinberg <zackw@panix.com>
+   Date: Fri, 17 Aug 2001 02:15:56 -0400
+
+   I got it by extracting all the identifiers from all the source code
+   I had lying around in mid-1999, and testing many recurrences of
+   the form "H_n = H_{n-1} * K + c_n * L + M" where K, L, M were either
+   prime numbers or the appropriate identity.  This was the best one.
+   I don't remember exactly what constituted "best", except I was
+   looking at bucket-length distributions mostly.
+   
+   So it should be very good at hashing identifiers, but might not be
+   as good at arbitrary strings.
+   
+   I'll add that it thoroughly trounces the hash functions recommended
+   for this use at http://burtleburtle.net/bob/hash/index.html, both
+   on speed and bucket distribution.  I haven't tried it against the
+   function they just started using for Perl's hashes.  */
+
+hashval_t
+htab_hash_string (p)
+     const PTR p;
+{
+  const unsigned char *str = (const unsigned char *) p;
+  hashval_t r = 0;
+  unsigned char c;
+
+  while ((c = *str++) != 0)
+    r = r * 67 + c - 113;
+
+  return r;
+}
+
+/* DERIVED FROM:
+--------------------------------------------------------------------
+lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+hash(), hash2(), hash3, and mix() are externally useful functions.
+Routines to test the hash are included if SELF_TEST is defined.
+You can use this free for any purpose.  It has no warranty.
+--------------------------------------------------------------------
+*/
+
+/*
+--------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+For every delta with one or two bit set, and the deltas of all three
+  high bits or all three low bits, whether the original value of a,b,c
+  is almost all zero or is uniformly distributed,
+* If mix() is run forward or backward, at least 32 bits in a,b,c
+  have at least 1/4 probability of changing.
+* If mix() is run forward, every bit of c will change between 1/3 and
+  2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
+mix() was built out of 36 single-cycle latency instructions in a 
+  structure that could supported 2x parallelism, like so:
+      a -= b; 
+      a -= c; x = (c>>13);
+      b -= c; a ^= x;
+      b -= a; x = (a<<8);
+      c -= a; b ^= x;
+      c -= b; x = (b>>13);
+      ...
+  Unfortunately, superscalar Pentiums and Sparcs can't take advantage 
+  of that parallelism.  They've also turned some of those single-cycle
+  latency instructions into multi-cycle latency instructions.  Still,
+  this is the fastest good hash I could find.  There were about 2^^68
+  to choose from.  I only looked at a billion or so.
+--------------------------------------------------------------------
+*/
+/* same, but slower, works on systems that might have 8 byte hashval_t's */
+#define mix(a,b,c) \
+{ \
+  a -= b; a -= c; a ^= (c>>13); \
+  b -= c; b -= a; b ^= (a<< 8); \
+  c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \
+  a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \
+  b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \
+  c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \
+  a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \
+  b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \
+  c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
+}
+
+/*
+--------------------------------------------------------------------
+hash() -- hash a variable-length key into a 32-bit value
+  k     : the key (the unaligned variable-length array of bytes)
+  len   : the length of the key, counting by bytes
+  level : can be any 4-byte value
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Every 1-bit and 2-bit delta achieves avalanche.
+About 36+6len instructions.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (ub1 **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
+
+By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial.  It's free.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use for hash table lookup, or anything where one collision in 2^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+--------------------------------------------------------------------
+*/
+
+hashval_t iterative_hash (k_in, length, initval)
+     const PTR k_in;               /* the key */
+     register size_t  length;      /* the length of the key */
+     register hashval_t  initval;  /* the previous hash, or an arbitrary value */
+{
+  register const unsigned char *k = (const unsigned char *)k_in;
+  register hashval_t a,b,c,len;
+
+  /* Set up the internal state */
+  len = length;
+  a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
+  c = initval;           /* the previous hash value */
+
+  /*---------------------------------------- handle most of the key */
+#ifndef WORDS_BIGENDIAN
+  /* On a little-endian machine, if the data is 4-byte aligned we can hash
+     by word for better speed.  This gives nondeterministic results on
+     big-endian machines.  */
+  if (sizeof (hashval_t) == 4 && (((size_t)k)&3) == 0)
+    while (len >= 12)    /* aligned */
+      {
+       a += *(hashval_t *)(k+0);
+       b += *(hashval_t *)(k+4);
+       c += *(hashval_t *)(k+8);
+       mix(a,b,c);
+       k += 12; len -= 12;
+      }
+  else /* unaligned */
+#endif
+    while (len >= 12)
+      {
+       a += (k[0] +((hashval_t)k[1]<<8) +((hashval_t)k[2]<<16) +((hashval_t)k[3]<<24));
+       b += (k[4] +((hashval_t)k[5]<<8) +((hashval_t)k[6]<<16) +((hashval_t)k[7]<<24));
+       c += (k[8] +((hashval_t)k[9]<<8) +((hashval_t)k[10]<<16)+((hashval_t)k[11]<<24));
+       mix(a,b,c);
+       k += 12; len -= 12;
+      }
+
+  /*------------------------------------- handle the last 11 bytes */
+  c += length;
+  switch(len)              /* all the case statements fall through */
+    {
+    case 11: c+=((hashval_t)k[10]<<24);
+    case 10: c+=((hashval_t)k[9]<<16);
+    case 9 : c+=((hashval_t)k[8]<<8);
+      /* the first byte of c is reserved for the length */
+    case 8 : b+=((hashval_t)k[7]<<24);
+    case 7 : b+=((hashval_t)k[6]<<16);
+    case 6 : b+=((hashval_t)k[5]<<8);
+    case 5 : b+=k[4];
+    case 4 : a+=((hashval_t)k[3]<<24);
+    case 3 : a+=((hashval_t)k[2]<<16);
+    case 2 : a+=((hashval_t)k[1]<<8);
+    case 1 : a+=k[0];
+      /* case 0: nothing left to add */
+    }
+  mix(a,b,c);
+  /*-------------------------------------------- report the result */
+  return c;
+}
diff --git a/support/cpp2/hashtab.h b/support/cpp2/hashtab.h
new file mode 100644 (file)
index 0000000..f7bd4ae
--- /dev/null
@@ -0,0 +1,195 @@
+/* An expandable hash tables datatype.  
+   Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Vladimir Makarov (vmakarov@cygnus.com).
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* This package implements basic hash table functionality.  It is possible
+   to search for an entry, create an entry and destroy an entry.
+
+   Elements in the table are generic pointers.
+
+   The size of the table is not fixed; if the occupancy of the table
+   grows too high the hash table will be expanded.
+
+   The abstract data implementation is based on generalized Algorithm D
+   from Knuth's book "The art of computer programming".  Hash table is
+   expanded by creation of new hash table and transferring elements from
+   the old table to the new table.  */
+
+#ifndef __HASHTAB_H__
+#define __HASHTAB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "ansidecl.h"
+
+#ifndef GTY
+#define GTY(X)
+#endif
+
+/* The type for a hash code.  */
+typedef unsigned int hashval_t;
+
+/* Callback function pointer types.  */
+
+/* Calculate hash of a table entry.  */
+typedef hashval_t (*htab_hash) PARAMS ((const void *));
+
+/* Compare a table entry with a possible entry.  The entry already in
+   the table always comes first, so the second element can be of a
+   different type (but in this case htab_find and htab_find_slot
+   cannot be used; instead the variants that accept a hash value
+   must be used).  */
+typedef int (*htab_eq) PARAMS ((const void *, const void *));
+
+/* Cleanup function called whenever a live element is removed from
+   the hash table.  */
+typedef void (*htab_del) PARAMS ((void *));
+  
+/* Function called by htab_traverse for each live element.  The first
+   arg is the slot of the element (which can be passed to htab_clear_slot
+   if desired), the second arg is the auxiliary pointer handed to
+   htab_traverse.  Return 1 to continue scan, 0 to stop.  */
+typedef int (*htab_trav) PARAMS ((void **, void *));
+
+/* Memory-allocation function, with the same functionality as calloc().
+   Iff it returns NULL, the hash table implementation will pass an error
+   code back to the user, so if your code doesn't handle errors,
+   best if you use xcalloc instead.  */
+typedef PTR (*htab_alloc) PARAMS ((size_t, size_t));
+
+/* We also need a free() routine.  */
+typedef void (*htab_free) PARAMS ((PTR));
+
+/* Memory allocation and deallocation; variants which take an extra
+   argument.  */
+typedef PTR (*htab_alloc_with_arg) PARAMS ((void *, size_t, size_t));
+typedef void (*htab_free_with_arg) PARAMS ((void *, void *));
+
+/* Hash tables are of the following type.  The structure
+   (implementation) of this type is not needed for using the hash
+   tables.  All work with hash table should be executed only through
+   functions mentioned below.  The size of this structure is subject to
+   change.  */
+
+struct htab GTY(())
+{
+  /* Pointer to hash function.  */
+  htab_hash hash_f;
+
+  /* Pointer to comparison function.  */
+  htab_eq eq_f;
+
+  /* Pointer to cleanup function.  */
+  htab_del del_f;
+
+  /* Table itself.  */
+  PTR * GTY ((use_param (""), length ("%h.size"))) entries;
+
+  /* Current size (in entries) of the hash table */
+  size_t size;
+
+  /* Current number of elements including also deleted elements */
+  size_t n_elements;
+
+  /* Current number of deleted elements in the table */
+  size_t n_deleted;
+
+  /* The following member is used for debugging. Its value is number
+     of all calls of `htab_find_slot' for the hash table. */
+  unsigned int searches;
+
+  /* The following member is used for debugging.  Its value is number
+     of collisions fixed for time of work with the hash table. */
+  unsigned int collisions;
+
+  /* Pointers to allocate/free functions.  */
+  htab_alloc alloc_f;
+  htab_free free_f;
+
+  /* Alternate allocate/free functions, which take an extra argument.  */
+  PTR GTY((skip (""))) alloc_arg;
+  htab_alloc_with_arg alloc_with_arg_f;
+  htab_free_with_arg free_with_arg_f;
+};
+
+typedef struct htab *htab_t;
+
+/* An enum saying whether we insert into the hash table or not.  */
+enum insert_option {NO_INSERT, INSERT};
+
+/* The prototypes of the package functions. */
+
+extern htab_t  htab_create_alloc       PARAMS ((size_t, htab_hash,
+                                                htab_eq, htab_del,
+                                                htab_alloc, htab_free));
+
+extern htab_t  htab_create_alloc_ex    PARAMS ((size_t, htab_hash,
+                                                   htab_eq, htab_del,
+                                                   PTR, htab_alloc_with_arg,
+                                                   htab_free_with_arg));
+
+/* Backward-compatibility functions.  */
+extern htab_t htab_create PARAMS ((size_t, htab_hash, htab_eq, htab_del));
+extern htab_t htab_try_create PARAMS ((size_t, htab_hash, htab_eq, htab_del));
+
+extern void    htab_set_functions_ex   PARAMS ((htab_t, htab_hash,
+                                                htab_eq, htab_del,
+                                                PTR, htab_alloc_with_arg,
+                                                htab_free_with_arg));
+
+extern void    htab_delete     PARAMS ((htab_t));
+extern void    htab_empty      PARAMS ((htab_t));
+
+extern PTR     htab_find       PARAMS ((htab_t, const void *));
+extern PTR     *htab_find_slot PARAMS ((htab_t, const void *,
+                                        enum insert_option));
+extern PTR     htab_find_with_hash       PARAMS ((htab_t, const void *,
+                                                  hashval_t));
+extern PTR     *htab_find_slot_with_hash  PARAMS ((htab_t, const void *,
+                                                  hashval_t,
+                                                  enum insert_option));
+extern void    htab_clear_slot PARAMS ((htab_t, void **));
+extern void    htab_remove_elt PARAMS ((htab_t, void *));
+
+extern void    htab_traverse   PARAMS ((htab_t, htab_trav, void *));
+extern void    htab_traverse_noresize  PARAMS ((htab_t, htab_trav, void *));
+
+extern size_t  htab_size       PARAMS ((htab_t));
+extern size_t  htab_elements   PARAMS ((htab_t));
+extern double  htab_collisions PARAMS ((htab_t));
+
+/* A hash function for pointers.  */
+extern htab_hash htab_hash_pointer;
+
+/* An equality function for pointers.  */
+extern htab_eq htab_eq_pointer;
+
+/* A hash function for null-terminated strings.  */
+extern hashval_t htab_hash_string PARAMS ((const PTR));
+
+/* An iterative hash function for arbitrary data.  */
+extern hashval_t iterative_hash PARAMS ((const PTR, size_t, hashval_t));
+/* Shorthand for hashing something with an intrinsic size.  */
+#define iterative_hash_object(OB,INIT) iterative_hash (&OB, sizeof (OB), INIT)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __HASHTAB_H */
index b1d5b2d06c7657c29231153b0c15048a35f83316..58f19d055fc21c402146d581b584dcdfd639a47f 100644 (file)
@@ -1,5 +1,5 @@
 /* Hash tables.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -30,39 +30,16 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    existing entry with a potential new one.  Also, the ability to
    delete members from the table has been removed.  */
 
-static unsigned int calc_hash PARAMS ((const unsigned char *, unsigned int));
-static void ht_expand PARAMS ((hash_table *));
-
-/* Let particular systems override the size of a chunk.  */
-#ifndef OBSTACK_CHUNK_SIZE
-#define OBSTACK_CHUNK_SIZE 0
-#endif
-  /* Let them override the alloc and free routines too.  */
-#ifndef OBSTACK_CHUNK_ALLOC
-#define OBSTACK_CHUNK_ALLOC xmalloc
-#endif
-#ifndef OBSTACK_CHUNK_FREE
-#define OBSTACK_CHUNK_FREE free
-#endif
-
-/* Initialize an obstack.  */
-void
-gcc_obstack_init (obstack)
-     struct obstack *obstack;
-{
-  _obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
-                 (void *(*) PARAMS ((long))) OBSTACK_CHUNK_ALLOC,
-                 (void (*) PARAMS ((void *))) OBSTACK_CHUNK_FREE);
-}
+static unsigned int calc_hash (const unsigned char *, size_t);
+static void ht_expand (hash_table *);
+static double approx_sqrt (double);
 
 /* Calculate the hash of the string STR of length LEN.  */
 
 static unsigned int
-calc_hash (str, len)
-     const unsigned char *str;
-     unsigned int len;
+calc_hash (const unsigned char *str, size_t len)
 {
-  unsigned int n = len;
+  size_t n = len;
   unsigned int r = 0;
 #define HASHSTEP(r, c) ((r) * 67 + ((c) - 113));
 
@@ -76,20 +53,21 @@ calc_hash (str, len)
 /* Initialize an identifier hashtable.  */
 
 hash_table *
-ht_create (order)
-     unsigned int order;
+ht_create (unsigned int order)
 {
   unsigned int nslots = 1 << order;
   hash_table *table;
 
-  table = (hash_table *) xmalloc (sizeof (hash_table));
-  memset (table, 0, sizeof (hash_table));
+  table = xcalloc (1, sizeof (hash_table));
 
   /* Strings need no alignment.  */
-  gcc_obstack_init (&table->stack);
+  _obstack_begin (&table->stack, 0, 0,
+                 (void *(*) (long)) xmalloc,
+                 (void (*) (void *)) free);
+
   obstack_alignment_mask (&table->stack) = 0;
 
-  table->entries = (hashnode *) xcalloc (nslots, sizeof (hashnode));
+  table->entries = xcalloc (nslots, sizeof (hashnode));
   table->nslots = nslots;
   return table;
 }
@@ -97,8 +75,7 @@ ht_create (order)
 /* Frees all memory associated with a hash table.  */
 
 void
-ht_destroy (table)
-     hash_table *table;
+ht_destroy (hash_table *table)
 {
   obstack_free (&table->stack, NULL);
   free (table->entries);
@@ -114,11 +91,8 @@ ht_destroy (table)
    CPP_ALLOCED and the item is assumed to be at the top of the
    obstack.  */
 hashnode
-ht_lookup (table, str, len, insert)
-     hash_table *table;
-     const unsigned char *str;
-     unsigned int len;
-     enum ht_lookup_option insert;
+ht_lookup (hash_table *table, const unsigned char *str, size_t len,
+          enum ht_lookup_option insert)
 {
   unsigned int hash = calc_hash (str, len);
   unsigned int hash2;
@@ -128,31 +102,46 @@ ht_lookup (table, str, len, insert)
 
   sizemask = table->nslots - 1;
   index = hash & sizemask;
-
-  /* hash2 must be odd, so we're guaranteed to visit every possible
-     location in the table during rehashing.  */
-  hash2 = ((hash * 17) & sizemask) | 1;
   table->searches++;
 
-  for (;;)
+  node = table->entries[index];
+  if (node != NULL)
     {
-      node = table->entries[index];
-
-      if (node == NULL)
-       break;
-
-      if (node->hash_value == hash && HT_LEN (node) == len
-          && !memcmp (HT_STR (node), str, len))
+      if (node->hash_value == hash
+         && HT_LEN (node) == (unsigned int) len
+         && !memcmp (HT_STR (node), str, len))
        {
          if (insert == HT_ALLOCED)
            /* The string we search for was placed at the end of the
               obstack.  Release it.  */
-           obstack_free (&table->stack, (PTR) str);
+           obstack_free (&table->stack, (void *) str);
          return node;
        }
 
-      index = (index + hash2) & sizemask;
-      table->collisions++;
+      /* hash2 must be odd, so we're guaranteed to visit every possible
+        location in the table during rehashing.  */
+      hash2 = ((hash * 17) & sizemask) | 1;
+
+      for (;;)
+       {
+         table->collisions++;
+         index = (index + hash2) & sizemask;
+         node = table->entries[index];
+         if (node == NULL)
+           break;
+
+         if (node->hash_value == hash
+             && HT_LEN (node) == (unsigned int) len
+             && !memcmp (HT_STR (node), str, len))
+           {
+             if (insert == HT_ALLOCED)
+             /* The string we search for was placed at the end of the
+                obstack.  Release it.  */
+               obstack_free (&table->stack, (void *) str);
+             return node;
+           }
+       }
     }
 
   if (insert == HT_NO_INSERT)
@@ -161,7 +150,7 @@ ht_lookup (table, str, len, insert)
   node = (*table->alloc_node) (table);
   table->entries[index] = node;
 
-  HT_LEN (node) = len;
+  HT_LEN (node) = (unsigned int) len;
   node->hash_value = hash;
   if (insert == HT_ALLOC)
     HT_STR (node) = obstack_copy0 (&table->stack, str, len);
@@ -178,14 +167,13 @@ ht_lookup (table, str, len, insert)
 /* Double the size of a hash table, re-hashing existing entries.  */
 
 static void
-ht_expand (table)
-     hash_table *table;
+ht_expand (hash_table *table)
 {
   hashnode *nentries, *p, *limit;
   unsigned int size, sizemask;
 
   size = table->nslots * 2;
-  nentries = (hashnode *) xcalloc (size, sizeof (hashnode));
+  nentries = xcalloc (size, sizeof (hashnode));
   sizemask = size - 1;
 
   p = table->entries;
@@ -196,19 +184,18 @@ ht_expand (table)
        unsigned int index, hash, hash2;
 
        hash = (*p)->hash_value;
-       hash2 = ((hash * 17) & sizemask) | 1;
        index = hash & sizemask;
 
-       for (;;)
+       if (nentries[index])
          {
-           if (! nentries[index])
+           hash2 = ((hash * 17) & sizemask) | 1;
+           do
              {
-               nentries[index] = *p;
-               break;
+               index = (index + hash2) & sizemask;
              }
-
-           index = (index + hash2) & sizemask;
+           while (nentries[index]);
          }
+       nentries[index] = *p;
       }
   while (++p < limit);
 
@@ -220,10 +207,7 @@ ht_expand (table)
 /* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
    the node, and V.  */
 void
-ht_forall (table, cb, v)
-     hash_table *table;
-     ht_cb cb;
-     const PTR v;
+ht_forall (hash_table *table, ht_cb cb, const void *v)
 {
   hashnode *p, *limit;
 
@@ -241,8 +225,7 @@ ht_forall (table, cb, v)
 /* Dump allocation statistics to stderr.  */
 
 void
-ht_dump_statistics (table)
-     hash_table *table;
+ht_dump_statistics (hash_table *table)
 {
   size_t nelts, nids, overhead, headers;
   size_t total_bytes, longest, sum_of_squares;
@@ -306,9 +289,8 @@ ht_dump_statistics (table)
 
 /* Return the approximate positive square root of a number N.  This is for
    statistical reports, not code generation.  */
-double
-approx_sqrt (x)
-     double x;
+static double
+approx_sqrt (double x)
 {
   double s, d;
 
index c3e0d1ee10aeae7f683aa0f1af261f0cf8ad1a7e..068341c072c5b67d416e7d463dbbabc0382efa00 100644 (file)
@@ -1,5 +1,5 @@
 /* Hash tables.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -23,6 +23,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #else
 #include "obstack.h"
 #endif
+#define GTY(x) /* nothing */
 
 /* This is what each hash table entry points to.  It may be embedded
    deeply within another object.  */
@@ -37,11 +38,6 @@ struct ht_identifier GTY(())
 #define HT_LEN(NODE) ((NODE)->len)
 #define HT_STR(NODE) ((NODE)->str)
 
-/* We want code outside cpplib, such as the compiler front-ends, to be
-   able to include this header, and to be able to link with
-   cpphashtbl.o without pulling in any other parts of cpplib.  */
-
-struct cpp_reader;
 typedef struct ht hash_table;
 typedef struct ht_identifier *hashnode;
 
@@ -55,7 +51,7 @@ struct ht
 
   hashnode *entries;
   /* Call back.  */
-  hashnode (*alloc_node) PARAMS ((hash_table *));
+  hashnode (*alloc_node) (hash_table *);
 
   unsigned int nslots;         /* Total slots in the entries array.  */
   unsigned int nelements;      /* Number of live elements.  */
@@ -68,28 +64,22 @@ struct ht
   unsigned int collisions;
 };
 
-extern void gcc_obstack_init PARAMS ((struct obstack *));
-
 /* Initialize the hashtable with 2 ^ order entries.  */
-extern hash_table *ht_create PARAMS ((unsigned int order));
+extern hash_table *ht_create (unsigned int order);
 
 /* Frees all memory associated with a hash table.  */
-extern void ht_destroy PARAMS ((hash_table *));
+extern void ht_destroy (hash_table *);
 
-extern hashnode ht_lookup PARAMS ((hash_table *, const unsigned char *,
-                                  unsigned int, enum ht_lookup_option));
+extern hashnode ht_lookup (hash_table *, const unsigned char *,
+                          size_t, enum ht_lookup_option);
 
 /* For all nodes in TABLE, make a callback.  The callback takes
    TABLE->PFILE, the node, and a PTR, and the callback sequence stops
    if the callback returns zero.  */
-typedef int (*ht_cb) PARAMS ((struct cpp_reader *, hashnode, const void *));
-extern void ht_forall PARAMS ((hash_table *, ht_cb, const void *));
+typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *);
+extern void ht_forall (hash_table *, ht_cb, const void *);
 
 /* Dump allocation statistics to stderr.  */
-extern void ht_dump_statistics PARAMS ((hash_table *));
-
-/* Approximate positive square root of a host double.  This is for
-   statistical reports, not code generation.  */
-extern double approx_sqrt PARAMS ((double));
+extern void ht_dump_statistics (hash_table *);
 
 #endif /* GCC_HASHTABLE_H */
index 6d645a00ea7c9cfa6009603fd47d1d851c07c900..4fed004cbf6cdcf9c6001b9b26411d5d8a040fdf 100644 (file)
 #define HOST_BITS_PER_INT   (CHAR_BIT * SIZEOF_INT)
 #define HOST_BITS_PER_LONG  (CHAR_BIT * SIZEOF_LONG)
 
+/* If HAVE_LONG_LONG and SIZEOF_LONG_LONG aren't defined, but
+   GCC_VERSION >= 3000, assume this is the second or later stage of a
+   bootstrap, we do have long long, and it's 64 bits.  (This is
+   required by C99; we do have some ports that violate that assumption
+   but they're all cross-compile-only.)  Just in case, force a
+   constraint violation if that assumption is incorrect.  */
+#if !defined HAVE_LONG_LONG
+# if GCC_VERSION >= 3000
+#  define HAVE_LONG_LONG 1
+#  define SIZEOF_LONG_LONG 8
+extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1];
+# endif
+#endif
+
 #ifdef HAVE_LONG_LONG
 # define HOST_BITS_PER_LONGLONG (CHAR_BIT * SIZEOF_LONG_LONG)
-#else
+#endif
 #ifdef HAVE___INT64
-# define HOST_BITS_PER_LONGLONG (CHAR_BIT * SIZEOF___INT64)
-#else
-/* If we're here and we're GCC, assume this is stage 2+ of a bootstrap
-   and 'long long' has the width of the *target*'s long long.  */
-# if GCC_VERSION > 3000
-#  define HOST_BITS_PER_LONGLONG LONG_LONG_TYPE_SIZE
-# endif /* gcc */
+# define HOST_BITS_PER___INT64 (CHAR_BIT * SIZEOF___INT64)
 #endif
-#endif /* no long long */
 
-/* Find the largest host integer type and set its size and type.  */
+/* Set HOST_WIDE_INT.  This should be the widest efficient host
+   integer type.  It can be 32 or 64 bits, except that if we are
+   targeting a machine with 64-bit size_t then it has to be 64 bits.
 
-/* Use long long on the host if the target has a wider long type than
-   the host.  */
+   With a sane ABI, 'long' is the largest efficient host integer type.
+   Thus, we use that unless we have to use 'long long' or '__int64'
+   because we're targeting a 64-bit machine from a 32-bit host.  */
 
-#if ! defined HOST_BITS_PER_WIDE_INT \
-    && defined HOST_BITS_PER_LONGLONG \
-    && (HOST_BITS_PER_LONGLONG > HOST_BITS_PER_LONG) \
-    && (defined (LONG_LONG_MAX) || defined (LONGLONG_MAX) \
-        || defined (LLONG_MAX) || defined (__GNUC__))
-
-# ifdef MAX_LONG_TYPE_SIZE
-#  if MAX_LONG_TYPE_SIZE > HOST_BITS_PER_LONG
-#   define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONGLONG
-#   define HOST_WIDE_INT long long
-#  endif
-# else
-#  if LONG_TYPE_SIZE > HOST_BITS_PER_LONG
+#if HOST_BITS_PER_LONG >= 64 || !defined NEED_64BIT_HOST_WIDE_INT
+#   define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
+#   define HOST_WIDE_INT long
+#else
+# if HOST_BITS_PER_LONGLONG >= 64
 #   define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONGLONG
 #   define HOST_WIDE_INT long long
-#  endif
-# endif
-
-#endif
-
-#ifndef HOST_BITS_PER_WIDE_INT
-
-# if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
-#  define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
-#  define HOST_WIDE_INT long
 # else
-#  define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
-#  define HOST_WIDE_INT int
-# endif
-
-#endif /* ! HOST_BITS_PER_WIDE_INT */
-
-/* Provide defaults for the way to print a HOST_WIDE_INT
-   in various manners.  */
-
-#ifndef HOST_WIDE_INT_PRINT_DEC
-# if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-#  define HOST_WIDE_INT_PRINT_DEC "%d"
-#  define HOST_WIDE_INT_PRINT_DEC_C "%d"
-#  define HOST_WIDE_INT_PRINT_DEC_SPACE "% *d"
-# else
-#  if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-#   define HOST_WIDE_INT_PRINT_DEC "%ld"
-#   define HOST_WIDE_INT_PRINT_DEC_C "%ldL"
-#   define HOST_WIDE_INT_PRINT_DEC_SPACE "% *ld"
+#  if HOST_BITS_PER___INT64 >= 64
+#   define HOST_BITS_PER_WIDE_INT HOST_BITS_PER___INT64
+#   define HOST_WIDE_INT __int64
 #  else
-#   define HOST_WIDE_INT_PRINT_DEC "%lld"
-#   define HOST_WIDE_INT_PRINT_DEC_C "%lldLL"
-#   define HOST_WIDE_INT_PRINT_DEC_SPACE "% *lld"
+    #error "Unable to find a suitable type for HOST_WIDE_INT"
 #  endif
 # endif
-#endif /* ! HOST_WIDE_INT_PRINT_DEC */
+#endif
 
-#ifndef HOST_WIDE_INT_PRINT_UNSIGNED
-# if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-#  define HOST_WIDE_INT_PRINT_UNSIGNED "%u"
-#  define HOST_WIDE_INT_PRINT_UNSIGNED_SPACE "% *u"
-# else
-#  if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-#   define HOST_WIDE_INT_PRINT_UNSIGNED "%lu"
-#   define HOST_WIDE_INT_PRINT_UNSIGNED_SPACE "% *lu"
-#  else
-#   define HOST_WIDE_INT_PRINT_UNSIGNED "%llu"
-#   define HOST_WIDE_INT_PRINT_UNSIGNED_SPACE "% *llu"
-#  endif
-# endif
-#endif /* ! HOST_WIDE_INT_PRINT_UNSIGNED */
+/* Various printf format strings for HOST_WIDE_INT.  */
 
-#ifndef HOST_WIDE_INT_PRINT_HEX
-# if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-#  define HOST_WIDE_INT_PRINT_HEX "0x%x"
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+# define HOST_WIDE_INT_PRINT "l"
+# define HOST_WIDE_INT_PRINT_C "L"
+  /* 'long' might be 32 or 64 bits, and the number of leading zeroes
+     must be tweaked accordingly.  */
+# if HOST_BITS_PER_WIDE_INT == 64
+#  define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%lx%016lx"
 # else
-#  if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-#   define HOST_WIDE_INT_PRINT_HEX "0x%lx"
-#  else
-#   define HOST_WIDE_INT_PRINT_HEX "0x%llx"
-#  endif
+#  define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%lx%08lx"
 # endif
-#endif /* ! HOST_WIDE_INT_PRINT_HEX */
-
-#ifndef HOST_WIDE_INT_PRINT_DOUBLE_HEX
-# if HOST_BITS_PER_WIDE_INT == 64
-#  if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-#   define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%x%016x"
-#  else
-#   if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-#    define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%lx%016lx"
-#   else
-#    define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%llx%016llx"
-#   endif
-#  endif
+#else
+# define HOST_WIDE_INT_PRINT "ll"
+# define HOST_WIDE_INT_PRINT_C "LL"
+  /* We can assume that 'long long' is at least 64 bits.  */
+# define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%llx%016llx"
+#endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
+
+#define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
+#define HOST_WIDE_INT_PRINT_DEC_C HOST_WIDE_INT_PRINT_DEC HOST_WIDE_INT_PRINT_C
+#define HOST_WIDE_INT_PRINT_UNSIGNED "%" HOST_WIDE_INT_PRINT "u"
+#define HOST_WIDE_INT_PRINT_HEX "0x%" HOST_WIDE_INT_PRINT "x"
+
+/* Set HOST_WIDEST_INT.  This is a 64-bit type unless the compiler
+   in use has no 64-bit type at all; in that case it's 32 bits.  */
+
+#if HOST_BITS_PER_WIDE_INT >= 64 \
+    || (HOST_BITS_PER_LONGLONG < 64 && HOST_BITS_PER___INT64 < 64)
+# define HOST_WIDEST_INT                     HOST_WIDE_INT
+# define HOST_BITS_PER_WIDEST_INT            HOST_BITS_PER_WIDE_INT
+# define HOST_WIDEST_INT_PRINT_DEC           HOST_WIDE_INT_PRINT_DEC
+# define HOST_WIDEST_INT_PRINT_DEC_C         HOST_WIDE_INT_PRINT_DEC_C
+# define HOST_WIDEST_INT_PRINT_UNSIGNED              HOST_WIDE_INT_PRINT_UNSIGNED
+# define HOST_WIDEST_INT_PRINT_HEX           HOST_WIDE_INT_PRINT_HEX
+# define HOST_WIDEST_INT_PRINT_DOUBLE_HEX     HOST_WIDE_INT_PRINT_DOUBLE_HEX
+#else
+# if HOST_BITS_PER_LONGLONG >= 64
+#  define HOST_BITS_PER_WIDEST_INT           HOST_BITS_PER_LONGLONG
+#  define HOST_WIDEST_INT                    long long
 # else
-#  if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-#   define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%x%08x"
+#  if HOST_BITS_PER___INT64 >= 64
+#   define HOST_BITS_PER_WIDEST_INT          HOST_BITS_PER___INT64
+#   define HOST_WIDEST_INT                   __int64
 #  else
-#   if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-#    define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%lx%08lx"
-#   else
-#    define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%llx%08llx"
-#   endif
+    #error "This line should be impossible to reach"
 #  endif
 # endif
-#endif /* ! HOST_WIDE_INT_PRINT_DOUBLE_HEX */
-
-/* Find HOST_WIDEST_INT and set its bit size, type and print macros.
-   It will be the largest integer mode supported by the host which may
-   (or may not) be larger than HOST_WIDE_INT.  */
-
-#ifndef HOST_WIDEST_INT
-#if defined HOST_BITS_PER_LONGLONG \
-    && HOST_BITS_PER_LONGLONG > HOST_BITS_PER_LONG
-#   define HOST_BITS_PER_WIDEST_INT HOST_BITS_PER_LONGLONG
-#   define HOST_WIDEST_INT long long
-#   define HOST_WIDEST_INT_PRINT_DEC "%lld"
-#   define HOST_WIDEST_INT_PRINT_DEC_SPACE "% *lld"
-#   define HOST_WIDEST_INT_PRINT_UNSIGNED "%llu"
-#   define HOST_WIDEST_INT_PRINT_UNSIGNED_SPACE "% *llu"
-#   define HOST_WIDEST_INT_PRINT_HEX "0x%llx"
-#  else
-#   define HOST_BITS_PER_WIDEST_INT HOST_BITS_PER_LONG
-#   define HOST_WIDEST_INT long
-#   define HOST_WIDEST_INT_PRINT_DEC "%ld"
-#   define HOST_WIDEST_INT_PRINT_DEC_SPACE "% *ld"
-#   define HOST_WIDEST_INT_PRINT_UNSIGNED "%lu"
-#   define HOST_WIDEST_INT_PRINT_UNSIGNED_SPACE "% *lu"
-#   define HOST_WIDEST_INT_PRINT_HEX "0x%lx"
-# endif /* long long wider than long */
-#endif /* ! HOST_WIDEST_INT */
+# define HOST_WIDEST_INT_PRINT_DEC           "%lld"
+# define HOST_WIDEST_INT_PRINT_DEC_C         "%lldLL"
+# define HOST_WIDEST_INT_PRINT_UNSIGNED              "%llu"
+# define HOST_WIDEST_INT_PRINT_HEX           "0x%llx"
+# define HOST_WIDEST_INT_PRINT_DOUBLE_HEX     "0x%llx%016llx"
+#endif
 
 #endif /* ! GCC_HWINT_H */
diff --git a/support/cpp2/input.h b/support/cpp2/input.h
new file mode 100644 (file)
index 0000000..ff014f6
--- /dev/null
@@ -0,0 +1,63 @@
+/* Declarations for variables relating to reading the source file.
+   Used by parsers, lexical analyzers, and error message routines.
+   Copyright (C) 1993, 1997, 1998, 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef GCC_INPUT_H
+#define GCC_INPUT_H
+
+/* The data structure used to record a location in a translation unit.  */
+/* Long-term, we want to get rid of this and typedef fileline location_t.  */
+struct location_s GTY (())
+{
+  /* The name of the source file involved.  */
+  const char *file;
+
+  /* The line-location in the source file.  */
+  int line;
+};
+typedef struct location_s location_t;
+
+struct file_stack
+{
+  struct file_stack *next;
+  location_t location;
+};
+
+/* Top-level source file.  */
+extern const char *main_input_filename;
+
+extern location_t input_location;
+#define input_line (input_location.line)
+#define input_filename (input_location.file)
+
+/* Stack of currently pending input files.
+   The line member is not accurate for the innermost file on the stack.  */
+extern struct file_stack *input_file_stack;
+
+/* Stack of EXPR_WITH_FILE_LOCATION nested expressions.  */
+extern struct file_stack *expr_wfl_stack;
+
+/* Incremented on each change to input_file_stack.  */
+extern int input_file_stack_tick;
+
+extern void push_srcloc (const char *name, int line);
+extern void pop_srcloc (void);
+
+#endif
index 8a9b35a66fd97425e20dca39de9abdae0d92284e..80a945b45f8e0cea175757d3358c82dcb8e10a9a 100644 (file)
@@ -1,5 +1,5 @@
 /* intl.h - internationalization
-   Copyright 1998, 2001 Free Software Foundation, Inc.
+   Copyright 1998, 2001, 2003 Free Software Foundation, Inc.
 
    GCC is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 # define setlocale(category, locale) (locale)
 #endif
 
-#ifdef USE_INCLUDED_LIBINTL
-# include <intl/libgnuintl.h>
-#else
-# ifdef HAVE_LIBINTL_H
-#  include <libintl.h>
-# else
-#  undef ENABLE_NLS
-# endif
-#endif
-
 #ifdef ENABLE_NLS
-extern void gcc_init_libintl PARAMS ((void));
+#include <libintl.h>
+extern void gcc_init_libintl (void);
+extern size_t gcc_gettext_width (const char *);
 #else
 /* Stubs.  */
 # undef textdomain
@@ -48,6 +40,7 @@ extern void gcc_init_libintl PARAMS ((void));
 # undef gettext
 # define gettext(msgid) (msgid)
 # define gcc_init_libintl()    /* nothing */
+# define gcc_gettext_width(s) strlen(s)
 #endif
 
 #ifndef _
@@ -55,7 +48,7 @@ extern void gcc_init_libintl PARAMS ((void));
 #endif
 
 #ifndef N_
-# define N_(msgid) (msgid)
+# define N_(msgid) msgid
 #endif
 
 #endif /* intl.h */
diff --git a/support/cpp2/libiberty/getpwd.c b/support/cpp2/libiberty/getpwd.c
new file mode 100644 (file)
index 0000000..a783744
--- /dev/null
@@ -0,0 +1,132 @@
+/* getpwd.c - get the working directory */
+
+/*
+
+@deftypefn Supplemental char* getpwd (void)
+
+Returns the current working directory.  This implementation caches the
+result on the assumption that the process will not call @code{chdir}
+between calls to @code{getpwd}.
+
+@end deftypefn
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+/* Prototype these in case the system headers don't provide them. */
+extern char *getpwd ();
+extern char *getwd ();
+
+#include "libiberty.h"
+
+/* Virtually every UN*X system now in common use (except for pre-4.3-tahoe
+   BSD systems) now provides getcwd as called for by POSIX.  Allow for
+   the few exceptions to the general rule here.  */
+
+#if !defined(HAVE_GETCWD) && defined(HAVE_GETWD)
+#define getcwd(buf,len) getwd(buf)
+#endif
+
+#ifdef MAXPATHLEN
+#define GUESSPATHLEN (MAXPATHLEN + 1)
+#else
+#define GUESSPATHLEN 100
+#endif
+
+#if !(defined (VMS) || (defined(_WIN32) && !defined(__CYGWIN__)))
+
+/* Get the working directory.  Use the PWD environment variable if it's
+   set correctly, since this is faster and gives more uniform answers
+   to the user.  Yield the working directory if successful; otherwise,
+   yield 0 and set errno.  */
+
+char *
+getpwd ()
+{
+  static char *pwd;
+  static int failure_errno;
+
+  char *p = pwd;
+  size_t s;
+  struct stat dotstat, pwdstat;
+
+  if (!p && !(errno = failure_errno))
+    {
+      if (! ((p = getenv ("PWD")) != 0
+            && *p == '/'
+            && stat (p, &pwdstat) == 0
+            && stat (".", &dotstat) == 0
+            && dotstat.st_ino == pwdstat.st_ino
+            && dotstat.st_dev == pwdstat.st_dev))
+
+       /* The shortcut didn't work.  Try the slow, ``sure'' way.  */
+       for (s = GUESSPATHLEN;  ! getcwd (p = xmalloc (s), s);  s *= 2)
+         {
+           int e = errno;
+           free (p);
+#ifdef ERANGE
+           if (e != ERANGE)
+#endif
+             {
+               errno = failure_errno = e;
+               p = 0;
+               break;
+             }
+         }
+
+      /* Cache the result.  This assumes that the program does
+        not invoke chdir between calls to getpwd.  */
+      pwd = p;
+    }
+  return p;
+}
+
+#else  /* VMS || _WIN32 && !__CYGWIN__ */
+
+#if defined(_WIN32)
+#include <direct.h>
+#define getcwd  _getcwd
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 255
+#endif
+
+char *
+getpwd ()
+{
+  static char *pwd = 0;
+
+  if (!pwd)
+    pwd = getcwd (xmalloc (MAXPATHLEN + 1), MAXPATHLEN + 1
+#ifdef VMS
+                 , 0
+#endif
+                 );
+  return pwd;
+}
+
+#endif /* VMS || _WIN32 && !__CYGWIN__ */
diff --git a/support/cpp2/libiberty/vasprintf.c b/support/cpp2/libiberty/vasprintf.c
new file mode 100644 (file)
index 0000000..b6cb94e
--- /dev/null
@@ -0,0 +1,196 @@
+/* Like vsprintf but provides a pointer to malloc'd storage, which must
+   be freed by the caller.
+   Copyright (C) 1994, 2003 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <ansidecl.h>
+#include <stdarg.h>
+#if !defined (va_copy) && defined (__va_copy)
+# define va_copy(d,s)  __va_copy((d),(s))
+#endif
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern unsigned long strtoul ();
+extern PTR malloc ();
+#endif
+#include "libiberty.h"
+
+#ifdef TEST
+int global_total_width;
+#endif
+
+/*
+
+@deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args})
+
+Like @code{vsprintf}, but instead of passing a pointer to a buffer,
+you pass a pointer to a pointer.  This function will compute the size
+of the buffer needed, allocate memory with @code{malloc}, and store a
+pointer to the allocated memory in @code{*@var{resptr}}.  The value
+returned is the same as @code{vsprintf} would return.  If memory could
+not be allocated, minus one is returned and @code{NULL} is stored in
+@code{*@var{resptr}}.
+
+@end deftypefn
+
+*/
+
+static int int_vasprintf (char **, const char *, va_list);
+
+static int
+int_vasprintf (char **result, const char *format, va_list args)
+{
+  const char *p = format;
+  /* Add one to make sure that it is never zero, which might cause malloc
+     to return NULL.  */
+  int total_width = strlen (format) + 1;
+  va_list ap;
+
+#ifdef va_copy
+  va_copy (ap, args);
+#else
+  memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list));
+#endif
+
+  while (*p != '\0')
+    {
+      if (*p++ == '%')
+       {
+         while (strchr ("-+ #0", *p))
+           ++p;
+         if (*p == '*')
+           {
+             ++p;
+             total_width += abs (va_arg (ap, int));
+           }
+         else
+           total_width += strtoul (p, (char **) &p, 10);
+         if (*p == '.')
+           {
+             ++p;
+             if (*p == '*')
+               {
+                 ++p;
+                 total_width += abs (va_arg (ap, int));
+               }
+             else
+             total_width += strtoul (p, (char **) &p, 10);
+           }
+         while (strchr ("hlL", *p))
+           ++p;
+         /* Should be big enough for any format specifier except %s and floats.  */
+         total_width += 30;
+         switch (*p)
+           {
+           case 'd':
+           case 'i':
+           case 'o':
+           case 'u':
+           case 'x':
+           case 'X':
+           case 'c':
+             (void) va_arg (ap, int);
+             break;
+           case 'f':
+           case 'e':
+           case 'E':
+           case 'g':
+           case 'G':
+             (void) va_arg (ap, double);
+             /* Since an ieee double can have an exponent of 307, we'll
+                make the buffer wide enough to cover the gross case. */
+             total_width += 307;
+             break;
+           case 's':
+             total_width += strlen (va_arg (ap, char *));
+             break;
+           case 'p':
+           case 'n':
+             (void) va_arg (ap, char *);
+             break;
+           }
+         p++;
+       }
+    }
+#ifdef va_copy
+  va_end (ap);
+#endif
+#ifdef TEST
+  global_total_width = total_width;
+#endif
+  *result = (char *) malloc (total_width);
+  if (*result != NULL)
+    return vsprintf (*result, format, args);
+  else
+    return -1;
+}
+
+int
+vasprintf (char **result, const char *format,
+#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
+           _BSD_VA_LIST_ args)
+#else
+           va_list args)
+#endif
+{
+  return int_vasprintf (result, format, args);
+}
+
+#ifdef TEST
+static void ATTRIBUTE_PRINTF_1
+checkit (const char *format, ...)
+{
+  char *result;
+  VA_OPEN (args, format);
+  VA_FIXEDARG (args, const char *, format);
+  vasprintf (&result, format, args);
+  VA_CLOSE (args);
+
+  if (strlen (result) < (size_t) global_total_width)
+    printf ("PASS: ");
+  else
+    printf ("FAIL: ");
+  printf ("%d %s\n", global_total_width, result);
+
+  free (result);
+}
+
+extern int main (void);
+
+int
+main (void)
+{
+  checkit ("%d", 0x12345678);
+  checkit ("%200d", 5);
+  checkit ("%.300d", 6);
+  checkit ("%100.150d", 7);
+  checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
+777777777777777777333333333333366666666666622222222222777777777777733333");
+  checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
+
+  return 0;
+}
+#endif /* TEST */
diff --git a/support/cpp2/libiberty/xmemdup.c b/support/cpp2/libiberty/xmemdup.c
new file mode 100644 (file)
index 0000000..d483116
--- /dev/null
@@ -0,0 +1,38 @@
+/* xmemdup.c -- Duplicate a memory buffer, using xcalloc.
+   This trivial function is in the public domain.
+   Jeff Garzik, September 1999.  */
+
+/*
+
+@deftypefn Replacement void* xmemdup (void *@var{input}, size_t @var{copy_size}, size_t @var{alloc_size})
+
+Duplicates a region of memory without fail.  First, @var{alloc_size} bytes
+are allocated, then @var{copy_size} bytes from @var{input} are copied into
+it, and the new memory is returned.  If fewer bytes are copied than were
+allocated, the remaining memory is zeroed.
+
+@end deftypefn
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "ansidecl.h"
+#include "libiberty.h"
+
+#include <sys/types.h> /* For size_t. */
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif
+
+PTR
+xmemdup (const PTR input, size_t copy_size, size_t alloc_size)
+{
+  PTR output = xcalloc (1, alloc_size);
+  return (PTR) memcpy (output, input, copy_size);
+}
index a0f3ee50bc0fb640e2e9264134d529fe8194a23f..521c4e5c843e76ab9f6cf7b33f9a4cc2a8e405b9 100644 (file)
@@ -1,5 +1,5 @@
 /* Map logical line numbers to (source file, line number) pairs.
-   Copyright (C) 2001
+   Copyright (C) 2001, 2003
    Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify it
@@ -25,14 +25,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #include "line-map.h"
 #include "intl.h"
 
-static void trace_include
-  PARAMS ((const struct line_maps *, const struct line_map *));
+static void trace_include (const struct line_maps *, const struct line_map *);
 
 /* Initialize a line map set.  */
 
 void
-init_line_maps (set)
-     struct line_maps *set;
+linemap_init (struct line_maps *set)
 {
   set->maps = 0;
   set->allocated = 0;
@@ -45,8 +43,7 @@ init_line_maps (set)
 /* Free a line map set.  */
 
 void
-free_line_maps (set)
-     struct line_maps *set;
+linemap_free (struct line_maps *set)
 {
   if (set->maps)
     {
@@ -64,20 +61,22 @@ free_line_maps (set)
 }
 
 /* Add a mapping of logical source line to physical source file and
-   line number.  Ther text pointed to by TO_FILE must have a lifetime
-   at least as long as the final call to lookup_line ().
+   line number.
+
+   The text pointed to by TO_FILE must have a lifetime
+   at least as long as the final call to lookup_line ().  An empty
+   TO_FILE means standard input.  If reason is LC_LEAVE, and
+   TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their
+   natural values considering the file we are returning to.
 
    FROM_LINE should be monotonic increasing across calls to this
-   function.  */
+   function.  A call to this function can relocate the previous set of
+   maps, so any stored line_map pointers should not be used.  */
 
 const struct line_map *
-add_line_map (set, reason, sysp, from_line, to_file, to_line)
-     struct line_maps *set;
-     enum lc_reason reason;
-     unsigned int sysp;
-     unsigned int from_line;
-     const char *to_file;
-     unsigned int to_line;
+linemap_add (struct line_maps *set, enum lc_reason reason,
+            unsigned int sysp, source_location from_line,
+            const char *to_file, unsigned int to_line)
 {
   struct line_map *map;
 
@@ -87,12 +86,14 @@ add_line_map (set, reason, sysp, from_line, to_file, to_line)
   if (set->used == set->allocated)
     {
       set->allocated = 2 * set->allocated + 256;
-      set->maps = (struct line_map *)
-       xrealloc (set->maps, set->allocated * sizeof (struct line_map));
+      set->maps = xrealloc (set->maps, set->allocated * sizeof (struct line_map));
     }
 
   map = &set->maps[set->used++];
 
+  if (to_file && *to_file == '\0')
+    to_file = "<stdin>";
+
   /* If we don't keep our line maps consistent, we can easily
      segfault.  Don't rely on the client to do it for us.  */
   if (set->depth == 0)
@@ -104,9 +105,15 @@ add_line_map (set, reason, sysp, from_line, to_file, to_line)
 
       if (MAIN_FILE_P (map - 1))
        {
+         if (to_file == NULL)
+           {
+             set->depth--;
+             set->used--;
+             return NULL;
+           }
          error = true;
-         reason = LC_RENAME;
-         from = map - 1;
+          reason = LC_RENAME;
+          from = map - 1;
        }
       else
        {
@@ -137,8 +144,8 @@ add_line_map (set, reason, sysp, from_line, to_file, to_line)
 
   if (reason == LC_ENTER)
     {
+      map->included_from = set->depth == 0 ? -1 : (int) (set->used - 2);
       set->depth++;
-      map->included_from = set->used - 2;
       if (set->trace_includes)
        trace_include (set, map);
     }
@@ -159,9 +166,7 @@ add_line_map (set, reason, sysp, from_line, to_file, to_line)
    the list is sorted and we can use a binary search.  */
 
 const struct line_map *
-lookup_line (set, line)
-     struct line_maps *set;
-     unsigned int line;
+linemap_lookup (struct line_maps *set, source_location line)
 {
   unsigned int md, mn = 0, mx = set->used;
 
@@ -185,9 +190,8 @@ lookup_line (set, line)
    the most recently listed stack is the same as the current one.  */
 
 void
-print_containing_files (set, map)
-     struct line_maps *set;
-     const struct line_map *map;
+linemap_print_containing_files (struct line_maps *set,
+                               const struct line_map *map)
 {
   if (MAIN_FILE_P (map) || set->last_listed == map->included_from)
     return;
@@ -223,9 +227,7 @@ print_containing_files (set, map)
 /* Print an include trace, for e.g. the -H option of the preprocessor.  */
 
 static void
-trace_include (set, map)
-     const struct line_maps *set;
-     const struct line_map *map;
+trace_include (const struct line_maps *set, const struct line_map *map)
 {
   unsigned int i = set->depth;
 
index 60201887f491fd9826c5e4733ed909e22a81d0ce..c57f51a66245ed7b9ced001712abbf234f123829 100644 (file)
@@ -1,5 +1,5 @@
 /* Map logical line numbers to (source file, line number) pairs.
-   Copyright (C) 2001
+   Copyright (C) 2001, 2003
    Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify it
@@ -30,6 +30,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    (e.g. a #line directive in C).  */
 enum lc_reason {LC_ENTER = 0, LC_LEAVE, LC_RENAME};
 
+/* A logical line number, i,e, an "index" into a line_map.  */
+/* Long-term, we want to use this to replace struct location_s (in input.h),
+   and effectively typedef source_location location_t.  */
+typedef unsigned int source_location;
+typedef source_location fileline; /* deprecated name */
+
 /* The logical line FROM_LINE maps to physical source file TO_FILE at
    line TO_LINE, and subsequently one-to-one until the next line_map
    structure in the set.  INCLUDED_FROM is an index into the set that
@@ -42,7 +48,7 @@ struct line_map
 {
   const char *to_file;
   unsigned int to_line;
-  unsigned int from_line;
+  source_location from_line;
   int included_from;
   ENUM_BITFIELD (lc_reason) reason : CHAR_BIT;
   unsigned char sysp;
@@ -68,36 +74,37 @@ struct line_maps
 };
 
 /* Initialize a line map set.  */
-extern void init_line_maps
-  PARAMS ((struct line_maps *));
+extern void linemap_init (struct line_maps *);
 
 /* Free a line map set.  */
-extern void free_line_maps
-  PARAMS ((struct line_maps *));
+extern void linemap_free (struct line_maps *);
 
 /* Add a mapping of logical source line to physical source file and
-   line number.  The text pointed to by TO_FILE must have a lifetime
-   at least as long as the line maps.  If reason is LC_LEAVE, and
+   line number.
+
+   The text pointed to by TO_FILE must have a lifetime
+   at least as long as the final call to lookup_line ().  An empty
+   TO_FILE means standard input.  If reason is LC_LEAVE, and
    TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their
    natural values considering the file we are returning to.
 
    FROM_LINE should be monotonic increasing across calls to this
    function.  A call to this function can relocate the previous set of
    maps, so any stored line_map pointers should not be used.  */
-extern const struct line_map *add_line_map
-  PARAMS ((struct line_maps *, enum lc_reason, unsigned int sysp,
-          unsigned int from_line, const char *to_file, unsigned int to_line));
+extern const struct line_map *linemap_add
+  (struct line_maps *, enum lc_reason, unsigned int sysp,
+   source_location from_line, const char *to_file, unsigned int to_line);
 
 /* Given a logical line, returns the map from which the corresponding
    (source file, line) pair can be deduced.  */
-extern const struct line_map *lookup_line
-  PARAMS ((struct line_maps *, unsigned int));
+extern const struct line_map *linemap_lookup
+  (struct line_maps *, source_location);
 
 /* Print the file names and line numbers of the #include commands
    which led to the map MAP, if any, to stderr.  Nothing is output if
    the most recently listed stack is the same as the current one.  */
-extern void print_containing_files
-  PARAMS ((struct line_maps *, const struct line_map *));
+extern void linemap_print_containing_files (struct line_maps *,
+                                           const struct line_map *);
 
 /* Converts a map and logical line to source line.  */
 #define SOURCE_LINE(MAP, LINE) ((LINE) + (MAP)->to_line - (MAP)->from_line)
index d533b889605b20227ee73fc5485b623d464ccea8..d50d2bf7dc3551d66e9f858781fe7694258f1442 100644 (file)
@@ -1,5 +1,5 @@
 /* Dependency generator for Makefile fragments.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
    Contributed by Zack Weinberg, Mar 2000
 
 This program is free software; you can redistribute it and/or modify it
@@ -39,7 +39,7 @@ struct deps
   unsigned int deps_size;
 };
 
-static const char *munge       PARAMS ((const char *));
+static const char *munge (const char *);
 
 /* Given a filename, quote characters in that filename which are
    significant to Make.  Note that it's not possible to quote all such
@@ -47,10 +47,9 @@ static const char *munge     PARAMS ((const char *));
    not properly handled.  It isn't possible to get this right in any
    current version of Make.  (??? Still true?  Old comment referred to
    3.76.1.)  */
-   
+
 static const char *
-munge (filename)
-     const char *filename;
+munge (const char *filename)
 {
   int len;
   const char *p, *q;
@@ -111,9 +110,9 @@ munge (filename)
 /* Public routines.  */
 
 struct deps *
-deps_init ()
+deps_init (void)
 {
-  struct deps *d = (struct deps *) xmalloc (sizeof (struct deps));
+  struct deps *d = xmalloc (sizeof (struct deps));
 
   /* Allocate space for the vectors only if we need it.  */
 
@@ -129,22 +128,21 @@ deps_init ()
 }
 
 void
-deps_free (d)
-     struct deps *d;
+deps_free (struct deps *d)
 {
   unsigned int i;
 
   if (d->targetv)
     {
       for (i = 0; i < d->ntargets; i++)
-       free ((PTR) d->targetv[i]);
+       free ((void *) d->targetv[i]);
       free (d->targetv);
     }
 
   if (d->depv)
     {
       for (i = 0; i < d->ndeps; i++)
-       free ((PTR) d->depv[i]);
+       free ((void *) d->depv[i]);
       free (d->depv);
     }
 
@@ -154,15 +152,12 @@ deps_free (d)
 /* Adds a target T.  We make a copy, so it need not be a permanent
    string.  QUOTE is true if the string should be quoted.  */
 void
-deps_add_target (d, t, quote)
-     struct deps *d;
-     const char *t;
-     int quote;
+deps_add_target (struct deps *d, const char *t, int quote)
 {
   if (d->ntargets == d->targets_size)
     {
       d->targets_size = d->targets_size * 2 + 4;
-      d->targetv = (const char **) xrealloc (d->targetv,
+      d->targetv = xrealloc (d->targetv,
                             d->targets_size * sizeof (const char *));
     }
 
@@ -178,11 +173,9 @@ deps_add_target (d, t, quote)
    string as the default target in interpreted as stdin.  The string
    is quoted for MAKE.  */
 void
-deps_add_default_target (pfile, tgt)
-     cpp_reader *pfile;
-     const char *tgt;
+deps_add_default_target (cpp_reader *pfile, const char *tgt)
 {
-   struct deps *d = pfile->deps;
+  struct deps *d = pfile->deps;
 
   /* Only if we have no targets.  */
   if (d->ntargets)
@@ -215,37 +208,31 @@ deps_add_default_target (pfile, tgt)
       o = (char *) alloca (strlen (start) + strlen (obj_ext) + 1);
 
       strcpy (o, start);
-      
+
       suffix = strrchr (o, '.');
       if (!suffix)
         suffix = o + strlen (o);
       strcpy (suffix, obj_ext);
-      
+
       deps_add_target (d, o, 1);
     }
 }
 
 void
-deps_add_dep (d, t)
-     struct deps *d;
-     const char *t;
+deps_add_dep (struct deps *d, const char *t)
 {
   t = munge (t);  /* Also makes permanent copy.  */
 
   if (d->ndeps == d->deps_size)
     {
       d->deps_size = d->deps_size * 2 + 8;
-      d->depv = (const char **)
-       xrealloc (d->depv, d->deps_size * sizeof (const char *));
+      d->depv = xrealloc (d->depv, d->deps_size * sizeof (const char *));
     }
   d->depv[d->ndeps++] = t;
 }
 
 void
-deps_write (d, fp, colmax)
-     const struct deps *d;
-     FILE *fp;
-     unsigned int colmax;
+deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
 {
   unsigned int size, i, column;
 
@@ -292,11 +279,9 @@ deps_write (d, fp, colmax)
     }
   putc ('\n', fp);
 }
-  
+
 void
-deps_phony_targets (d, fp)
-     const struct deps *d;
-     FILE *fp;
+deps_phony_targets (const struct deps *d, FILE *fp)
 {
   unsigned int i;
 
@@ -308,3 +293,72 @@ deps_phony_targets (d, fp)
       putc ('\n', fp);
     }
 }
+
+/* Write out a deps buffer to a file, in a form that can be read back
+   with deps_restore.  Returns nonzero on error, in which case the
+   error number will be in errno.  */
+
+int
+deps_save (struct deps *deps, FILE *f)
+{
+  unsigned int i;
+
+  /* The cppreader structure contains makefile dependences.  Write out this
+     structure.  */
+
+  /* The number of dependences.  */
+  if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
+      return -1;
+  /* The length of each dependence followed by the string.  */
+  for (i = 0; i < deps->ndeps; i++)
+    {
+      size_t num_to_write = strlen (deps->depv[i]);
+      if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
+          return -1;
+      if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
+          return -1;
+    }
+
+  return 0;
+}
+
+/* Read back dependency information written with deps_save into
+   the deps buffer.  The third argument may be NULL, in which case
+   the dependency information is just skipped, or it may be a filename,
+   in which case that filename is skipped.  */
+
+int
+deps_restore (struct deps *deps, FILE *fd, const char *self)
+{
+  unsigned int i, count;
+  size_t num_to_read;
+  size_t buf_size = 512;
+  char *buf = xmalloc (buf_size);
+
+  /* Number of dependences.  */
+  if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
+    return -1;
+
+  /* The length of each dependence string, followed by the string.  */
+  for (i = 0; i < count; i++)
+    {
+      /* Read in # bytes in string.  */
+      if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
+       return -1;
+      if (buf_size < num_to_read + 1)
+       {
+         buf_size = num_to_read + 1 + 127;
+         buf = xrealloc (buf, buf_size);
+       }
+      if (fread (buf, 1, num_to_read, fd) != num_to_read)
+       return -1;
+      buf[num_to_read] = '\0';
+
+      /* Generate makefile dependencies from .pch if -nopch-deps.  */
+      if (self != NULL && strcmp (buf, self) != 0)
+        deps_add_dep (deps, buf);
+    }
+
+  free (buf);
+  return 0;
+}
index ceee017b3065b0319eef2fb652bcea9afa597cff..db2e00e0b1682cc029e284a92bba05537f06774d 100644 (file)
@@ -1,5 +1,5 @@
 /* Dependency generator for Makefile fragments.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
    Contributed by Zack Weinberg, Mar 2000
 
 This program is free software; you can redistribute it and/or modify it
@@ -30,34 +30,44 @@ struct deps;
 struct cpp_reader;
 
 /* Create a deps buffer.  */
-extern struct deps *deps_init  PARAMS ((void));
+extern struct deps *deps_init (void);
 
 /* Destroy a deps buffer.  */
-extern void deps_free          PARAMS ((struct deps *));
+extern void deps_free (struct deps *);
 
 /* Add a target (appears on left side of the colon) to the deps list.  Takes
    a boolean indicating whether to quote the target for MAKE.  */
-extern void deps_add_target    PARAMS ((struct deps *, const char *, int));
+extern void deps_add_target (struct deps *, const char *, int);
 
 /* Sets the default target if none has been given already.  An empty
-   string as the default target in interpreted as stdin.  */
-extern void deps_add_default_target PARAMS ((struct cpp_reader *, const char *));
+   string as the default target is interpreted as stdin.  */
+extern void deps_add_default_target (struct cpp_reader *, const char *);
 
 /* Add a dependency (appears on the right side of the colon) to the
    deps list.  Dependencies will be printed in the order that they
    were entered with this function.  By convention, the first
    dependency entered should be the primary source file.  */
-extern void deps_add_dep       PARAMS ((struct deps *, const char *));
+extern void deps_add_dep (struct deps *, const char *);
 
 /* Write out a deps buffer to a specified file.  The third argument
    is the number of columns to word-wrap at (0 means don't wrap).  */
-extern void deps_write         PARAMS ((const struct deps *, FILE *,
-                                        unsigned int));
+extern void deps_write (const struct deps *, FILE *, unsigned int);
+
+/* Write out a deps buffer to a file, in a form that can be read back
+   with deps_restore.  Returns nonzero on error, in which case the
+   error number will be in errno.  */
+extern int deps_save (struct deps *, FILE *);
+
+/* Read back dependency information written with deps_save into
+   the deps buffer.  The third argument may be NULL, in which case
+   the dependency information is just skipped, or it may be a filename,
+   in which case that filename is skipped.  */
+extern int deps_restore (struct deps *, FILE *, const char *);
 
 /* For each dependency *except the first*, emit a dummy rule for that
    file, causing it to depend on nothing.  This is used to work around
    the intermediate-file deletion misfeature in Make, in some
    automatic dependency schemes.  */
-extern void deps_phony_targets PARAMS ((const struct deps *, FILE *));
+extern void deps_phony_targets (const struct deps *, FILE *);
 
 #endif /* ! GCC_MKDEPS_H */
diff --git a/support/cpp2/move-if-change b/support/cpp2/move-if-change
new file mode 100644 (file)
index 0000000..28fcfbb
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh\r
+# Like mv $1 $2, but if the files are the same, just delete $1.\r
+# Status is 0 if $2 is changed, 1 otherwise.\r
+if\r
+test -r $2\r
+then\r
+if\r
+cmp -s $1 $2\r
+then\r
+echo $2 is unchanged\r
+rm -f $1\r
+else\r
+mv -f $1 $2\r
+fi\r
+else\r
+mv -f $1 $2\r
+fi\r
diff --git a/support/cpp2/opts.c b/support/cpp2/opts.c
new file mode 100644 (file)
index 0000000..5323a32
--- /dev/null
@@ -0,0 +1,608 @@
+/* Command line option handling.
+   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Neil Booth.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "intl.h"
+#include "opts.h"
+#include "options.h"
+#include "diagnostic.h"
+
+/* True if we should exit after parsing options.  */
+bool exit_after_options;
+
+/* Don't print warning messages.  -w.  */
+bool inhibit_warnings;
+
+/* Treat warnings as errors.  -Werror.  */
+bool warnings_are_errors;
+
+/* Don't suppress warnings from system headers.  -Wsystem-headers.  */
+bool warn_system_headers;
+
+/* Columns of --help display.  */
+static unsigned int columns = 80;
+
+/* What to print when a switch has no documentation.  */
+static const char undocumented_msg[] = N_("This switch lacks documentation");
+
+/* Input file names.  */
+const char **in_fnames;
+unsigned num_in_fnames;
+
+static size_t find_opt (const char *, int);
+static int common_handle_option (size_t scode, const char *arg, int value);
+static unsigned int handle_option (const char **argv, unsigned int lang_mask);
+static char *write_langs (unsigned int lang_mask);
+static void complain_wrong_lang (const char *, const struct cl_option *,
+                                unsigned int lang_mask);
+static void handle_options (unsigned int, const char **, unsigned int);
+static void wrap_help (const char *help, const char *item, unsigned int);
+static void print_help (void);
+static void print_filtered_help (unsigned int flag);
+static unsigned int print_switch (const char *text, unsigned int indent);
+
+/* Perform a binary search to find which option the command-line INPUT
+   matches.  Returns its index in the option array, and N_OPTS
+   (cl_options_count) on failure.
+
+   This routine is quite subtle.  A normal binary search is not good
+   enough because some options can be suffixed with an argument, and
+   multiple sub-matches can occur, e.g. input of "-pedantic" matching
+   the initial substring of "-pedantic-errors".
+
+   A more complicated example is -gstabs.  It should match "-g" with
+   an argument of "stabs".  Suppose, however, that the number and list
+   of switches are such that the binary search tests "-gen-decls"
+   before having tested "-g".  This doesn't match, and as "-gen-decls"
+   is less than "-gstabs", it will become the lower bound of the
+   binary search range, and "-g" will never be seen.  To resolve this
+   issue, opts.sh makes "-gen-decls" point, via the back_chain member,
+   to "-g" so that failed searches that end between "-gen-decls" and
+   the lexicographically subsequent switch know to go back and see if
+   "-g" causes a match (which it does in this example).
+
+   This search is done in such a way that the longest match for the
+   front end in question wins.  If there is no match for the current
+   front end, the longest match for a different front end is returned
+   (or N_OPTS if none) and the caller emits an error message.  */
+static size_t
+find_opt (const char *input, int lang_mask)
+{
+  size_t mn, mx, md, opt_len;
+  size_t match_wrong_lang;
+  int comp;
+
+  mn = 0;
+  mx = cl_options_count;
+
+  /* Find mn such this lexicographical inequality holds:
+     cl_options[mn] <= input < cl_options[mn + 1].  */
+  while (mx - mn > 1)
+    {
+      md = (mn + mx) / 2;
+      opt_len = cl_options[md].opt_len;
+      comp = strncmp (input, cl_options[md].opt_text + 1, opt_len);
+
+      if (comp < 0)
+       mx = md;
+      else
+       mn = md;
+    }
+
+  /* This is the switch that is the best match but for a different
+     front end, or cl_options_count if there is no match at all.  */
+  match_wrong_lang = cl_options_count;
+
+  /* Backtrace the chain of possible matches, returning the longest
+     one, if any, that fits best.  With current GCC switches, this
+     loop executes at most twice.  */
+  do
+    {
+      const struct cl_option *opt = &cl_options[mn];
+
+      /* Is this switch a prefix of the input?  */
+      if (!strncmp (input, opt->opt_text + 1, opt->opt_len))
+       {
+         /* If language is OK, and the match is exact or the switch
+            takes a joined argument, return it.  */
+         if ((opt->flags & lang_mask)
+             && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED)))
+           return mn;
+
+         /* If we haven't remembered a prior match, remember this
+            one.  Any prior match is necessarily better.  */
+         if (match_wrong_lang == cl_options_count)
+           match_wrong_lang = mn;
+       }
+
+      /* Try the next possibility.  This is cl_options_count if there
+        are no more.  */
+      mn = opt->back_chain;
+    }
+  while (mn != cl_options_count);
+
+  /* Return the best wrong match, or cl_options_count if none.  */
+  return match_wrong_lang;
+}
+
+/* If ARG is a non-negative integer made up solely of digits, return its
+   value, otherwise return -1.  */
+static int
+integral_argument (const char *arg)
+{
+  const char *p = arg;
+
+  while (*p && ISDIGIT (*p))
+    p++;
+
+  if (*p == '\0')
+    return atoi (arg);
+
+  return -1;
+}
+
+/* Return a malloced slash-separated list of languages in MASK.  */
+static char *
+write_langs (unsigned int mask)
+{
+  unsigned int n = 0, len = 0;
+  const char *lang_name;
+  char *result;
+
+  for (n = 0; (lang_name = lang_names[n]) != 0; n++)
+    if (mask & (1U << n))
+      len += strlen (lang_name) + 1;
+
+  result = xmalloc (len);
+  len = 0;
+  for (n = 0; (lang_name = lang_names[n]) != 0; n++)
+    if (mask & (1U << n))
+      {
+       if (len)
+         result[len++] = '/';
+       strcpy (result + len, lang_name);
+       len += strlen (lang_name);
+      }
+
+  result[len] = 0;
+
+  return result;
+}
+
+/* Complain that switch OPT_INDEX does not apply to this front end.  */
+static void
+complain_wrong_lang (const char *text, const struct cl_option *option,
+                    unsigned int lang_mask)
+{
+  char *ok_langs, *bad_lang;
+
+  ok_langs = write_langs (option->flags);
+  bad_lang = write_langs (lang_mask);
+
+  /* Eventually this should become a hard error IMO.  */
+  warning ("command line option \"%s\" is valid for %s but not for %s",
+          text, ok_langs, bad_lang);
+
+  free (ok_langs);
+  free (bad_lang);
+}
+
+/* Handle the switch beginning at ARGV for the language indicated by
+   LANG_MASK.  Returns the number of switches consumed.  */
+static unsigned int
+handle_option (const char **argv, unsigned int lang_mask)
+{
+  size_t opt_index;
+  const char *opt, *arg = 0;
+  char *dup = 0;
+  int value = 1;
+  unsigned int result = 0;
+  const struct cl_option *option;
+
+  opt = argv[0];
+
+  /* Drop the "no-" from negative switches.  */
+  if ((opt[1] == 'W' || opt[1] == 'f')
+      && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
+    {
+      size_t len = strlen (opt) - 3;
+
+      dup = xmalloc (len + 1);
+      dup[0] = '-';
+      dup[1] = opt[1];
+      memcpy (dup + 2, opt + 5, len - 2 + 1);
+      opt = dup;
+      value = 0;
+    }
+
+  opt_index = find_opt (opt + 1, lang_mask | CL_COMMON);
+  if (opt_index == cl_options_count)
+    goto done;
+
+  option = &cl_options[opt_index];
+
+  /* Reject negative form of switches that don't take negatives as
+     unrecognized.  */
+  if (!value && (option->flags & CL_REJECT_NEGATIVE))
+    goto done;
+
+  /* We've recognized this switch.  */
+  result = 1;
+
+  /* Sort out any argument the switch takes.  */
+  if (option->flags & CL_JOINED)
+    {
+      /* Have arg point to the original switch.  This is because
+        some code, such as disable_builtin_function, expects its
+        argument to be persistent until the program exits.  */
+      arg = argv[0] + cl_options[opt_index].opt_len + 1;
+      if (!value)
+       arg += strlen ("no-");
+
+      if (*arg == '\0' && !(option->flags & CL_MISSING_OK))
+       {
+         if (option->flags & CL_SEPARATE)
+           {
+             arg = argv[1];
+             result = 2;
+           }
+         else
+           /* Missing argument.  */
+           arg = NULL;
+       }
+    }
+  else if (option->flags & CL_SEPARATE)
+    {
+      arg = argv[1];
+      result = 2;
+    }
+
+  /* Now we've swallowed any potential argument, complain if this
+     is a switch for a different front end.  */
+  if (!(option->flags & (lang_mask | CL_COMMON)))
+    {
+      complain_wrong_lang (argv[0], option, lang_mask);
+      goto done;
+    }
+
+  if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE)))
+    {
+      if (!(*lang_hooks.missing_argument) (opt, opt_index))
+       error ("missing argument to \"%s\"", opt);
+      goto done;
+    }
+
+  /* If the switch takes an integer, convert it.  */
+  if (arg && (option->flags & CL_UINTEGER))
+    {
+      value = integral_argument (arg);
+      if (value == -1)
+       {
+         error ("argument to \"%s\" should be a non-negative integer",
+                option->opt_text);
+         goto done;
+       }
+    }
+
+  if (option->flags & lang_mask)
+    if ((*lang_hooks.handle_option) (opt_index, arg, value) == 0)
+      result = 0;
+
+  if (result && (option->flags & CL_COMMON))
+    if (common_handle_option (opt_index, arg, value) == 0)
+      result = 0;
+
+ done:
+  if (dup)
+    free (dup);
+  return result;
+}
+
+/* Decode and handle the vector of command line options.  LANG_MASK
+   contains has a single bit set representing the current
+   language.  */
+static void
+handle_options (unsigned int argc, const char **argv, unsigned int lang_mask)
+{
+  unsigned int n, i;
+
+  for (i = 1; i < argc; i += n)
+    {
+      const char *opt = argv[i];
+
+      /* Interpret "-" or a non-switch as a file name.  */
+      if (opt[0] != '-' || opt[1] == '\0')
+       {
+         if (main_input_filename == NULL)
+           main_input_filename = opt;
+         add_input_filename (opt);
+         n = 1;
+         continue;
+       }
+
+      n = handle_option (argv + i, lang_mask);
+
+      if (!n)
+       {
+         n = 1;
+         error ("unrecognized command line option \"%s\"", opt);
+       }
+    }
+}
+
+/* Handle FILENAME from the command line.  */
+void
+add_input_filename (const char *filename)
+{
+  num_in_fnames++;
+  in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0]));
+  in_fnames[num_in_fnames - 1] = filename;
+}
+
+/* Parse command line options and set default flag values.  Do minimal
+   options processing.  */
+void
+decode_options (unsigned int argc, const char **argv)
+{
+  unsigned int lang_mask;
+
+  /* Perform language-specific options initialization.  */
+  lang_mask = (*lang_hooks.init_options) (argc, argv);
+
+  lang_hooks.initialize_diagnostics (global_dc);
+
+  /* Scan to see what optimization level has been specified.  That will
+     determine the default value of many flags.  */
+
+  handle_options (argc, argv, lang_mask);
+}
+
+/* Handle target- and language-independent options.  Return zero to
+   generate an "unknown option" message.  */
+static int
+common_handle_option (size_t scode, const char *arg,
+                     int value ATTRIBUTE_UNUSED)
+{
+  enum opt_code code = (enum opt_code) scode;
+
+  switch (code)
+    {
+    default:
+      abort ();
+
+    case OPT__help:
+      print_help ();
+      exit_after_options = true;
+      break;
+
+    case OPT__version:
+      print_version (stderr, "");
+      exit_after_options = true;
+      break;
+
+    case OPT_Werror:
+      warnings_are_errors = value;
+      break;
+
+    case OPT_Wsystem_headers:
+      warn_system_headers = value;
+      break;
+
+    case OPT_d:
+      decode_d_option (arg);
+      break;
+
+    case OPT_pedantic_errors:
+      flag_pedantic_errors = 1;
+      break;
+
+    case OPT_w:
+      inhibit_warnings = true;
+      break;
+    }
+
+  return 1;
+}
+
+/* Output --help text.  */
+static void
+print_help (void)
+{
+  size_t i;
+  const char *p;
+
+  GET_ENVIRONMENT (p, "COLUMNS");
+  if (p)
+    {
+      int value = atoi (p);
+      if (value > 0)
+       columns = value;
+    }
+
+  puts (_("The following options are language-independent:\n"));
+
+  print_filtered_help (CL_COMMON);
+
+  for (i = 0; lang_names[i]; i++)
+    {
+      printf (_("The %s front end recognizes the following options:\n\n"),
+             lang_names[i]);
+      print_filtered_help (1U << i);
+    }
+}
+
+/* Print help for a specific front-end, etc.  */
+static void
+print_filtered_help (unsigned int flag)
+{
+  unsigned int i, len, filter, indent = 0;
+  bool duplicates = false;
+  const char *help, *opt, *tab;
+  static char *printed;
+
+  if (flag == CL_COMMON)
+    {
+      filter = flag;
+      if (!printed)
+       printed = xmalloc (cl_options_count);
+      memset (printed, 0, cl_options_count);
+    }
+  else
+    {
+      /* Don't print COMMON options twice.  */
+      filter = flag | CL_COMMON;
+
+      for (i = 0; i < cl_options_count; i++)
+       {
+         if ((cl_options[i].flags & filter) != flag)
+           continue;
+
+         /* Skip help for internal switches.  */
+         if (cl_options[i].flags & CL_UNDOCUMENTED)
+           continue;
+
+         /* Skip switches that have already been printed, mark them to be
+            listed later.  */
+         if (printed[i])
+           {
+             duplicates = true;
+             indent = print_switch (cl_options[i].opt_text, indent);
+           }
+       }
+
+      if (duplicates)
+       {
+         putchar ('\n');
+         putchar ('\n');
+       }
+    }
+
+  for (i = 0; i < cl_options_count; i++)
+    {
+      if ((cl_options[i].flags & filter) != flag)
+       continue;
+
+      /* Skip help for internal switches.  */
+      if (cl_options[i].flags & CL_UNDOCUMENTED)
+       continue;
+
+      /* Skip switches that have already been printed.  */
+      if (printed[i])
+       continue;
+
+      printed[i] = true;
+
+      help = cl_options[i].help;
+      if (!help)
+       help = undocumented_msg;
+
+      /* Get the translation.  */
+      help = _(help);
+
+      tab = strchr (help, '\t');
+      if (tab)
+       {
+         len = tab - help;
+         opt = help;
+         help = tab + 1;
+       }
+      else
+       {
+         opt = cl_options[i].opt_text;
+         len = strlen (opt);
+       }
+
+      wrap_help (help, opt, len);
+    }
+
+  putchar ('\n');
+}
+
+/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by
+   word-wrapped HELP in a second column.  */
+static unsigned int
+print_switch (const char *text, unsigned int indent)
+{
+  unsigned int len = strlen (text) + 1; /* trailing comma */
+
+  if (indent)
+    {
+      putchar (',');
+      if (indent + len > columns)
+       {
+         putchar ('\n');
+         putchar (' ');
+         indent = 1;
+       }
+    }
+  else
+    putchar (' ');
+
+  putchar (' ');
+  fputs (text, stdout);
+
+  return indent + len + 1;
+}
+
+/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by
+   word-wrapped HELP in a second column.  */
+static void
+wrap_help (const char *help, const char *item, unsigned int item_width)
+{
+  unsigned int col_width = 27;
+  unsigned int remaining, room, len;
+
+  remaining = strlen (help);
+
+  do
+    {
+      room = columns - 3 - MAX (col_width, item_width);
+      if (room > columns)
+       room = 0;
+      len = remaining;
+
+      if (room < len)
+       {
+         unsigned int i;
+
+         for (i = 0; help[i]; i++)
+           {
+             if (i >= room && len != remaining)
+               break;
+             if (help[i] == ' ')
+               len = i;
+             else if ((help[i] == '-' || help[i] == '/')
+                      && help[i + 1] != ' '
+                      && i > 0 && ISALPHA (help[i - 1]))
+               len = i + 1;
+           }
+       }
+
+      printf( "  %-*.*s %.*s\n", col_width, item_width, item, len, help);
+      item_width = 0;
+      while (help[len] == ' ')
+       len++;
+      help += len;
+      remaining -= len;
+    }
+  while (remaining);
+}
diff --git a/support/cpp2/opts.h b/support/cpp2/opts.h
new file mode 100644 (file)
index 0000000..eb7c868
--- /dev/null
@@ -0,0 +1,56 @@
+/* Command line option handling.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef GCC_OPTS_H
+#define GCC_OPTS_H
+
+extern void decode_options (unsigned int argc, const char **argv);
+extern void add_input_filename (const char *filename);
+
+struct cl_option
+{
+  const char *opt_text;
+  const char *help;
+  unsigned short back_chain;
+  unsigned char opt_len;
+  unsigned int flags;
+};
+
+extern const struct cl_option cl_options[];
+extern const unsigned int cl_options_count;
+extern const char *const lang_names[];
+
+#define CL_JOINED              (1 << 24) /* If takes joined argument.  */
+#define CL_SEPARATE            (1 << 25) /* If takes a separate argument.  */
+#define CL_REJECT_NEGATIVE     (1 << 26) /* Reject no- form.  */
+#define CL_MISSING_OK          (1 << 27) /* Missing argument OK (joined).  */
+#define CL_UINTEGER            (1 << 28) /* Argument is an integer >=0.  */
+#define CL_COMMON              (1 << 29) /* Language-independent.  */
+#define CL_UNDOCUMENTED                (1 << 30) /* Do not output with --help.  */
+
+/* Input file names.  */
+
+extern const char **in_fnames;
+
+/* The count of input filenames.  */
+
+extern unsigned num_in_fnames;
+
+#endif
diff --git a/support/cpp2/opts.sh b/support/cpp2/opts.sh
new file mode 100755 (executable)
index 0000000..871c855
--- /dev/null
@@ -0,0 +1,175 @@
+#!/bin/sh
+#
+#  Copyright (C) 2003 Free Software Foundation, Inc.
+#  Contributed by Neil Booth, May 2003.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Usage: opts.sh moveifchange srcdir outfile.c outfile.h file1.opt [ ...]
+
+# Always operate in the C locale.
+LANG=C
+LANGUAGE=C
+LC_ALL=C
+export LANG LANGUAGE LC_ALL
+
+# Set AWK if environment has not already set it.
+AWK=${AWK-awk}
+
+SORT=sort              # Could be /bin/sort or /usr/bin/sort
+
+MOVEIFCHANGE=$1; shift
+C_FILE=$1; shift
+H_FILE=$1; shift
+TMP_C_FILE=tmp-${C_FILE}
+TMP_H_FILE=tmp-${H_FILE}
+
+${AWK} '
+       # Ignore comments and blank lines
+       /^[ \t]*(;|$)/  { next }
+       # Note that RS="" falls foul of gawk 3.1.2 bugs
+       /^[^ \t]/       { record = $0
+                         do { getline tmp;
+                              if (!(tmp ~ "^[ \t]*(;|$)"))
+                                 record = record "\034" tmp
+                         } while (tmp != "")
+                         print record
+                       }
+' "$@" | ${SORT} | ${AWK} '
+    function switch_flags (flags,   result)
+    {
+       flags = " " flags " "
+       result = "0"
+       for (j = 0; j < n_langs; j++) {
+           regex = " " langs[j] " "
+           gsub ( "\\+", "\\+", regex )
+           if (flags ~ regex)
+               result = result " | " macros[j]
+       }
+        if (flags ~ " Common ") result = result " | CL_COMMON"
+        if (flags ~ " Joined ") result = result " | CL_JOINED"
+        if (flags ~ " JoinedOrMissing ") \
+               result = result " | CL_JOINED | CL_MISSING_OK"
+        if (flags ~ " Separate ") result = result " | CL_SEPARATE"
+        if (flags ~ " RejectNegative ") result = result " | CL_REJECT_NEGATIVE"
+        if (flags ~ " UInteger ") result = result " | CL_UINTEGER"
+        if (flags ~ " Undocumented ") result = result " | CL_UNDOCUMENTED"
+       sub( "^0 \\| ", "", result )
+       return result
+    }
+
+    BEGIN {
+       FS = "\034"
+       n_opts = 0
+       n_langs = 0
+    }
+
+# Collect the text and flags of each option into an array
+    {
+       if ($1 == "Language") {
+               langs[n_langs] = $2
+               n_langs++;
+       } else {
+               opts[n_opts] = $1
+               flags[n_opts] = $2
+               help[n_opts] = $3
+               n_opts++;
+       }
+    }
+
+# Dump out an enumeration into a .h file, and an array of options into a
+# C file.  Combine the flags of duplicate options.
+    END {
+       c_file = "'${TMP_C_FILE}'"
+       h_file = "'${TMP_H_FILE}'"
+       realh_file = "'${H_FILE}'"
+       comma = ","
+
+       print "/* This file is auto-generated by opts.sh.  */\n" > c_file
+       print "#include <intl.h>"                       >> c_file
+       print "#include \"" realh_file "\""             >> c_file
+       print "#include \"opts.h\"\n"                   >> c_file
+       print "const char * const lang_names[] =\n{"    >> c_file
+
+       print "/* This file is auto-generated by opts.sh.  */\n" > h_file
+       for (i = 0; i < n_langs; i++) {
+           macros[i] = "CL_" langs[i]
+           gsub( "[^A-Za-z0-9_]", "X", macros[i] )
+           s = substr("         ", length (macros[i]))
+           print "#define " macros[i] s " (1 << " i ")" >> h_file
+           print "  \"" langs[i] "\","                 >> c_file
+       }
+
+       print "  0\n};\n"                               >> c_file
+       print "const unsigned int cl_options_count = N_OPTS;\n" >> c_file
+       print "const struct cl_option cl_options[] =\n{" >> c_file
+
+       print "\nenum opt_code\n{"                      >> h_file
+
+       for (i = 0; i < n_opts; i++)
+           back_chain[i] = "N_OPTS";
+
+       for (i = 0; i < n_opts; i++) {
+           # Combine the flags of identical switches.  Switches
+           # appear many times if they are handled by many front
+           # ends, for example.
+           while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {
+               flags[i + 1] = flags[i] " " flags[i + 1];
+               i++;
+           }
+
+           len = length (opts[i]);
+           enum = "OPT_" opts[i]
+           if (opts[i] == "finline-limit=")
+               enum = enum "eq"
+           gsub ("[^A-Za-z0-9]", "_", enum)
+
+           # If this switch takes joined arguments, back-chain all
+           # subsequent switches to it for which it is a prefix.  If
+           # a later switch S is a longer prefix of a switch T, T
+           # will be back-chained to S in a later iteration of this
+           # for() loop, which is what we want.
+           if (flags[i] ~ "Joined") {
+               for (j = i + 1; j < n_opts; j++) {
+                   if (substr (opts[j], 1, len) != opts[i])
+                       break;
+                   back_chain[j] = enum;
+               }
+           }
+
+           s = substr("                                  ", length (opts[i]))
+           if (i + 1 == n_opts)
+               comma = ""
+
+           if (help[i] == "")
+               hlp = "0"
+           else
+               hlp = "N_(\"" help[i] "\")";
+
+           printf("  %s,%s/* -%s */\n", enum, s, opts[i]) >> h_file
+           printf("  { \"-%s\",\n    %s,\n    %s, %u, %s }%s\n",
+                  opts[i], hlp, back_chain[i], len,
+                  switch_flags(flags[i]), comma)       >> c_file
+       }
+
+       print "  N_OPTS\n};"                            >> h_file
+       print "};"                                      >> c_file
+    }
+'
+
+# Copy the newly generated files back to the correct names only if different.
+# This is to prevent a cascade of file rebuilds when not necessary.
+${MOVEIFCHANGE} ${TMP_H_FILE} ${H_FILE}
+${MOVEIFCHANGE} ${TMP_C_FILE} ${C_FILE}
index 0f089719082198b56c2a631620cb0799507e166c..05a3743726f5057e1ce21d7a4a3bb4dfc25ad60a 100644 (file)
@@ -1,7 +1,7 @@
 /* Declarations for insn-output.c.  These functions are defined in recog.c,
    final.c, and varasm.c.
    Copyright (C) 1987, 1991, 1994, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -20,220 +20,214 @@ along with GCC; see the file COPYING.  If not, write to the Free
 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 02111-1307, USA.  */
 
+#ifndef GCC_OUTPUT_H
+#define GCC_OUTPUT_H
+
 /* Compute branch alignments based on frequency information in the CFG.  */
-extern void compute_alignments  PARAMS ((void));
+extern void compute_alignments (void);
 
 /* Initialize data in final at the beginning of a compilation.  */
-extern void init_final         PARAMS ((const char *));
-
-/* Called at end of source file,
-   to output the block-profiling table for this entire compilation.  */
-extern void end_final          PARAMS ((const char *));
+extern void init_final (const char *);
 
 /* Enable APP processing of subsequent output.
    Used before the output from an `asm' statement.  */
-extern void app_enable         PARAMS ((void));
+extern void app_enable (void);
 
 /* Disable APP processing of subsequent output.
    Called from varasm.c before most kinds of output.  */
-extern void app_disable                PARAMS ((void));
+extern void app_disable (void);
 
 /* Return the number of slots filled in the current
    delayed branch sequence (we don't count the insn needing the
    delay slot).   Zero if not in a delayed branch sequence.  */
-extern int dbr_sequence_length PARAMS ((void));
+extern int dbr_sequence_length (void);
 
 /* Indicate that branch shortening hasn't yet been done.  */
-extern void init_insn_lengths  PARAMS ((void));
+extern void init_insn_lengths (void);
 
 /* Obtain the current length of an insn.  If branch shortening has been done,
    get its actual length.  Otherwise, get its maximum length.  */
-extern int get_attr_length     PARAMS ((rtx));
+extern int get_attr_length (rtx);
 
 /* Make a pass over all insns and compute their actual lengths by shortening
    any branches of variable length if possible.  */
-extern void shorten_branches   PARAMS ((rtx));
+extern void shorten_branches (rtx);
 
 /* Output assembler code for the start of a function,
    and initialize some of the variables in this file
    for the new function.  The label for the function and associated
    assembler pseudo-ops have already been output in
    `assemble_start_function'.  */
-extern void final_start_function  PARAMS ((rtx, FILE *, int));
+extern void final_start_function (rtx, FILE *, int);
 
 /* Output assembler code for the end of a function.
    For clarity, args are same as those of `final_start_function'
    even though not all of them are needed.  */
-extern void final_end_function  PARAMS ((void));
+extern void final_end_function (void);
 
 /* Output assembler code for some insns: all or part of a function.  */
-extern void final              PARAMS ((rtx, FILE *, int, int));
+extern void final (rtx, FILE *, int, int);
 
 /* The final scan for one insn, INSN.  Args are same as in `final', except
    that INSN is the insn being scanned.  Value returned is the next insn to
    be scanned.  */
-extern rtx final_scan_insn     PARAMS ((rtx, FILE *, int, int, int));
+extern rtx final_scan_insn (rtx, FILE *, int, int, int, int *);
 
 /* Replace a SUBREG with a REG or a MEM, based on the thing it is a
    subreg of.  */
-extern rtx alter_subreg PARAMS ((rtx *));
+extern rtx alter_subreg (rtx *);
 
 /* Report inconsistency between the assembler template and the operands.
    In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
-extern void output_operand_lossage  PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1;
+extern void output_operand_lossage (const char *, ...) ATTRIBUTE_PRINTF_1;
 
 /* Output a string of assembler code, substituting insn operands.
    Defined in final.c.  */
-extern void output_asm_insn    PARAMS ((const char *, rtx *));
+extern void output_asm_insn (const char *, rtx *);
 
 /* Compute a worst-case reference address of a branch so that it
    can be safely used in the presence of aligned labels.
    Defined in final.c.  */
-extern int insn_current_reference_address      PARAMS ((rtx));
+extern int insn_current_reference_address (rtx);
 
 /* Find the alignment associated with a CODE_LABEL.
    Defined in final.c.  */
-extern int label_to_alignment  PARAMS ((rtx));
+extern int label_to_alignment (rtx);
 
 /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
-extern void output_asm_label   PARAMS ((rtx));
+extern void output_asm_label (rtx);
 
 /* Print a memory reference operand for address X
    using machine-dependent assembler syntax.  */
-extern void output_address     PARAMS ((rtx));
+extern void output_address (rtx);
 
 /* Print an integer constant expression in assembler syntax.
    Addition and subtraction are the only arithmetic
    that may appear in these expressions.  */
-extern void output_addr_const PARAMS ((FILE *, rtx));
+extern void output_addr_const (FILE *, rtx);
 
 /* Output a string of assembler code, substituting numbers, strings
    and fixed syntactic prefixes.  */
-extern void asm_fprintf                PARAMS ((FILE *file, const char *p, ...));
+#if GCC_VERSION >= 3004
+#define ATTRIBUTE_ASM_FPRINTF(m, n) __attribute__ ((__format__ (__asm_fprintf__, m, n))) ATTRIBUTE_NONNULL(m)
+/* This is a magic identifier which allows GCC to figure out the type
+   of HOST_WIDE_INT for %wd specifier checks.  You must issue this
+   typedef before using the __asm_fprintf__ format attribute.  */
+typedef HOST_WIDE_INT __gcc_host_wide_int__;
+#else
+#define ATTRIBUTE_ASM_FPRINTF(m, n) ATTRIBUTE_NONNULL(m)
+#endif
+
+extern void asm_fprintf (FILE *file, const char *p, ...)
+     ATTRIBUTE_ASM_FPRINTF(2, 3);
 
 /* Split up a CONST_DOUBLE or integer constant rtx into two rtx's for single
    words.  */
-extern void split_double       PARAMS ((rtx, rtx *, rtx *));
+extern void split_double (rtx, rtx *, rtx *);
 
 /* Return nonzero if this function has no function calls.  */
-extern int leaf_function_p     PARAMS ((void));
+extern int leaf_function_p (void);
 
 /* Return 1 if branch is a forward branch.
    Uses insn_shuid array, so it works only in the final pass.  May be used by
    output templates to add branch prediction hints, for example.  */
-extern int final_forward_branch_p PARAMS ((rtx));
+extern int final_forward_branch_p (rtx);
 
 /* Return 1 if this function uses only the registers that can be
    safely renumbered.  */
-extern int only_leaf_regs_used PARAMS ((void));
+extern int only_leaf_regs_used (void);
 
 /* Scan IN_RTX and its subexpressions, and renumber all regs into those
    available in leaf functions.  */
-extern void leaf_renumber_regs_insn PARAMS ((rtx));
+extern void leaf_renumber_regs_insn (rtx);
 
 /* Locate the proper template for the given insn-code.  */
-extern const char *get_insn_template PARAMS ((int, rtx));
+extern const char *get_insn_template (int, rtx);
 
 /* Add function NAME to the weak symbols list.  VALUE is a weak alias
    associated with NAME.  */
-extern int add_weak PARAMS ((tree, const char *, const char *));
+extern int add_weak (tree, const char *, const char *);
 
 /* Functions in flow.c */
-extern void allocate_for_life_analysis PARAMS ((void));
-extern int regno_uninitialized         PARAMS ((unsigned int));
-extern int regno_clobbered_at_setjmp   PARAMS ((int));
-extern void find_basic_blocks          PARAMS ((rtx, int, FILE *));
-extern bool cleanup_cfg                        PARAMS ((int));
-extern bool delete_unreachable_blocks  PARAMS ((void));
-extern void check_function_return_warnings PARAMS ((void));
+extern void allocate_for_life_analysis (void);
+extern int regno_uninitialized (unsigned int);
+extern int regno_clobbered_at_setjmp (int);
+extern void find_basic_blocks (rtx, int, FILE *);
+extern bool cleanup_cfg (int);
+extern bool delete_unreachable_blocks (void);
+extern void check_function_return_warnings (void);
 
 /* Functions in varasm.c.  */
 
 /* Tell assembler to switch to text section.  */
-extern void text_section               PARAMS ((void));
+extern void text_section (void);
 
 /* Tell assembler to switch to data section.  */
-extern void data_section               PARAMS ((void));
-
-/* Tell assembler to make sure its in the data section.  */
-extern void force_data_section         PARAMS ((void));
+extern void data_section (void);
 
 /* Tell assembler to switch to read-only data section.  This is normally
    the text section.  */
-extern void readonly_data_section      PARAMS ((void));
+extern void readonly_data_section (void);
 
 /* Determine if we're in the text section.  */
-extern int in_text_section             PARAMS ((void));
+extern int in_text_section (void);
 
 #ifdef CTORS_SECTION_ASM_OP
-extern void ctors_section PARAMS ((void));
+extern void ctors_section (void);
 #endif
 
 #ifdef DTORS_SECTION_ASM_OP
-extern void dtors_section PARAMS ((void));
+extern void dtors_section (void);
 #endif
 
 #ifdef BSS_SECTION_ASM_OP
-extern void bss_section PARAMS ((void));
-#endif
-
-#ifdef CONST_SECTION_ASM_OP
-extern void const_section PARAMS ((void));
+extern void bss_section (void);
 #endif
 
 #ifdef INIT_SECTION_ASM_OP
-extern void init_section PARAMS ((void));
+extern void init_section (void);
 #endif
 
 #ifdef FINI_SECTION_ASM_OP
-extern void fini_section PARAMS ((void));
+extern void fini_section (void);
 #endif
 
 #ifdef EXPORTS_SECTION_ASM_OP
-extern void exports_section PARAMS ((void));
-#endif
-
-#ifdef TDESC_SECTION_ASM_OP
-extern void tdesc_section PARAMS ((void));
+extern void exports_section (void);
 #endif
 
 #ifdef DRECTVE_SECTION_ASM_OP
-extern void drectve_section PARAMS ((void));
+extern void drectve_section (void);
 #endif
 
 #ifdef SDATA_SECTION_ASM_OP
-extern void sdata_section PARAMS ((void));
-#endif
-
-#ifdef RDATA_SECTION_ASM_OP
-extern void rdata_section PARAMS ((void));
+extern void sdata_section (void);
 #endif
 
 /* Tell assembler to change to section NAME for DECL.
    If DECL is NULL, just switch to section NAME.
    If NAME is NULL, get the name from DECL.
    If RELOC is 1, the initializer for DECL contains relocs.  */
-extern void named_section              PARAMS ((tree, const char *, int));
+extern void named_section (tree, const char *, int);
 
 /* Tell assembler to switch to the section for function DECL.  */
-extern void function_section           PARAMS ((tree));
+extern void function_section (tree);
 
 /* Tell assembler to switch to the section for string merging.  */
-extern void mergeable_string_section   PARAMS ((tree, unsigned HOST_WIDE_INT,
-                                                unsigned int));
+extern void mergeable_string_section (tree, unsigned HOST_WIDE_INT,
+                                     unsigned int);
 
 /* Tell assembler to switch to the section for constant merging.  */
-extern void mergeable_constant_section PARAMS ((enum machine_mode,
-                                                unsigned HOST_WIDE_INT,
-                                                unsigned int));
+extern void mergeable_constant_section (enum machine_mode,
+                                       unsigned HOST_WIDE_INT, unsigned int);
 
 /* Declare DECL to be a weak symbol.  */
-extern void declare_weak               PARAMS ((tree));
+extern void declare_weak (tree);
 /* Merge weak status.  */
-extern void merge_weak                 PARAMS ((tree, tree));
+extern void merge_weak (tree, tree);
 
 /* Emit any pending weak declarations.  */
-extern void weak_finish                        PARAMS ((void));
+extern void weak_finish (void);
 
 /* Decode an `asm' spec for a declaration as a register name.
    Return the register number, or -1 if nothing specified,
@@ -242,32 +236,29 @@ extern void weak_finish                   PARAMS ((void));
    or -4 if ASMSPEC is `memory' and is not recognized.
    Accept an exact spelling or a decimal number.
    Prefixes such as % are optional.  */
-extern int decode_reg_name             PARAMS ((const char *));
+extern int decode_reg_name (const char *);
 
 /* Make the rtl for variable VAR be volatile.
    Use this only for static variables.  */
-extern void make_var_volatile          PARAMS ((tree));
-
-/* Output alignment directive to align for constant expression EXP.  */
-extern void assemble_constant_align    PARAMS ((tree));
+extern void make_var_volatile (tree);
 
-extern void assemble_alias             PARAMS ((tree, tree));
+extern void assemble_alias (tree, tree);
 
-extern void default_assemble_visibility        PARAMS ((tree, int));
+extern void default_assemble_visibility (tree, int);
 
 /* Output a string of literal assembler code
    for an `asm' keyword used between functions.  */
-extern void assemble_asm               PARAMS ((tree));
+extern void assemble_asm (tree);
 
 /* Output assembler code for the constant pool of a function and associated
    with defining the name of the function.  DECL describes the function.
    NAME is the function's name.  For the constant pool, we use the current
    constant pool data.  */
-extern void assemble_start_function    PARAMS ((tree, const char *));
+extern void assemble_start_function (tree, const char *);
 
 /* Output assembler code associated with defining the size of the
    function.  DECL describes the function.  NAME is the function's name.  */
-extern void assemble_end_function      PARAMS ((tree, const char *));
+extern void assemble_end_function (tree, const char *);
 
 /* Assemble everything that is needed for a variable or function declaration.
    Not used for automatic variables, and not used for function definitions.
@@ -278,36 +269,36 @@ extern void assemble_end_function PARAMS ((tree, const char *));
    to define things that have had only tentative definitions.
    DONT_OUTPUT_DATA if nonzero means don't actually output the
    initial value (that will be done by the caller).  */
-extern void assemble_variable          PARAMS ((tree, int, int, int));
+extern void assemble_variable (tree, int, int, int);
 
 /* Output something to declare an external symbol to the assembler.
    (Most assemblers don't need this, so we normally output nothing.)
    Do nothing if DECL is not external.  */
-extern void assemble_external          PARAMS ((tree));
+extern void assemble_external (tree);
 
 /* Assemble code to leave SIZE bytes of zeros.  */
-extern void assemble_zeros             PARAMS ((int));
+extern void assemble_zeros (unsigned HOST_WIDE_INT);
 
 /* Assemble an alignment pseudo op for an ALIGN-bit boundary.  */
-extern void assemble_align             PARAMS ((int));
-extern void assemble_eh_align          PARAMS ((int));
+extern void assemble_align (int);
+extern void assemble_eh_align (int);
 
 /* Assemble a string constant with the specified C string as contents.  */
-extern void assemble_string            PARAMS ((const char *, int));
+extern void assemble_string (const char *, int);
 
 /* Similar, for calling a library function FUN.  */
-extern void assemble_external_libcall  PARAMS ((rtx));
+extern void assemble_external_libcall (rtx);
 
 /* Assemble a label named NAME.  */
-extern void assemble_label             PARAMS ((const char *));
-extern void assemble_eh_label          PARAMS ((const char *));
+extern void assemble_label (const char *);
+extern void assemble_eh_label (const char *);
 
 /* Output to FILE a reference to the assembler name of a C-level name NAME.
    If NAME starts with a *, the rest of NAME is output verbatim.
    Otherwise NAME is transformed in an implementation-defined way
    (usually by the addition of an underscore).
    Many macros in the tm file are defined to call this function.  */
-extern void assemble_name              PARAMS ((FILE *, const char *));
+extern void assemble_name (FILE *, const char *);
 
 /* Return the assembler directive for creating a given kind of integer
    object.  SIZE is the number of bytes in the object and ALIGNED_P
@@ -316,20 +307,20 @@ extern void assemble_name         PARAMS ((FILE *, const char *));
 
    The returned string should be printed at the start of a new line and
    be followed immediately by the object's initial value.  */
-extern const char *integer_asm_op      PARAMS ((int, int));
+extern const char *integer_asm_op (int, int);
 
 /* Use directive OP to assemble an integer object X.  Print OP at the
    start of the line, followed immediately by the value of X.  */
-extern void assemble_integer_with_op   PARAMS ((const char *, rtx));
+extern void assemble_integer_with_op (const char *, rtx);
 
 /* The default implementation of the asm_out.integer target hook.  */
-extern bool default_assemble_integer   PARAMS ((rtx, unsigned int, int));
+extern bool default_assemble_integer (rtx, unsigned int, int);
 
 /* Assemble the integer constant X into an object of SIZE bytes.  ALIGN is
    the alignment of the integer in bits.  Return 1 if we were able to output
    the constant, otherwise 0.  If FORCE is nonzero, abort if we can't output
    the constant.  */
-extern bool assemble_integer           PARAMS ((rtx, unsigned, unsigned, int));
+extern bool assemble_integer (rtx, unsigned, unsigned, int);
 
 /* An interface to assemble_integer for the common case in which a value is
    fully aligned and must be printed.  VALUE is the value of the integer
@@ -339,27 +330,18 @@ extern bool assemble_integer              PARAMS ((rtx, unsigned, unsigned, int));
 
 #ifdef REAL_VALUE_TYPE_SIZE
 /* Assemble the floating-point constant D into an object of size MODE.  */
-extern void assemble_real              PARAMS ((REAL_VALUE_TYPE,
-                                                enum machine_mode,
-                                                unsigned));
+extern void assemble_real (REAL_VALUE_TYPE, enum machine_mode, unsigned);
 #endif
 
-/* Start deferring output of subconstants.  */
-extern void defer_addressed_constants  PARAMS ((void));
-
-/* Stop deferring output of subconstants,
-   and output now all those that have been deferred.  */
-extern void output_deferred_addressed_constants PARAMS ((void));
-
 /* Return the size of the constant pool.  */
-extern int get_pool_size               PARAMS ((void));
+extern int get_pool_size (void);
 
 #ifdef HAVE_peephole
-extern rtx peephole                    PARAMS ((rtx));
+extern rtx peephole (rtx);
 #endif
 
 /* Write all the constants in the constant pool.  */
-extern void output_constant_pool       PARAMS ((const char *, tree));
+extern void output_constant_pool (const char *, tree);
 
 /* Return nonzero if VALUE is a valid constant-valued expression
    for use in initializing a static variable; one that can be an
@@ -370,7 +352,7 @@ extern void output_constant_pool    PARAMS ((const char *, tree));
    We assume that VALUE has been folded as much as possible;
    therefore, we do not need to check for such things as
    arithmetic-combinations of integers.  */
-extern tree initializer_constant_valid_p       PARAMS ((tree, tree));
+extern tree initializer_constant_valid_p (tree, tree);
 
 /* Output assembler code for constant EXP to FILE, with no label.
    This includes the pseudo-op such as ".int" or ".byte", and a newline.
@@ -380,8 +362,7 @@ extern tree initializer_constant_valid_p    PARAMS ((tree, tree));
    with zeros if necessary.  SIZE must always be specified.
 
    ALIGN is the alignment in bits that may be assumed for the data.  */
-extern void output_constant            PARAMS ((tree, HOST_WIDE_INT,
-                                                unsigned int));
+extern void output_constant (tree, unsigned HOST_WIDE_INT, unsigned int);
 
 /* When outputting delayed branch sequences, this rtx holds the
    sequence being output.  It is null when no delayed branch
@@ -441,10 +422,10 @@ extern FILE *rtl_dump_file;
 #endif
 
 /* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
-extern struct rtx_def *current_insn_predicate;
+extern rtx current_insn_predicate;
 
 /* Last insn processed by final_scan_insn.  */
-extern struct rtx_def *current_output_insn;
+extern rtx current_output_insn;
 
 /* Nonzero while outputting an `asm' with operands.
    This means that inconsistencies are the user's fault, so don't abort.
@@ -453,25 +434,31 @@ extern rtx this_is_asm_operands;
 
 /* Decide whether DECL needs to be in a writable section.
    RELOC is the same as for SELECT_SECTION.  */
-extern bool decl_readonly_section PARAMS ((tree, int));
-extern bool decl_readonly_section_1 PARAMS ((tree, int, int));
+extern bool decl_readonly_section (tree, int);
+extern bool decl_readonly_section_1 (tree, int, int);
+
+/* This can be used to compute RELOC for the function above, when
+   given a constant expression.  */
+extern int compute_reloc_for_constant (tree);
 
 /* User label prefix in effect for this compilation.  */
 extern const char *user_label_prefix;
 
 /* Default target function prologue and epilogue assembler output.  */
-extern void default_function_pro_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+extern void default_function_pro_epilogue (FILE *, HOST_WIDE_INT);
 
 /* Tell assembler to switch to the section for the exception table.  */
-extern void default_exception_section  PARAMS ((void));
+extern void default_exception_section (void);
 
 /* Tell assembler to switch to the section for the EH frames.  */
-extern void default_eh_frame_section   PARAMS ((void));
+extern void named_section_eh_frame_section (void);
+extern void collect2_eh_frame_section (void);
+extern void default_eh_frame_section (void);
 
 /* Default target hook that outputs nothing to a stream.  */
-extern void no_asm_to_stream PARAMS ((FILE *));
+extern void no_asm_to_stream (FILE *);
 
-/* Flags controling properties of a section.  */
+/* Flags controlling properties of a section.  */
 #define SECTION_ENTSIZE         0x000ff        /* entity size in section */
 #define SECTION_CODE    0x00100        /* contains code */
 #define SECTION_WRITE   0x00200        /* data is writable */
@@ -488,53 +475,45 @@ extern void no_asm_to_stream PARAMS ((FILE *));
 #define SECTION_NOTYPE  0x80000        /* don't output @progbits */
 #define SECTION_MACH_DEP 0x100000      /* subsequent bits reserved for target */
 
-extern unsigned int get_named_section_flags PARAMS ((const char *));
-extern bool set_named_section_flags    PARAMS ((const char *, unsigned int));
-extern void named_section_flags                PARAMS ((const char *, unsigned int));
-extern bool named_section_first_declaration PARAMS((const char *));
-
-union tree_node;
-extern unsigned int default_section_type_flags PARAMS ((union tree_node *,
-                                                       const char *, int));
-extern unsigned int default_section_type_flags_1 PARAMS ((union tree_node *,
-                                                         const char *,
-                                                         int, int));
-
-extern void default_no_named_section PARAMS ((const char *, unsigned int));
-extern void default_elf_asm_named_section PARAMS ((const char *, unsigned int));
-extern void default_coff_asm_named_section PARAMS ((const char *,
-                                                   unsigned int));
-extern void default_pe_asm_named_section PARAMS ((const char *, unsigned int));
-
-extern void default_stabs_asm_out_destructor PARAMS ((struct rtx_def *, int));
-extern void default_named_section_asm_out_destructor PARAMS ((struct rtx_def *,
-                                                             int));
-extern void default_dtor_section_asm_out_destructor PARAMS ((struct rtx_def *,
-                                                            int));
-extern void default_stabs_asm_out_constructor PARAMS ((struct rtx_def *, int));
-extern void default_named_section_asm_out_constructor PARAMS ((struct rtx_def *,
-                                                              int));
-extern void default_ctor_section_asm_out_constructor PARAMS ((struct rtx_def *,
-                                                             int));
-
-extern void default_select_section PARAMS ((tree, int,
-                                           unsigned HOST_WIDE_INT));
-extern void default_elf_select_section PARAMS ((tree, int,
-                                               unsigned HOST_WIDE_INT));
-extern void default_elf_select_section_1 PARAMS ((tree, int,
-                                                 unsigned HOST_WIDE_INT, int));
-extern void default_unique_section PARAMS ((tree, int));
-extern void default_unique_section_1 PARAMS ((tree, int, int));
-extern void default_select_rtx_section PARAMS ((enum machine_mode, rtx,
-                                               unsigned HOST_WIDE_INT));
-extern void default_elf_select_rtx_section PARAMS ((enum machine_mode, rtx,
-                                                   unsigned HOST_WIDE_INT));
-extern const char *default_strip_name_encoding PARAMS ((const char *));
-extern bool default_binds_local_p PARAMS ((tree));
-extern bool default_binds_local_p_1 PARAMS ((tree, int));
-extern void default_globalize_label PARAMS ((FILE *, const char *));
-
-/* Emit data for vtable gc for GNU binutils.  */
-extern void assemble_vtable_entry PARAMS ((struct rtx_def *, HOST_WIDE_INT));
-extern void assemble_vtable_inherit PARAMS ((struct rtx_def *,
-                                            struct rtx_def *));
+extern unsigned int get_named_section_flags (const char *);
+extern bool set_named_section_flags (const char *, unsigned int);
+extern void named_section_flags (const char *, unsigned int);
+extern bool named_section_first_declaration (const char *);
+extern unsigned int default_section_type_flags (tree, const char *, int);
+extern unsigned int default_section_type_flags_1 (tree, const char *, int, int);
+
+extern void default_no_named_section (const char *, unsigned int);
+extern void default_elf_asm_named_section (const char *, unsigned int);
+extern void default_coff_asm_named_section (const char *, unsigned int);
+extern void default_pe_asm_named_section (const char *, unsigned int);
+
+extern void default_stabs_asm_out_destructor (rtx, int);
+extern void default_named_section_asm_out_destructor (rtx, int);
+extern void default_dtor_section_asm_out_destructor (rtx, int);
+extern void default_stabs_asm_out_constructor (rtx, int);
+extern void default_named_section_asm_out_constructor (rtx, int);
+extern void default_ctor_section_asm_out_constructor (rtx, int);
+
+extern void default_select_section (tree, int, unsigned HOST_WIDE_INT);
+extern void default_elf_select_section (tree, int, unsigned HOST_WIDE_INT);
+extern void default_elf_select_section_1 (tree, int,
+                                         unsigned HOST_WIDE_INT, int);
+extern void default_unique_section (tree, int);
+extern void default_unique_section_1 (tree, int, int);
+extern void default_select_rtx_section (enum machine_mode, rtx,
+                                       unsigned HOST_WIDE_INT);
+extern void default_elf_select_rtx_section (enum machine_mode, rtx,
+                                           unsigned HOST_WIDE_INT);
+extern void default_encode_section_info (tree, rtx, int);
+extern const char *default_strip_name_encoding (const char *);
+extern bool default_binds_local_p (tree);
+extern bool default_binds_local_p_1 (tree, int);
+extern void default_globalize_label (FILE *, const char *);
+extern void default_internal_label (FILE *, const char *, unsigned long);
+extern void default_file_start (void);
+extern void file_end_indicate_exec_stack (void);
+extern bool default_valid_pointer_mode (enum machine_mode);
+
+extern int default_address_cost (rtx);
+
+#endif /* ! GCC_OUTPUT_H */
index 06930fee2ab1bfdc35c3f2aa4bf815758020e524..6204ee925e41be564e41be3e0c8c8068f5bea875 100644 (file)
@@ -1,5 +1,5 @@
 /* Utility to update paths from internal to external forms.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -74,21 +74,20 @@ Boston, MA 02111-1307, USA.  */
 
 static const char *std_prefix = PREFIX;
 
-static const char *get_key_value       PARAMS ((char *));
-static char *translate_name            PARAMS ((char *));
-static char *save_string               PARAMS ((const char *, int));
-static void tr                         PARAMS ((char *, int, int));
+static const char *get_key_value (char *);
+static char *translate_name (char *);
+static char *save_string (const char *, int);
+static void tr (char *, int, int);
 
 #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
-static char *lookup_key                PARAMS ((char *));
+static char *lookup_key (char *);
 static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
 #endif
 
 /* Given KEY, as above, return its value.  */
 
 static const char *
-get_key_value (key)
-     char *key;
+get_key_value (char *key)
 {
   const char *prefix = 0;
   char *temp = 0;
@@ -112,9 +111,7 @@ get_key_value (key)
 /* Return a copy of a string that has been placed in the heap.  */
 
 static char *
-save_string (s, len)
-  const char *s;
-  int len;
+save_string (const char *s, int len)
 {
   char *result = xmalloc (len + 1);
 
@@ -128,8 +125,7 @@ save_string (s, len)
 /* Look up "key" in the registry, as above.  */
 
 static char *
-lookup_key (key)
-     char *key;
+lookup_key (char *key)
 {
   char *dst;
   DWORD size;
@@ -157,12 +153,12 @@ lookup_key (key)
     }
 
   size = 32;
-  dst = (char *) xmalloc (size);
+  dst = xmalloc (size);
 
   res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
   if (res == ERROR_MORE_DATA && type == REG_SZ)
     {
-      dst = (char *) xrealloc (dst, size);
+      dst = xrealloc (dst, size);
       res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
     }
 
@@ -181,8 +177,7 @@ lookup_key (key)
    Otherwise, return the given name.  */
 
 static char *
-translate_name (name)
-     char *name;
+translate_name (char *name)
 {
   char code;
   char *key, *old_name;
@@ -200,7 +195,7 @@ translate_name (name)
           keylen++)
        ;
 
-      key = (char *) alloca (keylen + 1);
+      key = alloca (keylen + 1);
       strncpy (key, &name[1], keylen);
       key[keylen] = 0;
 
@@ -231,9 +226,7 @@ translate_name (name)
 
 /* In a NUL-terminated STRING, replace character C1 with C2 in-place.  */
 static void
-tr (string, c1, c2)
-     char *string;
-     int c1, c2;
+tr (char *string, int c1, int c2)
 {
   do
     {
@@ -248,9 +241,7 @@ tr (string, c1, c2)
    freeing it.  */
 
 char *
-update_path (path, key)
-  const char *path;
-  const char *key;
+update_path (const char *path, const char *key)
 {
   char *result, *p;
 
@@ -348,11 +339,9 @@ update_path (path, key)
   return result;
 }
 
-/* Reset the standard prefix */
+/* Reset the standard prefix */
 void
-set_std_prefix (prefix, len)
-  const char *prefix;
-  int len;
+set_std_prefix (const char *prefix, int len)
 {
   std_prefix = save_string (prefix, len);
 }
index ca8ee19dc3ec47ac314f3ed415421ae9e85e9005..25f2115962b899c3fcd3f7d7d78298f9a5b2bbfa 100644 (file)
@@ -1,5 +1,5 @@
 /* Provide prototypes for functions exported from prefix.c.
-   Copyright (C) 1999 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -25,7 +25,7 @@ Boston, MA 02111-1307, USA.  */
 /* Update PATH using KEY if PATH starts with PREFIX.  The returned
    string is always malloc-ed, and the caller is responsible for
    freeing it.  */
-extern char *update_path PARAMS ((const char *path, const char *key));
-extern void set_std_prefix PARAMS ((const char *, int));
+extern char *update_path (const char *path, const char *key);
+extern void set_std_prefix (const char *, int);
 
 #endif /* ! GCC_PREFIX_H */
diff --git a/support/cpp2/pretty-print.c b/support/cpp2/pretty-print.c
new file mode 100644 (file)
index 0000000..9ef12f2
--- /dev/null
@@ -0,0 +1,547 @@
+/* Various declarations for language-independent pretty-print subroutines.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "config.h"
+#undef FLOAT /* This is for hpux. They should change hpux.  */
+#undef FFS  /* Some systems define this in param.h.  */
+#include "system.h"
+#include "pretty-print.h"
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free  free
+
+/* A pointer to the formatted diagnostic message.  */
+#define pp_formatted_text_data(PP) \
+   ((const char *) obstack_base (&pp_base (PP)->buffer->obstack))
+
+/* Format an integer given by va_arg (ARG, type-specifier T) where
+   type-specifier is a precision modifier as indicated by PREC.  F is
+   a string used to construct the appropriate format-specifier.  */
+#define pp_integer_with_precision(PP, ARG, PREC, T, F)       \
+  do                                                         \
+    switch (PREC)                                            \
+      {                                                      \
+      case 0:                                                \
+        pp_scalar (PP, "%" F, va_arg (ARG, T));              \
+        break;                                               \
+                                                             \
+      case 1:                                                \
+        pp_scalar (PP, "%l" F, va_arg (ARG, long T));        \
+        break;                                               \
+                                                             \
+      case 2:                                                \
+        pp_scalar (PP, "%" PRINTF_INT64_MODIFIER F, va_arg (ARG, long_long)); \
+        break;                                               \
+                                                             \
+      default:                                               \
+        break;                                               \
+      }                                                      \
+  while (0)
+
+
+/* Subroutine of pp_set_maximum_length.  Set up PRETTY-PRINTER's
+   internal maximum characters per line.  */
+static void
+pp_set_real_maximum_length (pretty_printer *pp)
+{
+  /* If we're told not to wrap lines then do the obvious thing.  In case
+     we'll emit prefix only once per message, it is appropriate
+     not to increase unnecessarily the line-length cut-off.  */
+  if (!pp_is_wrapping_line (pp)
+      || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_ONCE
+      || pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_NEVER)
+    pp->maximum_length = pp_line_cutoff (pp);
+  else
+    {
+      int prefix_length = pp->prefix ? strlen (pp->prefix) : 0;
+      /* If the prefix is ridiculously too long, output at least
+         32 characters.  */
+      if (pp_line_cutoff (pp) - prefix_length < 32)
+       pp->maximum_length = pp_line_cutoff (pp) + 32;
+      else
+       pp->maximum_length = pp_line_cutoff (pp);
+    }
+}
+
+/* Clear PRETTY-PRINTER's output state.  */
+static inline void
+pp_clear_state (pretty_printer *pp)
+{
+  pp->emitted_prefix = false;
+  pp_indentation (pp) = 0;
+}
+
+/* Flush the formatted text of PRETTY-PRINTER onto the attached stream.  */
+static inline void
+pp_write_text_to_stream (pretty_printer *pp)
+{
+  const char *text = pp_formatted_text (pp);
+  fputs (text, pp->buffer->stream);
+  pp_clear_output_area (pp);
+}
+
+/* Wrap a text delimited by START and END into PRETTY-PRINTER.  */
+static void
+pp_wrap_text (pretty_printer *pp, const char *start, const char *end)
+{
+  bool wrapping_line = pp_is_wrapping_line (pp);
+
+  while (start != end)
+    {
+      /* Dump anything bordered by whitespaces.  */
+      {
+       const char *p = start;
+       while (p != end && !ISBLANK (*p) && *p != '\n')
+         ++p;
+       if (wrapping_line
+            && p - start >= pp_remaining_character_count_for_line (pp))
+         pp_newline (pp);
+       pp_append_text (pp, start, p);
+       start = p;
+      }
+
+      if (start != end && ISBLANK (*start))
+       {
+         pp_space (pp);
+         ++start;
+       }
+      if (start != end && *start == '\n')
+       {
+         pp_newline (pp);
+         ++start;
+       }
+    }
+}
+
+/* Same as pp_wrap_text but wrap text only when in line-wrapping mode.  */
+static inline void
+pp_maybe_wrap_text (pretty_printer *pp, const char *start, const char *end)
+{
+  if (pp_is_wrapping_line (pp))
+    pp_wrap_text (pp, start, end);
+  else
+    pp_append_text (pp, start, end);
+}
+
+/* Append to the output area of PRETTY-PRINTER a string specified by its
+   STARTing character and LENGTH.  */
+static inline void
+pp_append_r (pretty_printer *pp, const char *start, int length)
+{
+  obstack_grow (&pp->buffer->obstack, start, length);
+  pp->buffer->line_length += length;
+}
+
+/* Insert enough spaces into the output area of PRETTY-PRINTER to bring
+   the column position to the current indentation level, assuming that a
+   newline has just been written to the buffer.  */
+void
+pp_base_indent (pretty_printer *pp)
+{
+  int n = pp_indentation (pp);
+  int i;
+
+  for (i = 0; i < n; ++i)
+    pp_space (pp);
+}
+
+/* Format a message pointed to by TEXT.  The following format specifiers are
+   recognized as being client independent:
+   %d, %i: (signed) integer in base ten.
+   %u: unsigned integer in base ten.
+   %o: unsigned integer in base eight.
+   %x: unsigned integer in base sixteen.
+   %ld, %li, %lo, %lu, %lx: long versions of the above.
+   %lld, %lli, %llo, %llu, %llx: long long versions.
+   %wd, %wi, %wo, %wu, %wx: HOST_WIDE_INT versions.
+   %c: character.
+   %s: string.
+   %p: pointer.
+   %m: strerror(text->err_no) - does not consume a value from args_ptr.
+   %%: `%'.
+   %.*s: a substring the length of which is specified by an integer.
+   %H: location_t.  */
+void
+pp_base_format_text (pretty_printer *pp, text_info *text)
+{
+  for (; *text->format_spec; ++text->format_spec)
+    {
+      int precision = 0;
+      bool wide = false;
+
+      /* Ignore text.  */
+      {
+       const char *p = text->format_spec;
+       while (*p && *p != '%')
+         ++p;
+       pp_wrap_text (pp, text->format_spec, p);
+        text->format_spec = p;
+      }
+
+      if (*text->format_spec == '\0')
+       break;
+
+      /* We got a '%'.  Parse precision modifiers, if any.  */
+      switch (*++text->format_spec)
+        {
+        case 'w':
+          wide = true;
+          ++text->format_spec;
+          break;
+
+        case 'l':
+          do
+            ++precision;
+          while (*++text->format_spec == 'l');
+          break;
+
+        default:
+          break;
+        }
+      /* We don't support precision beyond that of "long long".  */
+      if (precision > 2)
+        abort();
+
+      switch (*text->format_spec)
+       {
+       case 'c':
+         pp_character (pp, va_arg (*text->args_ptr, int));
+         break;
+
+       case 'd':
+       case 'i':
+          if (wide)
+            pp_wide_integer (pp, va_arg (*text->args_ptr, HOST_WIDE_INT));
+          else
+            pp_integer_with_precision
+              (pp, *text->args_ptr, precision, int, "d");
+         break;
+
+       case 'o':
+          if (wide)
+            pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
+                       va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
+          else
+            pp_integer_with_precision
+              (pp, *text->args_ptr, precision, unsigned, "u");
+         break;
+
+       case 's':
+         pp_string (pp, va_arg (*text->args_ptr, const char *));
+         break;
+
+        case 'p':
+          pp_pointer (pp, va_arg (*text->args_ptr, void *));
+          break;
+
+       case 'u':
+          if (wide)
+            pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
+                       va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
+          else
+            pp_integer_with_precision
+              (pp, *text->args_ptr, precision, unsigned, "u");
+         break;
+
+       case 'x':
+          if (wide)
+            pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
+                       va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
+          else
+            pp_integer_with_precision
+              (pp, *text->args_ptr, precision, unsigned, "x");
+         break;
+
+       case 'm':
+         pp_string (pp, xstrerror (text->err_no));
+         break;
+
+       case '%':
+         pp_character (pp, '%');
+         break;
+
+        case 'H':
+          {
+            const location_t *locus = va_arg (*text->args_ptr, location_t *);
+            pp_string (pp, "file '");
+            pp_string (pp, locus->file);
+            pp_string (pp, "', line ");
+            pp_decimal_int (pp, locus->line);
+          }
+          break;
+
+       case '.':
+         {
+           int n;
+           const char *s;
+           /* We handle no precision specifier but `%.*s'.  */
+           if (*++text->format_spec != '*')
+             abort ();
+           else if (*++text->format_spec != 's')
+             abort ();
+           n = va_arg (*text->args_ptr, int);
+           s = va_arg (*text->args_ptr, const char *);
+           pp_append_text (pp, s, s + n);
+         }
+         break;
+
+       default:
+          if (!pp_format_decoder (pp) || !(*pp_format_decoder (pp)) (pp, text))
+           {
+             /* Hmmm.  The client failed to install a format translator
+                 but called us with an unrecognized format.  Or, maybe, the
+                 translated string just contains an invalid format, or
+                 has formats in the wrong order.  Sorry.  */
+             abort ();
+           }
+       }
+    }
+}
+
+/* Helper subroutine of output_verbatim and verbatim. Do the appropriate
+   settings needed by BUFFER for a verbatim formatting.  */
+void
+pp_base_format_verbatim (pretty_printer *pp, text_info *text)
+{
+  diagnostic_prefixing_rule_t rule = pp_prefixing_rule (pp);
+  int line_cutoff = pp_line_cutoff (pp);
+
+  /* Set verbatim mode.  */
+  pp->prefixing_rule = DIAGNOSTICS_SHOW_PREFIX_NEVER;
+  pp_line_cutoff (pp) = 0;
+  /* Do the actual formatting.  */
+  pp_format_text (pp, text);
+  /* Restore previous settings.  */
+  pp_prefixing_rule (pp) = rule;
+  pp_line_cutoff (pp) = line_cutoff;
+}
+
+/* Flush the content of BUFFER onto the attached stream.  */
+void
+pp_base_flush (pretty_printer *pp)
+{
+  pp_write_text_to_stream (pp);
+  pp_clear_state (pp);
+  fputc ('\n', pp->buffer->stream);
+  fflush (pp->buffer->stream);
+  pp_needs_newline (pp) = false;
+}
+
+/* Sets the number of maximum characters per line PRETTY-PRINTER can
+   output in line-wrapping mode.  A LENGTH value 0 suppresses
+   line-wrapping.  */
+void
+pp_base_set_line_maximum_length (pretty_printer *pp, int length)
+{
+  pp_line_cutoff (pp) = length;
+  pp_set_real_maximum_length (pp);
+}
+
+/* Clear PRETTY-PRINTER output area text info.  */
+void
+pp_base_clear_output_area (pretty_printer *pp)
+{
+  obstack_free (&pp->buffer->obstack, obstack_base (&pp->buffer->obstack));
+  pp->buffer->line_length = 0;
+}
+
+/* Set PREFIX for PRETTY-PRINTER.  */
+void
+pp_base_set_prefix (pretty_printer *pp, const char *prefix)
+{
+  pp->prefix = prefix;
+  pp_set_real_maximum_length (pp);
+  pp->emitted_prefix = false;
+  pp_indentation (pp) = 0;
+}
+
+/* Free PRETTY-PRINTER's prefix, a previously malloc()'d string.  */
+void
+pp_base_destroy_prefix (pretty_printer *pp)
+{
+  if (pp->prefix != NULL)
+    {
+      free ((char *) pp->prefix);
+      pp->prefix = NULL;
+    }
+}
+
+/* Write out PRETTY-PRINTER's prefix.  */
+void
+pp_base_emit_prefix (pretty_printer *pp)
+{
+  if (pp->prefix != NULL)
+    {
+      switch (pp_prefixing_rule (pp))
+       {
+       default:
+       case DIAGNOSTICS_SHOW_PREFIX_NEVER:
+         break;
+
+       case DIAGNOSTICS_SHOW_PREFIX_ONCE:
+         if (pp->emitted_prefix)
+           {
+             pp_base_indent (pp);
+             break;
+           }
+         pp_indentation (pp) += 3;
+         /* Fall through.  */
+
+       case DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE:
+         {
+           int prefix_length = strlen (pp->prefix);
+           pp_append_r (pp, pp->prefix, prefix_length);
+           pp->emitted_prefix = true;
+         }
+         break;
+       }
+    }
+}
+
+/* Construct a PRETTY-PRINTER with PREFIX and of MAXIMUM_LENGTH
+   characters per line.  */
+void
+pp_construct (pretty_printer *pp, const char *prefix, int maximum_length)
+{
+  memset (pp, 0, sizeof (pretty_printer));
+  pp->buffer = xcalloc (1, sizeof (output_buffer));
+  obstack_init (&pp->buffer->obstack);
+  pp->buffer->stream = stderr;
+  pp_line_cutoff (pp) = maximum_length;
+  pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
+  pp_set_prefix (pp, prefix);
+}
+
+/* Append a string delimited by START and END to the output area of
+   PRETTY-PRINTER.  No line wrapping is done.  However, if beginning a
+   new line then emit PRETTY-PRINTER's prefix and skip any leading
+   whitespace if appropriate.  The caller must ensure that it is
+   safe to do so.  */
+void
+pp_base_append_text (pretty_printer *pp, const char *start, const char *end)
+{
+  /* Emit prefix and skip whitespace if we're starting a new line.  */
+  if (pp->buffer->line_length == 0)
+    {
+      pp_emit_prefix (pp);
+      if (pp_is_wrapping_line (pp))
+       while (start != end && *start == ' ')
+         ++start;
+    }
+  pp_append_r (pp, start, end - start);
+}
+
+/* Finishes constructing a NULL-terminated character string representing
+   the PRETTY-PRINTED text.  */
+const char *
+pp_base_formatted_text (pretty_printer *pp)
+{
+  obstack_1grow (&pp->buffer->obstack, '\0');
+  return pp_formatted_text_data (pp);
+}
+
+/*  Return a pointer to the last character emitted in PRETTY-PRINTER's
+    output area.  A NULL pointer means no character available.  */
+const char *
+pp_base_last_position_in_text (const pretty_printer *pp)
+{
+  const char *p = NULL;
+  struct obstack *text = &pp->buffer->obstack;
+
+  if (obstack_base (text) != obstack_next_free (text))
+    p = ((const char *) obstack_next_free (text)) - 1;
+  return p;
+}
+
+/* Return the amount of characters PRETTY-PRINTER can accept to
+   make a full line.  Meaningful only in line-wrapping mode.  */
+int
+pp_base_remaining_character_count_for_line (pretty_printer *pp)
+{
+  return pp->maximum_length - pp->buffer->line_length;
+}
+
+
+/* Format a message into BUFFER a la printf.  */
+void
+pp_printf (pretty_printer *pp, const char *msg, ...)
+{
+  text_info text;
+  va_list ap;
+
+  va_start (ap, msg);
+  text.err_no = errno;
+  text.args_ptr = &ap;
+  text.format_spec = msg;
+  pp_format_text (pp, &text);
+  va_end (ap);
+}
+
+
+/* Output MESSAGE verbatim into BUFFER.  */
+void
+pp_verbatim (pretty_printer *pp, const char *msg, ...)
+{
+  text_info text;
+  va_list ap;
+
+  va_start (ap, msg);
+  text.err_no = errno;
+  text.args_ptr = &ap;
+  text.format_spec = msg;
+  pp_format_verbatim (pp, &text);
+  va_end (ap);
+}
+
+
+
+/* Have PRETTY-PRINTER start a new line.  */
+void
+pp_base_newline (pretty_printer *pp)
+{
+  obstack_1grow (&pp->buffer->obstack, '\n');
+  pp->buffer->line_length = 0;
+}
+
+/* Have PRETTY-PRINTER add a CHARACTER.  */
+void
+pp_base_character (pretty_printer *pp, int c)
+{
+  if (pp_is_wrapping_line (pp)
+      && pp_remaining_character_count_for_line (pp) <= 0)
+    {
+      pp_newline (pp);
+      if (ISSPACE (c))
+        return;
+    }
+  obstack_1grow (&pp->buffer->obstack, c);
+  ++pp->buffer->line_length;
+}
+
+/* Append a STRING to the output area of PRETTY-PRINTER; the STRING may
+   be line-wrapped if in appropriate mode.  */
+void
+pp_base_string (pretty_printer *pp, const char *str)
+{
+  pp_maybe_wrap_text (pp, str, str + (str ? strlen (str) : 0));
+}
+
+
diff --git a/support/cpp2/pretty-print.h b/support/cpp2/pretty-print.h
new file mode 100644 (file)
index 0000000..1691aec
--- /dev/null
@@ -0,0 +1,261 @@
+/* Various declarations for language-independent pretty-print subroutines.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#ifndef GCC_PRETTY_PRINT_H
+#define GCC_PRETTY_PRINT_H
+
+#include "obstack.h"
+#include "input.h"
+
+/* The type of a text to be formatted according a format specification
+   along with a list of things.  */
+typedef struct
+{
+  const char *format_spec;
+  va_list *args_ptr;
+  int err_no;  /* for %m */
+} text_info;
+
+/* How often diagnostics are prefixed by their locations:
+   o DIAGNOSTICS_SHOW_PREFIX_NEVER: never - not yet supported;
+   o DIAGNOSTICS_SHOW_PREFIX_ONCE: emit only once;
+   o DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE: emit each time a physical
+   line is started.  */
+typedef enum
+{
+  DIAGNOSTICS_SHOW_PREFIX_ONCE       = 0x0,
+  DIAGNOSTICS_SHOW_PREFIX_NEVER      = 0x1,
+  DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE = 0x2
+} diagnostic_prefixing_rule_t;
+
+/* The output buffer datatype.  This is best seen as an abstract datatype
+   whose fields should not be accessed directly by clients.  */
+typedef struct 
+{
+  /* The obstack where the text is built up.  */  
+  struct obstack obstack;
+
+  /* Where to output formatted text.  */
+  FILE *stream;
+
+  /* The amount of characters output so far.  */  
+  int line_length;
+
+  /* This must be large enough to hold any printed integer or
+     floating-point value.  */
+  char digit_buffer[128];
+} output_buffer;
+
+/* The type of pretty-printer flags passed to clients.  */
+typedef unsigned int pp_flags;
+
+typedef enum
+{
+  pp_none, pp_before, pp_after
+} pp_padding;
+
+/* The type of a hook that formats client-specific data onto a pretty_pinter.
+   A client-supplied formatter returns true if everything goes well,
+   otherwise it returns false.  */
+typedef struct pretty_print_info pretty_printer;
+typedef bool (*printer_fn) (pretty_printer *, text_info *);
+
+/* Client supplied function used to decode formats.  */
+#define pp_format_decoder(PP) pp_base (PP)->format_decoder
+
+/* TRUE if a newline character needs to be added before further
+   formatting.  */
+#define pp_needs_newline(PP)  pp_base (PP)->need_newline 
+
+/* Maximum characters per line in automatic line wrapping mode.
+   Zero means don't wrap lines.  */
+#define pp_line_cutoff(PP)  pp_base (PP)->ideal_maximum_length
+
+/* True if PRETTY-PTINTER is in line-wrapping mode.  */
+#define pp_is_wrapping_line(PP) (pp_line_cutoff (PP) > 0)
+
+/* Prefixing rule used in formatting a diagnostic message.  */
+#define pp_prefixing_rule(PP)  pp_base (PP)->prefixing_rule
+
+/* The amount of whitespace to be emitted when starting a new line.  */
+#define pp_indentation(PP) pp_base (PP)->indent_skip
+
+/* The data structure that contains the bare minimum required to do
+   proper pretty-printing.  Clients may derived from this structure
+   and add additional fields they need.  */
+struct pretty_print_info
+{
+  /* Where we print external representation of ENTITY.  */
+  output_buffer *buffer;
+
+  /* The prefix for each new line.  */
+  const char *prefix;
+  
+  /* Where to put whitespace around the entity being formatted.  */
+  pp_padding padding;
+  
+  /* The real upper bound of number of characters per line, taking into
+     account the case of a very very looong prefix.  */  
+  int maximum_length;
+
+  /* The ideal upper bound of number of characters per line, as suggested
+     by front-end.  */  
+  int ideal_maximum_length;
+
+  /* Indentation count.  */
+  int indent_skip;
+
+  /* Current prefixing rule.  */
+  diagnostic_prefixing_rule_t prefixing_rule;
+
+  /* If non-NULL, this function formats a TEXT into the BUFFER.  When called,
+     TEXT->format_spec points to a format code.  FORMAT_DECODER should call
+     pp_string (and related functions) to add data to the BUFFER.
+     FORMAT_DECODER can read arguments from *TEXT->args_pts using VA_ARG.
+     If the BUFFER needs additional characters from the format string, it
+     should advance the TEXT->format_spec as it goes.  When FORMAT_DECODER
+     returns, TEXT->format_spec should point to the last character processed.
+  */
+  printer_fn format_decoder;
+
+  /* Nonzero if current PREFIX was emitted at least once.  */
+  bool emitted_prefix;
+
+  /* Nonzero means one should emit a newline before outputting anything.  */
+  bool need_newline;
+};
+
+#define pp_set_line_maximum_length(PP, L) \
+   pp_base_set_line_maximum_length (pp_base (PP), L)
+#define pp_set_prefix(PP, P)    pp_base_set_prefix (pp_base (PP), P)
+#define pp_destroy_prefix(PP)   pp_base_destroy_prefix (pp_base (PP))
+#define pp_remaining_character_count_for_line(PP) \
+  pp_base_remaining_character_count_for_line (pp_base (PP))
+#define pp_clear_output_area(PP) \
+  pp_base_clear_output_area (pp_base (PP))
+#define pp_formatted_text(PP)   pp_base_formatted_text (pp_base (PP))
+#define pp_last_position_in_text(PP) \
+  pp_base_last_position_in_text (pp_base (PP))
+#define pp_emit_prefix(PP)      pp_base_emit_prefix (pp_base (PP))
+#define pp_append_text(PP, B, E) \
+  pp_base_append_text (pp_base (PP), B, E)
+#define pp_flush(PP)            pp_base_flush (pp_base (PP))
+#define pp_format_text(PP, TI)  pp_base_format_text (pp_base (PP), TI)
+#define pp_format_verbatim(PP, TI) \
+  pp_base_format_verbatim (pp_base (PP), TI)
+
+#define pp_character(PP, C)     pp_base_character (pp_base (PP), C)
+#define pp_string(PP, S)        pp_base_string (pp_base (PP), S)
+#define pp_newline(PP)          pp_base_newline (pp_base (PP))
+
+#define pp_space(PP)            pp_character (PP, ' ')
+#define pp_left_paren(PP)       pp_character (PP, '(')
+#define pp_right_paren(PP)      pp_character (PP, ')')
+#define pp_left_bracket(PP)     pp_character (PP, '[')
+#define pp_right_bracket(PP)    pp_character (PP, ']')
+#define pp_left_brace(PP)       pp_character (PP, '{')
+#define pp_right_brace(PP)      pp_character (PP, '}')
+#define pp_semicolon(PP)        pp_character (PP, ';')
+#define pp_comma(PP)            pp_string (PP, ", ")
+#define pp_dot(PP)              pp_character (PP, '.')
+#define pp_colon(PP)            pp_character (PP, ':')
+#define pp_colon_colon(PP)      pp_string (PP, "::")
+#define pp_arrow(PP)            pp_string (PP, "->")
+#define pp_equal(PP)            pp_character (PP, '=')
+#define pp_question(PP)         pp_character (PP, '?')
+#define pp_bar(PP)              pp_character (PP, '|')
+#define pp_carret(PP)           pp_character (PP, '^')
+#define pp_ampersand(PP)        pp_character (PP, '&')
+#define pp_less(PP)             pp_character (PP, '<')
+#define pp_greater(PP)          pp_character (PP, '>')
+#define pp_plus(PP)             pp_character (PP, '+')
+#define pp_minus(PP)            pp_character (PP, '-')
+#define pp_star(PP)             pp_character (PP, '*')
+#define pp_slash(PP)            pp_character (PP, '/')
+#define pp_modulo(PP)           pp_character (PP, '%')
+#define pp_exclamation(PP)      pp_character (PP, '!')
+#define pp_complement(PP)       pp_character (PP, '~')
+#define pp_quote(PP)            pp_character (PP, '\'')
+#define pp_backquote(PP)        pp_character (PP, '`')
+#define pp_doublequote(PP)      pp_character (PP, '"')
+#define pp_newline_and_indent(PP, N) \
+  do {                               \
+    pp_indentation (PP) += N;        \
+    pp_newline (PP);                 \
+    pp_base_indent (pp_base (PP));   \
+    pp_needs_newline (PP) = false;   \
+  } while (0)
+#define pp_maybe_newline_and_indent(PP, N) \
+  if (pp_needs_newline (PP)) pp_newline_and_indent (PP, N)
+#define pp_separate_with(PP, C)     \
+   do {                             \
+     pp_character (PP, C);          \
+     pp_space (PP);                 \
+   } while (0)
+#define pp_scalar(PP, FORMAT, SCALAR)                        \
+  do                                                         \
+    {                                                        \
+      sprintf (pp_buffer (PP)->digit_buffer, FORMAT, SCALAR); \
+      pp_string (PP, pp_buffer (PP)->digit_buffer);           \
+    }                                                        \
+  while (0)
+#define pp_decimal_int(PP, I)  pp_scalar (PP, "%d", I)
+#define pp_wide_integer(PP, I) \
+   pp_scalar (PP, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) I)
+#define pp_pointer(PP, P)      pp_scalar (PP, "%p", P)
+
+#define pp_identifier(PP, ID)  pp_string (PP, ID)
+#define pp_tree_identifier(PP, T)                      \
+  pp_append_text(PP, IDENTIFIER_POINTER (T), \
+                 IDENTIFIER_POINTER (T) + IDENTIFIER_LENGTH (T))
+
+#define pp_unsupported_tree(PP, T)                         \
+  pp_verbatim (pp_base (PP), "#`%s' not supported by %s#", \
+               tree_code_name[(int) TREE_CODE (T)], __FUNCTION__)
+
+
+#define pp_buffer(PP) pp_base (PP)->buffer
+/* Clients that directly derive from pretty_printer need to override
+   this macro to return a pointer to the base pretty_printer structure.  */
+#define pp_base(PP) (PP)
+
+extern void pp_construct (pretty_printer *, const char *, int);
+extern void pp_base_set_line_maximum_length (pretty_printer *, int);
+extern void pp_base_set_prefix (pretty_printer *, const char *);
+extern void pp_base_destroy_prefix (pretty_printer *);
+extern int pp_base_remaining_character_count_for_line (pretty_printer *);
+extern void pp_base_clear_output_area (pretty_printer *);
+extern const char *pp_base_formatted_text (pretty_printer *);
+extern const char *pp_base_last_position_in_text (const pretty_printer *);
+extern void pp_base_emit_prefix (pretty_printer *);
+extern void pp_base_append_text (pretty_printer *, const char *, const char *);
+extern void pp_printf (pretty_printer *, const char *, ...) ATTRIBUTE_PRINTF_2;
+extern void pp_verbatim (pretty_printer *, const char *, ...);
+extern void pp_base_flush (pretty_printer *);
+extern void pp_base_format_text (pretty_printer *, text_info *);
+extern void pp_base_format_verbatim (pretty_printer *, text_info *);
+
+extern void pp_base_indent (pretty_printer *);
+extern void pp_base_newline (pretty_printer *);
+extern void pp_base_character (pretty_printer *, int);
+extern void pp_base_string (pretty_printer *, const char *);
+
+#endif /* GCC_PRETTY_PRINT_H */
diff --git a/support/cpp2/sdcc.h b/support/cpp2/sdcc.h
deleted file mode 100644 (file)
index dd917df..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef __SDCC_H
-#define __SDCC_H
-
-/*
- * From defaults.h
- */
-#ifndef GET_ENVIRONMENT
-#define GET_ENVIRONMENT(VALUE, NAME) do { (VALUE) = getenv (NAME); } while (0)
-#endif
-
-/* Define results of standard character escape sequences.  */
-#define TARGET_BELL    007
-#define TARGET_BS      010
-#define TARGET_TAB     011
-#define TARGET_NEWLINE 012
-#define TARGET_VT      013
-#define TARGET_FF      014
-#define TARGET_CR      015
-#define TARGET_ESC     033
-
-#define CHAR_TYPE_SIZE 8
-#define WCHAR_TYPE_SIZE 32     /* ? maybe ? */
-
-#define SUPPORTS_ONE_ONLY 0
-
-#define TARGET_OBJECT_SUFFIX ".rel"
-
-#ifndef WCHAR_UNSIGNED
-#define WCHAR_UNSIGNED 0
-#endif
-
-#ifdef _WIN32
-#define HAVE_DOS_BASED_FILE_SYSTEM
-#endif
-
-/*
- * From hashtab.h
- */
-#ifndef GTY
-#define GTY(X)
-#endif
-
-#endif  /* __SDCC_H */
diff --git a/support/cpp2/sdcpp-opts.c b/support/cpp2/sdcpp-opts.c
new file mode 100644 (file)
index 0000000..8f8e85e
--- /dev/null
@@ -0,0 +1,883 @@
+/* C/ObjC/C++ command line option handling.
+   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Neil Booth.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "cppdefault.h"
+#include "c-incpath.h"
+#include "opts.h"
+#include "options.h"
+
+#ifndef DOLLARS_IN_IDENTIFIERS
+# define DOLLARS_IN_IDENTIFIERS true
+#endif
+
+#ifndef TARGET_SYSTEM_ROOT
+# define TARGET_SYSTEM_ROOT NULL
+#endif
+
+static int saved_lineno;
+
+/* CPP's options.  */
+static cpp_options *cpp_opts;
+
+/* Input filename.  */
+static const char *this_input_filename;
+
+/* Filename and stream for preprocessed output.  */
+static const char *out_fname;
+static FILE *out_stream;
+
+/* Append dependencies to deps_file.  */
+static bool deps_append;
+
+/* If dependency switches (-MF etc.) have been given.  */
+static bool deps_seen;
+
+/* If -v seen.  */
+static bool verbose;
+
+/* Dependency output file.  */
+static const char *deps_file;
+
+/* The prefix given by -iprefix, if any.  */
+static const char *iprefix;
+
+/* The system root, if any.  Overridden by -isysroot.  */
+static const char *sysroot = TARGET_SYSTEM_ROOT;
+
+/* Zero disables all standard directories for headers.  */
+static bool std_inc = true;
+
+/* If the quote chain has been split by -I-.  */
+static bool quote_chain_split;
+
+/* If -Wunused-macros.  */
+static bool warn_unused_macros;
+
+/* Number of deferred options.  */
+static size_t deferred_count;
+
+/* Number of deferred options scanned for -include.  */
+static size_t include_cursor;
+
+static void handle_OPT_d (const char *);
+static void set_std_c89 (int, int);
+static void set_std_c99 (int);
+static void check_deps_environment_vars (void);
+static void handle_deferred_opts (void);
+static void sanitize_cpp_opts (void);
+static void add_prefixed_path (const char *, size_t);
+static void push_command_line_include (void);
+static void cb_file_change (cpp_reader *, const struct line_map *);
+static void cb_dir_change (cpp_reader *, const char *);
+static void finish_options (void);
+
+#ifndef STDC_0_IN_SYSTEM_HEADERS
+#define STDC_0_IN_SYSTEM_HEADERS 0
+#endif
+
+/* Holds switches parsed by sdcpp_common_handle_option (), but whose
+   handling is deferred to sdcpp_common_post_options ().  */
+static void defer_opt (enum opt_code, const char *);
+static struct deferred_opt
+{
+  enum opt_code code;
+  const char *arg;
+} *deferred_opts;
+
+/* Complain that switch CODE expects an argument but none was
+   provided.  OPT was the command-line option.  Return FALSE to get
+   the default message in opts.c, TRUE if we provide a specialized
+   one.  */
+bool
+sdcpp_common_missing_argument (const char *opt, size_t code)
+{
+  switch (code)
+    {
+    default:
+      /* Pick up the default message.  */
+      return false;
+
+    case OPT_A:
+      error ("assertion missing after \"%s\"", opt);
+      break;
+
+    case OPT_D:
+    case OPT_U:
+      error ("macro name missing after \"%s\"", opt);
+      break;
+
+    case OPT_I:
+    case OPT_idirafter:
+    case OPT_isysroot:
+    case OPT_isystem:
+      error ("missing path after \"%s\"", opt);
+      break;
+
+    case OPT_MF:
+    case OPT_MD:
+    case OPT_MMD:
+    case OPT_include:
+    case OPT_imacros:
+    case OPT_o:
+      error ("missing filename after \"%s\"", opt);
+      break;
+
+    case OPT_MQ:
+    case OPT_MT:
+      error ("missing makefile target after \"%s\"", opt);
+      break;
+    }
+
+  return true;
+}
+
+/* Defer option CODE with argument ARG.  */
+static void
+defer_opt (enum opt_code code, const char *arg)
+{
+  deferred_opts[deferred_count].code = code;
+  deferred_opts[deferred_count].arg = arg;
+  deferred_count++;
+}
+
+/* Common initialization before parsing options.  */
+unsigned int
+sdcpp_common_init_options (unsigned int argc, const char **argv ATTRIBUTE_UNUSED)
+{
+  parse_in = cpp_create_reader (CLK_GNUC89, NULL);
+
+  cpp_opts = cpp_get_options (parse_in);
+  cpp_opts->dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
+  cpp_opts->objc = 0;
+
+  /* Reset to avoid warnings on internal definitions.  We set it just
+     before passing on command-line options to cpplib.  */
+  cpp_opts->warn_dollars = 0;
+
+  deferred_opts = xmalloc (argc * sizeof (struct deferred_opt));
+
+  return CL_SDCPP;
+}
+
+/* Handle switch SCODE with argument ARG.  VALUE is true, unless no-
+   form of an -f or -W option was given.  Returns 0 if the switch was
+   invalid, a negative number to prevent language-independent
+   processing in toplev.c (a hack necessary for the short-term).  */
+int
+sdcpp_common_handle_option (size_t scode, const char *arg, int value)
+{
+  const struct cl_option *option = &cl_options[scode];
+  enum opt_code code = (enum opt_code) scode;
+  int result = 1;
+
+  switch (code)
+    {
+    default:
+      result = 0;
+      break;
+
+#if 0 // pch not supported by sdcpp
+    case OPT__output_pch_:
+      pch_file = arg;
+      break;
+#endif
+
+    case OPT_A:
+      defer_opt (code, arg);
+      break;
+
+    case OPT_C:
+      cpp_opts->discard_comments = 0;
+      break;
+
+    case OPT_CC:
+      cpp_opts->discard_comments = 0;
+      cpp_opts->discard_comments_in_macro_exp = 0;
+      break;
+
+    case OPT_D:
+      defer_opt (code, arg);
+      break;
+
+    case OPT_H:
+      cpp_opts->print_include_names = 1;
+      break;
+
+    case OPT_I:
+      if (strcmp (arg, "-"))
+       add_path (xstrdup (arg), BRACKET, 0);
+      else
+       {
+         if (quote_chain_split)
+           error ("-I- specified twice");
+         quote_chain_split = true;
+         split_quote_chain ();
+       }
+      break;
+
+    case OPT_M:
+    case OPT_MM:
+      /* When doing dependencies with -M or -MM, suppress normal
+        preprocessed output, but still do -dM etc. as software
+        depends on this.  Preprocessed output does occur if -MD, -MMD
+        or environment var dependency generation is used.  */
+      cpp_opts->deps.style = (code == OPT_M ? DEPS_SYSTEM: DEPS_USER);
+      flag_no_output = 1;
+      cpp_opts->inhibit_warnings = 1;
+      break;
+
+    case OPT_MD:
+    case OPT_MMD:
+      cpp_opts->deps.style = (code == OPT_MD ? DEPS_SYSTEM: DEPS_USER);
+      deps_file = arg;
+      break;
+
+    case OPT_MF:
+      deps_seen = true;
+      deps_file = arg;
+      break;
+
+    case OPT_MG:
+      deps_seen = true;
+      cpp_opts->deps.missing_files = true;
+      break;
+
+    case OPT_MP:
+      deps_seen = true;
+      cpp_opts->deps.phony_targets = true;
+      break;
+
+    case OPT_MQ:
+    case OPT_MT:
+      deps_seen = true;
+      defer_opt (code, arg);
+      break;
+
+    case OPT_P:
+      flag_no_line_commands = 1;
+      break;
+
+    case OPT_fworking_directory:
+      flag_working_directory = value;
+      break;
+
+    case OPT_U:
+      defer_opt (code, arg);
+      break;
+
+    case OPT_Wall:
+      cpp_opts->warn_trigraphs = value;
+      cpp_opts->warn_comments = value;
+      cpp_opts->warn_num_sign_change = value;
+      cpp_opts->warn_multichar = value;        /* Was C++ only.  */
+      break;
+
+    case OPT_Wcomment:
+    case OPT_Wcomments:
+      cpp_opts->warn_comments = value;
+      break;
+
+    case OPT_Wdeprecated:
+      cpp_opts->warn_deprecated = value;
+      break;
+
+    case OPT_Wendif_labels:
+      cpp_opts->warn_endif_labels = value;
+      break;
+
+    case OPT_Werror:
+      cpp_opts->warnings_are_errors = value;
+      break;
+
+    case OPT_Wimport:
+      /* Silently ignore for now.  */
+      break;
+
+#if 0 // pch not supported by sdcpp
+    case OPT_Winvalid_pch:
+      cpp_opts->warn_invalid_pch = value;
+      break;
+#endif
+
+    case OPT_Wsystem_headers:
+      cpp_opts->warn_system_headers = value;
+      break;
+
+    case OPT_Wtrigraphs:
+      cpp_opts->warn_trigraphs = value;
+      break;
+
+    case OPT_Wundef:
+      cpp_opts->warn_undef = value;
+      break;
+
+    case OPT_Wunused_macros:
+      warn_unused_macros = value;
+      break;
+
+    case OPT_ansi:
+      set_std_c89 (false, true);
+      break;
+
+    case OPT_d:
+      handle_OPT_d (arg);
+      break;
+
+    case OPT_fdollars_in_identifiers:
+      cpp_opts->dollars_in_ident = value;
+      break;
+
+    case OPT_fsigned_char:
+      flag_signed_char = value;
+      break;
+
+    case OPT_funsigned_char:
+      flag_signed_char = !value;
+      break;
+
+#if 0 // pch not supported by sdcpp
+    case OPT_fpch_deps:
+      cpp_opts->restore_pch_deps = value;
+      break;
+#endif
+
+    case OPT_fpreprocessed:
+      cpp_opts->preprocessed = value;
+      break;
+
+    case OPT_fshow_column:
+      cpp_opts->show_column = value;
+      break;
+
+    case OPT_ftabstop_:
+      /* It is documented that we silently ignore silly values.  */
+      if (value >= 1 && value <= 100)
+       cpp_opts->tabstop = value;
+      break;
+
+    case OPT_fexec_charset_:
+      cpp_opts->narrow_charset = arg;
+      break;
+
+    case OPT_fwide_exec_charset_:
+      cpp_opts->wide_charset = arg;
+      break;
+
+    case OPT_finput_charset_:
+      cpp_opts->input_charset = arg;
+      break;
+
+    case OPT_idirafter:
+      add_path (xstrdup (arg), AFTER, 0);
+      break;
+
+    case OPT_imacros:
+    case OPT_include:
+      defer_opt (code, arg);
+      break;
+
+    case OPT_iprefix:
+      iprefix = arg;
+      break;
+
+    case OPT_isysroot:
+      sysroot = arg;
+      break;
+
+    case OPT_isystem:
+      add_path (xstrdup (arg), SYSTEM, 0);
+      break;
+
+    case OPT_iwithprefix:
+      add_prefixed_path (arg, SYSTEM);
+      break;
+
+    case OPT_iwithprefixbefore:
+      add_prefixed_path (arg, BRACKET);
+      break;
+
+    case OPT_lang_asm:
+      cpp_set_lang (parse_in, CLK_ASM);
+      cpp_opts->dollars_in_ident = false;
+      break;
+
+    case OPT_lang_objc:
+      cpp_opts->objc = 1;
+      break;
+
+    case OPT_nostdinc:
+      std_inc = false;
+      break;
+
+    case OPT_o:
+      if (!out_fname)
+       out_fname = arg;
+      else
+       error ("output filename specified twice");
+      break;
+
+      /* SDCPP specfic */
+    case OPT_obj_ext_:
+      cpp_opts->obj_ext = arg;
+      break;
+
+      /* We need to handle the -pedantic switches here, rather than in
+        sdcpp_common_post_options, so that a subsequent -Wno-endif-labels
+        is not overridden.  */
+    case OPT_pedantic_errors:
+      cpp_opts->pedantic_errors = 1;
+      /* Fall through.  */
+    case OPT_pedantic:
+      cpp_opts->pedantic = 1;
+      cpp_opts->warn_endif_labels = 1;
+      break;
+
+      /* SDCPP specfic */
+    case OPT_pedantic_parse_number:
+      cpp_opts->pedantic_parse_number = 1;
+      break;
+
+    case OPT_remap:
+      cpp_opts->remap = 1;
+      break;
+
+    case OPT_std_c89:
+    case OPT_std_iso9899_1990:
+    case OPT_std_iso9899_199409:
+      set_std_c89 (code == OPT_std_iso9899_199409 /* c94 */, true /* ISO */);
+      break;
+
+    case OPT_std_c99:
+    case OPT_std_iso9899_1999:
+      set_std_c99 (true /* ISO */);
+      break;
+
+    case OPT_trigraphs:
+      cpp_opts->trigraphs = 1;
+      break;
+
+    case OPT_traditional_cpp:
+      cpp_opts->traditional = 1;
+      break;
+
+    case OPT_w:
+      cpp_opts->inhibit_warnings = 1;
+      break;
+
+    case OPT_v:
+      verbose = true;
+      break;
+    }
+
+  return result;
+}
+
+/* Post-switch processing.  */
+bool
+sdcpp_common_post_options (const char **pfilename)
+{
+  struct cpp_callbacks *cb;
+
+  /* Canonicalize the input and output filenames.  */
+  if (in_fnames == NULL)
+    {
+      in_fnames = xmalloc (sizeof (in_fnames[0]));
+      in_fnames[0] = "";
+    }
+  else if (strcmp (in_fnames[0], "-") == 0)
+    in_fnames[0] = "";
+
+  if (out_fname == NULL || !strcmp (out_fname, "-"))
+    out_fname = "";
+
+  if (cpp_opts->deps.style == DEPS_NONE)
+    check_deps_environment_vars ();
+
+  handle_deferred_opts ();
+
+  sanitize_cpp_opts ();
+
+  register_include_chains (parse_in, sysroot, iprefix,
+                          std_inc, 0, verbose);
+
+  /* Open the output now.  We must do so even if flag_no_output is
+     on, because there may be other output than from the actual
+     preprocessing (e.g. from -dM).  */
+  if (out_fname[0] == '\0')
+    out_stream = stdout;
+  else
+    out_stream = fopen (out_fname, "w");
+
+  if (out_stream == NULL)
+    {
+      fatal_error ("opening output file %s: %m", out_fname);
+      return false;
+    }
+
+  if (num_in_fnames > 1)
+    error ("too many filenames given.  Type %s --help for usage",
+          progname);
+
+  init_pp_output (out_stream);
+
+  cb = cpp_get_callbacks (parse_in);
+  cb->file_change = cb_file_change;
+  cb->dir_change = cb_dir_change;
+  cpp_post_options (parse_in);
+
+  saved_lineno = input_line;
+  input_line = 0;
+
+  /* If an error has occurred in cpplib, note it so we fail
+     immediately.  */
+  errorcount += cpp_errors (parse_in);
+
+  *pfilename = this_input_filename
+    = cpp_read_main_file (parse_in, in_fnames[0]);
+  /* Don't do any compilation or preprocessing if there is no input file.  */
+  if (this_input_filename == NULL)
+    {
+      errorcount++;
+      return false;
+    }
+
+  if (flag_working_directory && ! flag_no_line_commands)
+    pp_dir_change (parse_in, get_src_pwd ());
+
+  return 1;
+}
+
+/* Front end initialization common to C, ObjC and C++.  */
+bool
+sdcpp_common_init (void)
+{
+  input_line = saved_lineno;
+
+  /* Default CPP arithmetic to something sensible for the host for the
+     benefit of dumb users like fix-header.  */
+  cpp_opts->precision = CHAR_BIT * sizeof (long);
+  cpp_opts->char_precision = CHAR_BIT;
+  cpp_opts->int_precision = CHAR_BIT * sizeof (int);
+  cpp_opts->wchar_precision = CHAR_BIT * sizeof (int);
+  cpp_opts->unsigned_wchar = 1;
+  cpp_opts->bytes_big_endian = BYTES_BIG_ENDIAN;
+
+  /* This can't happen until after wchar_precision and bytes_big_endian
+     are known.  */
+  cpp_init_iconv (parse_in);
+
+  finish_options ();
+  preprocess_file (parse_in);
+  return false;
+}
+
+/* Common finish hook for the C, ObjC and C++ front ends.  */
+void
+sdcpp_common_finish (void)
+{
+  FILE *deps_stream = NULL;
+
+  if (cpp_opts->deps.style != DEPS_NONE)
+    {
+      /* If -M or -MM was seen without -MF, default output to the
+        output stream.  */
+      if (!deps_file)
+       deps_stream = out_stream;
+      else
+       {
+         deps_stream = fopen (deps_file, deps_append ? "a": "w");
+         if (!deps_stream)
+           fatal_error ("opening dependency file %s: %m", deps_file);
+       }
+    }
+
+  /* For performance, avoid tearing down cpplib's internal structures
+     with cpp_destroy ().  */
+  errorcount += cpp_finish (parse_in, deps_stream);
+
+  if (deps_stream && deps_stream != out_stream
+      && (ferror (deps_stream) || fclose (deps_stream)))
+    fatal_error ("closing dependency file %s: %m", deps_file);
+
+  if (out_stream && (ferror (out_stream) || fclose (out_stream)))
+    fatal_error ("when writing output to %s: %m", out_fname);
+}
+
+/* Either of two environment variables can specify output of
+   dependencies.  Their value is either "OUTPUT_FILE" or "OUTPUT_FILE
+   DEPS_TARGET", where OUTPUT_FILE is the file to write deps info to
+   and DEPS_TARGET is the target to mention in the deps.  They also
+   result in dependency information being appended to the output file
+   rather than overwriting it, and like Sun's compiler
+   SUNPRO_DEPENDENCIES suppresses the dependency on the main file.  */
+static void
+check_deps_environment_vars (void)
+{
+  char *spec;
+
+  GET_ENVIRONMENT (spec, "DEPENDENCIES_OUTPUT");
+  if (spec)
+    cpp_opts->deps.style = DEPS_USER;
+  else
+    {
+      GET_ENVIRONMENT (spec, "SUNPRO_DEPENDENCIES");
+      if (spec)
+       {
+         cpp_opts->deps.style = DEPS_SYSTEM;
+         cpp_opts->deps.ignore_main_file = true;
+       }
+    }
+
+  if (spec)
+    {
+      /* Find the space before the DEPS_TARGET, if there is one.  */
+      char *s = strchr (spec, ' ');
+      if (s)
+       {
+         /* Let the caller perform MAKE quoting.  */
+         defer_opt (OPT_MT, s + 1);
+         *s = '\0';
+       }
+
+      /* Command line -MF overrides environment variables and default.  */
+      if (!deps_file)
+       deps_file = spec;
+
+      deps_append = 1;
+    }
+}
+
+/* Handle deferred command line switches.  */
+static void
+handle_deferred_opts (void)
+{
+  size_t i;
+
+  for (i = 0; i < deferred_count; i++)
+    {
+      struct deferred_opt *opt = &deferred_opts[i];
+
+      if (opt->code == OPT_MT || opt->code == OPT_MQ)
+       cpp_add_dependency_target (parse_in, opt->arg, opt->code == OPT_MQ);
+    }
+}
+
+/* These settings are appropriate for GCC, but not necessarily so for
+   cpplib as a library.  */
+static void
+sanitize_cpp_opts (void)
+{
+  /* If we don't know what style of dependencies to output, complain
+     if any other dependency switches have been given.  */
+  if (deps_seen && cpp_opts->deps.style == DEPS_NONE)
+    error ("to generate dependencies you must specify either -M or -MM");
+
+  /* -dM and dependencies suppress normal output; do it here so that
+     the last -d[MDN] switch overrides earlier ones.  */
+  if (flag_dump_macros == 'M')
+    flag_no_output = 1;
+
+  /* Disable -dD, -dN and -dI if normal output is suppressed.  Allow
+     -dM since at least glibc relies on -M -dM to work.  */
+  /* Also, flag_no_output implies flag_no_line_commands, always. */
+  if (flag_no_output)
+    {
+      if (flag_dump_macros != 'M')
+       flag_dump_macros = 0;
+      flag_dump_includes = 0;
+      flag_no_line_commands = 1;
+    }
+
+  cpp_opts->unsigned_char = !flag_signed_char;
+  cpp_opts->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS;
+
+  /* If we're generating preprocessor output, emit current directory
+     if explicitly requested  */
+  if (flag_working_directory == -1)
+    flag_working_directory = 0;
+}
+
+/* Add include path with a prefix at the front of its name.  */
+static void
+add_prefixed_path (const char *suffix, size_t chain)
+{
+  char *path;
+  const char *prefix;
+  size_t prefix_len, suffix_len;
+
+  suffix_len = strlen (suffix);
+  prefix     = iprefix ? iprefix : cpp_GCC_INCLUDE_DIR;
+  prefix_len = iprefix ? strlen (iprefix) : cpp_GCC_INCLUDE_DIR_len;
+
+  path = xmalloc (prefix_len + suffix_len + 1);
+  memcpy (path, prefix, prefix_len);
+  memcpy (path + prefix_len, suffix, suffix_len);
+  path[prefix_len + suffix_len] = '\0';
+
+  add_path (path, chain, 0);
+}
+
+/* Handle -D, -U, -A, -imacros, and the first -include.  */
+static void
+finish_options (void)
+{
+  if (!cpp_opts->preprocessed)
+    {
+      size_t i;
+
+      cpp_change_file (parse_in, LC_RENAME, _("<built-in>"));
+      cpp_init_builtins (parse_in, 0 /*flag_hosted*/);
+
+      /* We're about to send user input to cpplib, so make it warn for
+        things that we previously (when we sent it internal definitions)
+        told it to not warn.
+
+        C99 permits implementation-defined characters in identifiers.
+        The documented meaning of -std= is to turn off extensions that
+        conflict with the specified standard, and since a strictly
+        conforming program cannot contain a '$', we do not condition
+        their acceptance on the -std= setting.  */
+      cpp_opts->warn_dollars = (cpp_opts->pedantic && !cpp_opts->c99);
+
+      cpp_change_file (parse_in, LC_RENAME, _("<command line>"));
+      for (i = 0; i < deferred_count; i++)
+       {
+         struct deferred_opt *opt = &deferred_opts[i];
+
+         if (opt->code == OPT_D)
+           cpp_define (parse_in, opt->arg);
+         else if (opt->code == OPT_U)
+           cpp_undef (parse_in, opt->arg);
+         else if (opt->code == OPT_A)
+           {
+             if (opt->arg[0] == '-')
+               cpp_unassert (parse_in, opt->arg + 1);
+             else
+               cpp_assert (parse_in, opt->arg);
+           }
+       }
+
+      /* Handle -imacros after -D and -U.  */
+      for (i = 0; i < deferred_count; i++)
+       {
+         struct deferred_opt *opt = &deferred_opts[i];
+
+         if (opt->code == OPT_imacros
+             && cpp_push_include (parse_in, opt->arg))
+           {
+             /* Disable push_command_line_include callback for now.  */
+             include_cursor = deferred_count + 1;
+             cpp_scan_nooutput (parse_in);
+           }
+       }
+    }
+
+  include_cursor = 0;
+  push_command_line_include ();
+}
+
+/* Give CPP the next file given by -include, if any.  */
+static void
+push_command_line_include (void)
+{
+  while (include_cursor < deferred_count)
+    {
+      struct deferred_opt *opt = &deferred_opts[include_cursor++];
+
+      if (! cpp_opts->preprocessed && opt->code == OPT_include
+         && cpp_push_include (parse_in, opt->arg))
+       return;
+    }
+
+  if (include_cursor == deferred_count)
+    {
+      include_cursor++;
+      /* -Wunused-macros should only warn about macros defined hereafter.  */
+      cpp_opts->warn_unused_macros = warn_unused_macros;
+      /* Restore the line map from <command line>.  */
+      if (! cpp_opts->preprocessed)
+       cpp_change_file (parse_in, LC_RENAME, main_input_filename);
+
+      /* Set this here so the client can change the option if it wishes,
+        and after stacking the main file so we don't trace the main file.  */
+      cpp_get_line_maps (parse_in)->trace_includes
+       = cpp_opts->print_include_names;
+    }
+}
+
+/* File change callback.  Has to handle -include files.  */
+static void
+cb_file_change (cpp_reader *pfile ATTRIBUTE_UNUSED,
+               const struct line_map *new_map)
+{
+  pp_file_change (new_map);
+
+  if (new_map == 0 || (new_map->reason == LC_LEAVE && MAIN_FILE_P (new_map)))
+    push_command_line_include ();
+}
+
+void
+cb_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir)
+{
+  if (! set_src_pwd (dir))
+    warning ("too late for # directive to set debug directory");
+}
+
+/* Set the C 89 standard (with 1994 amendments if C94, without GNU
+   extensions if ISO).  There is no concept of gnu94.  */
+static void
+set_std_c89 (int c94, int iso)
+{
+  cpp_set_lang (parse_in, c94 ? CLK_STDC94: iso ? CLK_STDC89: CLK_GNUC89);
+}
+
+/* Set the C 99 standard (without GNU extensions if ISO).  */
+static void
+set_std_c99 (int iso)
+{
+  cpp_set_lang (parse_in, iso ? CLK_STDC99: CLK_GNUC99);
+}
+
+/* Args to -d specify what to dump.  Silently ignore
+   unrecognized options; they may be aimed at toplev.c.  */
+static void
+handle_OPT_d (const char *arg)
+{
+  char c;
+
+  while ((c = *arg++) != '\0')
+    switch (c)
+      {
+      case 'M':                        /* Dump macros only.  */
+      case 'N':                        /* Dump names.  */
+      case 'D':                        /* Dump definitions.  */
+       flag_dump_macros = c;
+       break;
+
+      case 'I':
+       flag_dump_includes = 1;
+       break;
+      }
+}
diff --git a/support/cpp2/sdcpp.c b/support/cpp2/sdcpp.c
new file mode 100644 (file)
index 0000000..def45e2
--- /dev/null
@@ -0,0 +1,360 @@
+/*-------------------------------------------------------------------------
+    sdcppmain.c - sdcpp: SDCC preprocessor main file, using cpplib.
+
+    Written by Borut Razem, 2006.
+
+    This program is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the
+    Free Software Foundation; either version 2, or (at your option) any
+    later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+    In other words, you are welcome to use, share and improve this program.
+    You are forbidden to forbid anyone else to use, share and improve
+    what you give them.   Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "cpphash.h"
+#include "version.h"
+#include "mkdeps.h"
+#include "opts.h"
+#include "intl.h"
+#include "c-pretty-print.h"
+#include "diagnostic.h"
+
+#define CPP_FATAL_LIMIT 1000
+/* True if we have seen a "fatal" error.  */
+#define CPP_FATAL_ERRORS(PFILE) (cpp_errors (PFILE) >= CPP_FATAL_LIMIT)
+
+const char *progname;          /* Needs to be global.  */
+
+/* From laghooks-def.h */
+/* The whole thing.  The structure is defined in langhooks.h.  */
+#define LANG_HOOKS_INITIALIZER { \
+  LANG_HOOKS_INIT_OPTIONS, \
+  LANG_HOOKS_INITIALIZE_DIAGNOSTICS, \
+  LANG_HOOKS_HANDLE_OPTION, \
+  LANG_HOOKS_MISSING_ARGUMENT, \
+  LANG_HOOKS_POST_OPTIONS, \
+  LANG_HOOKS_INIT, \
+  LANG_HOOKS_FINISH, \
+  LANG_HOOKS_PRINT_ERROR_FUNCTION, \
+}
+
+/* From c-lang.c */
+#define LANG_HOOKS_INIT_OPTIONS sdcpp_common_init_options
+#define LANG_HOOKS_INITIALIZE_DIAGNOSTICS sdcpp_initialize_diagnostics
+#define LANG_HOOKS_HANDLE_OPTION sdcpp_common_handle_option
+#define LANG_HOOKS_MISSING_ARGUMENT sdcpp_common_missing_argument
+#define LANG_HOOKS_POST_OPTIONS sdcpp_common_post_options
+#define LANG_HOOKS_INIT sdcpp_common_init
+#define LANG_HOOKS_FINISH sdcpp_common_finish
+#define LANG_HOOKS_PRINT_ERROR_FUNCTION sdcpp_print_error_function
+
+static void sdcpp_initialize_diagnostics (diagnostic_context *context);
+static void sdcpp_print_error_function (diagnostic_context *context, const char *file);
+
+/* Each front end provides its own lang hook initializer.  */
+const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+/* Name of top-level original source file (what was input to cpp).
+   This comes from the #-command at the beginning of the actual input.
+   If there isn't any there, then this is the cc1 input file name.  */
+
+const char *main_input_filename;
+
+/* Current position in real source file.  */
+
+location_t input_location;
+
+/* Stack of currently pending input files.  */
+
+struct file_stack *input_file_stack;
+
+/* Incremented on each change to input_file_stack.  */
+int input_file_stack_tick;
+
+/* Temporarily suppress certain warnings.
+   This is set while reading code from a system header file.  */
+
+int in_system_header = 0;
+
+/* Nonzero means change certain warnings into errors.
+   Usually these are warnings about failure to conform to some standard.  */
+
+int flag_pedantic_errors = 0;
+
+cpp_reader *parse_in;          /* Declared in c-pragma.h.  */
+
+/* Nonzero means `char' should be signed.  */
+
+int flag_signed_char;
+
+/* Nonzero means don't output line number information.  */
+
+char flag_no_line_commands;
+
+/* Nonzero causes -E output not to be done, but directives such as
+   #define that have side effects are still obeyed.  */
+
+char flag_no_output;
+
+/* Nonzero means dump macros in some fashion.  */
+
+char flag_dump_macros;
+
+/* Nonzero means pass #include lines through to the output.  */
+
+char flag_dump_includes;
+
+/* 0 means we want the preprocessor to not emit line directives for
+   the current working directory.  1 means we want it to do it.  -1
+   means we should decide depending on whether debugging information
+   is being emitted or not.  */
+
+int flag_working_directory = -1;
+
+/* The current working directory of a translation.  It's generally the
+   directory from which compilation was initiated, but a preprocessed
+   file may specify the original directory in which it was
+   created.  */
+
+static const char *src_pwd;
+
+/* Initialize src_pwd with the given string, and return true.  If it
+   was already initialized, return false.  As a special case, it may
+   be called with a NULL argument to test whether src_pwd has NOT been
+   initialized yet.  */
+
+bool
+set_src_pwd (const char *pwd)
+{
+  if (src_pwd)
+    return false;
+
+  src_pwd = xstrdup (pwd);
+  return true;
+}
+
+/* Return the directory from which the translation unit was initiated,
+   in case set_src_pwd() was not called before to assign it a
+   different value.  */
+
+const char *
+get_src_pwd (void)
+{
+  if (! src_pwd)
+    src_pwd = getpwd ();
+
+   return src_pwd;
+}
+
+static void
+sdcpp_initialize_diagnostics (diagnostic_context *context)
+{
+  pretty_printer *base = context->printer;
+  c_pretty_printer *pp = xmalloc (sizeof (c_pretty_printer));
+  memcpy (pp_base (pp), base, sizeof (pretty_printer));
+  pp_c_pretty_printer_init (pp);
+  context->printer = (pretty_printer *) pp;
+
+  /* It is safe to free this object because it was previously malloc()'d.  */
+  free (base);
+}
+
+/* The default function to print out name of current function that caused
+   an error.  */
+static void
+sdcpp_print_error_function (diagnostic_context *context, const char *file)
+{
+}
+
+/* Initialize the PRETTY-PRINTER for handling C codes.  */
+
+void
+pp_c_pretty_printer_init (c_pretty_printer *pp)
+{
+}
+
+void
+print_version (FILE *file, const char *indent)
+{
+  fprintf (file, _("GNU CPP version %s (cpplib)"), version_string);
+#ifdef TARGET_VERSION
+  TARGET_VERSION;
+#endif
+  fputc ('\n', file);
+}
+
+/* Initialization of the front end environment, before command line
+   options are parsed.  Signal handlers, internationalization etc.
+   ARGV0 is main's argv[0].  */
+static void
+general_init (const char *argv0)
+{
+  const char *p;
+
+  p = argv0 + strlen (argv0);
+  while (p != argv0 && !IS_DIR_SEPARATOR (p[-1]))
+    --p;
+  progname = p;
+
+  xmalloc_set_program_name (progname);
+
+  hex_init ();
+
+  gcc_init_libintl ();
+
+  /* Initialize the diagnostics reporting machinery, so option parsing
+     can give warnings and errors.  */
+  diagnostic_initialize (global_dc);
+}
+
+/* Process the options that have been parsed.  */
+static void
+process_options (void)
+{
+  /* Allow the front end to perform consistency checks and do further
+     initialization based on the command line options.  This hook also
+     sets the original filename if appropriate (e.g. foo.i -> foo.c)
+     so we can correctly initialize debug output.  */
+  /*no_backend =*/ (*lang_hooks.post_options) (&main_input_filename);
+  input_filename = main_input_filename;
+}
+
+#if 0
+/* A warning.  Use this for code which is correct according to the
+   relevant language specification but is likely to be buggy anyway.  */
+void
+warning (const char *msgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, msgid);
+  fprintf (stderr, "%s: error: ", progname);
+  vfprintf (stderr, msgid, ap);
+  va_end (ap);
+}
+
+/* A hard error: the code is definitely ill-formed, and an object file
+   will not be produced.  */
+void
+error (const char *msgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, msgid);
+  fprintf (stderr, "%s: warning: ", progname);
+  vfprintf (stderr, msgid, ap);
+  va_end (ap);
+}
+
+/* Print a fatal I/O error message.  Argument are like printf.
+   Also include a system error message based on `errno'.  */
+void
+fatal_io_error (const char *msgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, msgid);
+  fprintf (stderr, "%s: %s: ", progname, xstrerror (errno));
+  vfprintf(stderr, msgid, ap);
+  va_end (ap);
+  exit (FATAL_EXIT_CODE);
+}
+#endif
+
+/* Parse a -d... command line switch.  */
+
+void
+decode_d_option (const char *arg)
+{
+  int c;
+
+  while (*arg)
+    switch (c = *arg++)
+      {
+      case 'D':        /* These are handled by the preprocessor.  */
+      case 'I':
+      case 'M':
+      case 'N':
+       break;
+
+      default:
+       warning ("unrecognized gcc debugging option: %c", c);
+       break;
+      }
+}
+
+/* Language-dependent initialization.  Returns nonzero on success.  */
+static int
+lang_dependent_init (const char *name)
+{
+  /* Other front-end initialization.  */
+  if ((*lang_hooks.init) () == 0)
+    return 0;
+
+  return 1;
+}
+
+/* Clean up: close opened files, etc.  */
+
+static void
+finalize (void)
+{
+  /* Language-specific end of compilation actions.  */
+  (*lang_hooks.finish) ();
+}
+
+/* Initialize the compiler, and compile the input file.  */
+static void
+do_compile (void)
+{
+  process_options ();
+
+  /* Don't do any more if an error has already occurred.  */
+  if (!errorcount)
+    {
+      /* Language-dependent initialization.  Returns true on success.  */
+      lang_dependent_init (main_input_filename);
+
+      finalize ();
+    }
+}
+
+/* Entry point of cc1, cc1plus, jc1, f771, etc.
+   Exit code is FATAL_EXIT_CODE if can't open files or if there were
+   any errors, or SUCCESS_EXIT_CODE if compilation succeeded.
+
+   It is not safe to call this function more than once.  */
+
+int
+main (unsigned int argc, const char **argv)
+{
+  /* Initialization of GCC's environment, and diagnostics.  */
+  general_init (argv[0]);
+
+  /* Parse the options and do minimal processing; basically just
+     enough to default flags appropriately.  */
+  decode_options (argc, argv);
+
+  /* Exit early if we can (e.g. -help).  */
+  if (!exit_after_options)
+    do_compile ();
+
+  if (errorcount || sorrycount)
+    return (FATAL_EXIT_CODE);
+
+  return (SUCCESS_EXIT_CODE);
+}
index 0e9b737ce40798b94503ee86dbed3e1fdc6ccb01..a26e2acef24da03d5232d3c73d74a768d5bb9bb8 100644 (file)
@@ -43,7 +43,7 @@ RSC=rc.exe
 # PROP Ignore_Export_Lib 0\r
 # PROP Target_Dir ""\r
 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I ".\libiberty" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /FD /D /GZ "HAVE_CONFIG_H" /c\r
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I ".\libiberty" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /FR /FD /GZ /c\r
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I ".\libiberty" /I ".\win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /FR /FD /GZ /c\r
 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
 # ADD BASE RSC /l 0x409 /d "_DEBUG"\r
@@ -70,7 +70,7 @@ LINK32=link.exe
 # PROP Ignore_Export_Lib 0\r
 # PROP Target_Dir ""\r
 # ADD BASE CPP /nologo /W3 /GX /O2 /I "." /I ".\libiberty" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c\r
-# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".\libiberty" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_WIN32" /FD /c\r
+# ADD CPP /nologo /W3 /GX /O2 /I "." /I ".\libiberty" /I ".\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_WIN32" /FD /c\r
 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
 # ADD BASE RSC /l 0x409 /d "NDEBUG"\r
@@ -93,10 +93,22 @@ LINK32=link.exe
 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
 # Begin Source File\r
 \r
+SOURCE=".\c-incpath.c"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=".\c-ppoutput.c"\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\libiberty\concat.c\r
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\cppcharset.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\cppdefault.c\r
 # End Source File\r
 # Begin Source File\r
@@ -117,6 +129,10 @@ SOURCE=.\cpphash.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\cppinit.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\cpplex.c\r
 # End Source File\r
 # Begin Source File\r
@@ -129,11 +145,23 @@ SOURCE=.\cppmacro.c
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\cppmain.c\r
+SOURCE=.\cpptrad.c\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\cpptrad.c\r
+SOURCE=.\diagnostic.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\win32\dirent.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\libiberty\getpwd.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\hashtab.c\r
 # End Source File\r
 # Begin Source File\r
 \r
@@ -165,19 +193,31 @@ SOURCE=.\libiberty\obstack.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\options.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\opts.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\prefix.c\r
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=".\pretty-print.c"\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=".\libiberty\safe-ctype.c"\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\sdcppinit.c\r
+SOURCE=".\sdcpp-opts.c"\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\sdcppmain.c\r
+SOURCE=.\sdcpp.c\r
 # End Source File\r
 # Begin Source File\r
 \r
@@ -185,6 +225,10 @@ SOURCE=".\libiberty\splay-tree.c"
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\libiberty\vasprintf.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\version.c\r
 # End Source File\r
 # Begin Source File\r
@@ -197,6 +241,10 @@ SOURCE=.\libiberty\xmalloc.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\libiberty\xmemdup.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\libiberty\xstrdup.c\r
 # End Source File\r
 # Begin Source File\r
@@ -217,6 +265,10 @@ SOURCE=".\auto-host.h"
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=".\c-incpath.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\config.h\r
 # End Source File\r
 # Begin Source File\r
@@ -233,6 +285,18 @@ SOURCE=.\cpplib.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\diagnostic.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\win32\dirent.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\hashtab.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\hashtable.h\r
 # End Source File\r
 # Begin Source File\r
@@ -241,6 +305,10 @@ SOURCE=.\hwint.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\input.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\intl.h\r
 # End Source File\r
 # Begin Source File\r
@@ -261,6 +329,14 @@ SOURCE=.\libiberty\obstack.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\options.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\opts.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\output.h\r
 # End Source File\r
 # Begin Source File\r
@@ -269,11 +345,15 @@ SOURCE=.\prefix.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=".\pretty-print.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=".\libiberty\safe-ctype.h"\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\sdcc.h\r
+SOURCE=.\sdcpp.h\r
 # End Source File\r
 # Begin Source File\r
 \r
diff --git a/support/cpp2/sdcpp.h b/support/cpp2/sdcpp.h
new file mode 100644 (file)
index 0000000..38c762d
--- /dev/null
@@ -0,0 +1,254 @@
+#ifndef __SDCPP_H
+#define __SDCPP_H
+
+#ifdef _WIN32
+#include <string.h>
+#define strcasecmp  _stricmp
+#endif
+#define BYTES_BIG_ENDIAN  0
+
+#if defined _MSC_VER || defined __MINGW32__
+/*
+ * The following define causes the following warning:
+ * warning: `I' flag used with `%x' printf format
+ * when copiled with mingw or cygwin -mno-cygwin gcc.
+ * This is correct, because the mingw compilation links against msvcrt.dll,
+ * which uses "I46" for 64 bit integer (long long) printf lenght modifier,
+ * instead of "ll" used by libc.
+ */
+#define PRINTF_INT64_MODIFIER "I64"
+typedef __int64 long_long;
+#else
+#define PRINTF_INT64_MODIFIER "ll"
+typedef long long long_long;
+#endif
+
+/*
+ * From defaults.h
+ */
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(VALUE, NAME) do { (VALUE) = getenv (NAME); } while (0)
+#endif
+
+/* Define results of standard character escape sequences.  */
+#define TARGET_BELL    007
+#define TARGET_BS      010
+#define TARGET_TAB     011
+#define TARGET_NEWLINE 012
+#define TARGET_VT      013
+#define TARGET_FF      014
+#define TARGET_CR      015
+#define TARGET_ESC     033
+
+#define CHAR_TYPE_SIZE 8
+#define WCHAR_TYPE_SIZE 32     /* ? maybe ? */
+
+#define SUPPORTS_ONE_ONLY 0
+
+#define TARGET_OBJECT_SUFFIX ".rel"
+
+#ifndef WCHAR_UNSIGNED
+#define WCHAR_UNSIGNED 0
+#endif
+
+/*
+ * From langhooks.h
+ */
+struct diagnostic_context;
+
+struct lang_hooks
+{
+  /* The first callback made to the front end, for simple
+     initialization needed before any calls to handle_option.  Return
+     the language mask to filter the switch array with.  */
+  unsigned int (*init_options) (unsigned int argc, const char **argv);
+
+  /* Callback used to perform language-specific initialization for the
+     global diagnostic context structure.  */
+  void (*initialize_diagnostics) (struct diagnostic_context *);
+
+  /* Handle the switch CODE, which has real type enum opt_code from
+     options.h.  If the switch takes an argument, it is passed in ARG
+     which points to permanent storage.  The handler is responsible for
+     checking whether ARG is NULL, which indicates that no argument
+     was in fact supplied.  For -f and -W switches, VALUE is 1 or 0
+     for the positive and negative forms respectively.
+
+     Return 1 if the switch is valid, 0 if invalid, and -1 if it's
+     valid and should not be treated as language-independent too.  */
+  int (*handle_option) (size_t code, const char *arg, int value);
+
+  /* Return false to use the default complaint about a missing
+     argument, otherwise output a complaint and return true.  */
+  bool (*missing_argument) (const char *opt, size_t code);
+
+  /* Called when all command line options have been parsed to allow
+     further processing and initialization
+
+     Should return true to indicate that a compiler back-end is
+     not required, such as with the -E option.
+
+     If errorcount is nonzero after this call the compiler exits
+     immediately and the finish hook is not called.  */
+  bool (*post_options) (const char **);
+
+  /* Called after post_options to initialize the front end.  Return
+     false to indicate that no further compilation be performed, in
+     which case the finish hook is called immediately.  */
+  bool (*init) (void);
+
+  /* Called at the end of compilation, as a finalizer.  */
+  void (*finish) (void);
+
+  /* Called by report_error_function to print out function name.  */
+  void (*print_error_function) (struct diagnostic_context *, const char *);
+};
+
+/* Each front end provides its own.  */
+extern const struct lang_hooks lang_hooks;
+
+/*
+ * From toplev.h
+ */
+/* If we haven't already defined a frontend specific diagnostics
+   style, use the generic one.  */
+#ifndef GCC_DIAG_STYLE
+#define GCC_DIAG_STYLE __gcc_diag__
+#endif
+
+/* None of these functions are suitable for ATTRIBUTE_PRINTF, because
+   each language front end can extend them with its own set of format
+   specifiers.  We must use custom format checks.  */
+#if GCC_VERSION >= 3004
+#define ATTRIBUTE_GCC_DIAG(m, n) __attribute__ ((__format__ (GCC_DIAG_STYLE, m, n))) ATTRIBUTE_NONNULL(m)
+#else
+#define ATTRIBUTE_GCC_DIAG(m, n) ATTRIBUTE_NONNULL(m)
+#endif
+extern void warning (const char *, ...);
+extern void error (const char *, ...);
+extern void fatal_error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2)
+     ATTRIBUTE_NORETURN;
+
+#ifdef BUFSIZ
+  /* N.B. Unlike all the others, fnotice is just gettext+fprintf, and
+     therefore it can have ATTRIBUTE_PRINTF.  */
+extern void fnotice                    (FILE *, const char *, ...)
+     ATTRIBUTE_PRINTF_2;
+#endif
+
+extern bool exit_after_options;
+
+extern void print_version (FILE *, const char *);
+
+/* Handle -d switch.  */
+extern void decode_d_option (const char *);
+
+/* Functions used to get and set GCC's notion of in what directory
+   compilation was started.  */
+
+extern const char *get_src_pwd (void);
+extern bool set_src_pwd        (const char *);
+
+/*
+ * From flags.h
+ */
+/* Don't suppress warnings from system headers.  -Wsystem-headers.  */
+
+extern bool warn_system_headers;
+
+/* If -Werror.  */
+
+extern bool warnings_are_errors;
+
+/* Nonzero for -pedantic switch: warn about anything
+   that standard C forbids.  */
+
+/* Temporarily suppress certain warnings.
+   This is set while reading code from a system header file.  */
+
+extern int in_system_header;
+
+/* Nonzero means `char' should be signed.  */
+
+extern int flag_signed_char;
+
+/* Nonzero means change certain warnings into errors.
+   Usually these are warnings about failure to conform to some standard.  */
+
+extern int flag_pedantic_errors;
+
+/* Don't print warning messages.  -w.  */
+
+extern bool inhibit_warnings;
+
+/*
+ * From c-common.h
+ */
+#include "cpplib.h"
+
+/* Nonzero means don't output line number information.  */
+
+extern char flag_no_line_commands;
+
+/* Nonzero causes -E output not to be done, but directives such as
+   #define that have side effects are still obeyed.  */
+
+extern char flag_no_output;
+
+/* Nonzero means dump macros in some fashion; contains the 'D', 'M' or
+   'N' of the command line switch.  */
+
+extern char flag_dump_macros;
+
+/* 0 means we want the preprocessor to not emit line directives for
+   the current working directory.  1 means we want it to do it.  -1
+   means we should decide depending on whether debugging information
+   is being emitted or not.  */
+
+extern int flag_working_directory;
+
+/* Nonzero means warn about usage of long long when `-pedantic'.  */
+
+extern int warn_long_long;
+
+extern int sdcpp_common_handle_option (size_t code, const char *arg, int value);
+extern bool sdcpp_common_missing_argument (const char *opt, size_t code);
+extern unsigned int sdcpp_common_init_options (unsigned int, const char **);
+extern bool sdcpp_common_post_options (const char **);
+extern bool sdcpp_common_init (void);
+extern void sdcpp_common_finish (void);
+
+/* Nonzero means pass #include lines through to the output.  */
+
+char flag_dump_includes;
+
+/* In c-ppoutput.c  */
+extern void init_pp_output (FILE *);
+extern void preprocess_file (cpp_reader *);
+extern void pp_file_change (const struct line_map *);
+extern void pp_dir_change (cpp_reader *, const char *);
+
+/*
+ * From c-pragma.h
+ */
+extern struct cpp_reader* parse_in;
+
+/*
+ * From tree.h
+ */
+#include "input.h"
+
+/* Define the overall contents of a tree node.
+   just to make diagnostic.c happy  */
+
+union tree_node
+{
+  struct tree_decl
+  {
+    location_t locus;
+  } decl;
+};
+
+#define DECL_SOURCE_LOCATION(NODE) ((NODE)->decl.locus)
+
+#endif  /* __SDCPP_H */
diff --git a/support/cpp2/sdcpp.opt b/support/cpp2/sdcpp.opt
new file mode 100644 (file)
index 0000000..d6fe7cf
--- /dev/null
@@ -0,0 +1,344 @@
+; Options for the SDCPP front end.\r
+; Copyright (C) 2003 Free Software Foundation, Inc.\r
+;\r
+; This file is part of GCC.\r
+;\r
+; GCC is free software; you can redistribute it and/or modify it under\r
+; the terms of the GNU General Public License as published by the Free\r
+; Software Foundation; either version 2, or (at your option) any later\r
+; version.\r
+;\r
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY\r
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
+; for more details.\r
+;\r
+; You should have received a copy of the GNU General Public License\r
+; along with GCC; see the file COPYING.  If not, write to the Free\r
+; Software Foundation, 59 Temple Place - Suite 330, Boston, MA\r
+; 02111-1307, USA.\r
+\r
+\r
+; This file is processed by the script opts.sh.  It is a database of\r
+; command line options, with each record separated by a blank line,\r
+; and each field appearing on its own line.  The first field is the\r
+; command-line switch with the leading "-" removed.  All options\r
+; beginning with "f" or "W" are implicitly assumed to take a "no-"\r
+; form; this form should not be listed.  If you do not want this\r
+; negative form and you want it to be automatically rejected, add\r
+; RejectNegative to the second field.\r
+\r
+; The second field is a space-separated list of which parts of the\r
+; compiler recognize the switch, as declared by "Language" entries.\r
+; If the switch takes an argument, then you should also specify\r
+; "Joined" and/or "Separate" to indicate where the argument can\r
+; appear.  If a Joined argument can legitimately be omitted, specify\r
+; "JoinedOrMissing" instead of "Joined".  If the argument to a switch\r
+; is a non-negative integer, you can specify "UInteger" and the switch\r
+; decoder will convert the argument for you, or complain to the user\r
+; if the argument is invalid.\r
+\r
+; The third field is the help text to output with --help.  This is\r
+; automatically line-wrapped on output.  Normally the switch is output\r
+; automatically, with the help text on the right hand side of the\r
+; output.  However, if the help text contains a tab character, the\r
+; text to the left of the tab is output instead of the switch, and the\r
+; text to its right forms the help.  This is useful for elaborating on\r
+; what type of argument a switch takes, for example.  If the second\r
+; field contains "Undocumented" then nothing is output with --help.\r
+; Only do this with good reason like the switch being internal between\r
+; the driver and the front end - it is not an excuse to leave a switch\r
+; undocumented.\r
+\r
+; Comments can appear on their own line anwhere in the file, preceded\r
+; by a semicolon.  Whitespace is permitted before the semicolon.\r
+\r
+; For each switch XXX below, an enumeration constant is created by the\r
+; script opts.sh spelt OPT_XXX, but with all non-alphanumeric\r
+; characters replaced with an underscore.\r
+\r
+; Please try to keep this file in ASCII collating order.\r
+\r
+Language\r
+SDCPP\r
+\r
+-help\r
+Common\r
+Display this information\r
+\r
+-version\r
+Common\r
+Display the compiler's version\r
+\r
+;***-output-pch=\r
+;***SDCPP Joined Separate\r
+\r
+A\r
+SDCPP Joined Separate\r
+-A<question>=<answer>  Assert the <answer> to <question>.  Putting '-' before <question> disables the <answer> to <question>\r
+\r
+C\r
+SDCPP\r
+Do not discard comments\r
+\r
+CC\r
+SDCPP\r
+Do not discard comments in macro expansions\r
+\r
+D\r
+SDCPP Joined Separate\r
+-D<macro>[=<val>]      Define a <macro> with <val> as its value.  If just <macro> is given, <val> is taken to be 1\r
+\r
+H\r
+SDCPP\r
+Print the name of header files as they are used\r
+\r
+I\r
+SDCPP Joined Separate\r
+-I <dir>       Add <dir> to the end of the main include path.  -I- gives more include path control; see info documentation\r
+\r
+M\r
+SDCPP\r
+Generate make dependencies\r
+\r
+MD\r
+SDCPP Separate\r
+Generate make dependencies and compile\r
+\r
+MF\r
+SDCPP Joined Separate\r
+-MF <file>     Write dependency output to the given file\r
+\r
+MG\r
+SDCPP\r
+Treat missing header files as generated files\r
+\r
+MM\r
+SDCPP\r
+Like -M but ignore system header files\r
+\r
+MMD\r
+SDCPP Separate\r
+Like -MD but ignore system header files\r
+\r
+MP\r
+SDCPP\r
+Generate phony targets for all headers\r
+\r
+MQ\r
+SDCPP Joined Separate\r
+-MQ <target>   Add a MAKE-quoted target\r
+\r
+MT\r
+SDCPP Joined Separate\r
+-MT <target>   Add an unquoted target\r
+\r
+P\r
+SDCPP\r
+Do not generate #line directives\r
+\r
+U\r
+SDCPP Joined Separate\r
+-U<macro>      Undefine <macro>\r
+\r
+Wall\r
+SDCPP\r
+Enable most warning messages\r
+\r
+Wcomment\r
+SDCPP\r
+Warn about possibly nested block comments, and C++ comments spanning more than one physical line\r
+\r
+Wcomments\r
+SDCPP\r
+Synonym for -Wcomment\r
+\r
+Wdeprecated\r
+SDCPP\r
+Warn about deprecated compiler features\r
+\r
+Wendif-labels\r
+SDCPP\r
+Warn about stray tokens after #elif and #endif\r
+\r
+Werror\r
+SDCPP\r
+Treat all warnings as errors\r
+\r
+Wimport\r
+SDCPP\r
+Deprecated.  This switch has no effect.\r
+\r
+;***Winvalid-pch\r
+;***SDCPP\r
+;***Warn about PCH files that are found but not used\r
+\r
+Wsystem-headers\r
+SDCPP\r
+Do not suppress warnings from system headers\r
+\r
+Wtrigraphs\r
+SDCPP\r
+Warn if trigraphs are encountered that might affect the meaning of the program\r
+\r
+Wundef\r
+SDCPP\r
+Warn if an undefined macro is used in an #if directive\r
+\r
+Wunused-macros\r
+SDCPP\r
+Warn about macros defined in the main file that are not used\r
+\r
+ansi\r
+SDCPP\r
+A synonym for -std=c89.\r
+\r
+d\r
+SDCPP Joined\r
+-d<letters>    Enable dumps from specific passes of the compiler\r
+\r
+fdollars-in-identifiers\r
+SDCPP\r
+Permit '$' as an identifier character\r
+\r
+fexec-charset=\r
+SDCPP Joined RejectNegative\r
+-fexec-charset=<cset>  Convert all strings and character constants to character set <cset>\r
+\r
+finput-charset=\r
+SDCPP Joined RejectNegative\r
+-finput-charset=<cset>      Specify the default character set for source files.\r
+\r
+;***fpch-deps\r
+;***SDCPP\r
+\r
+fpreprocessed\r
+SDCPP\r
+Treat the input file as already preprocessed\r
+\r
+fshow-column\r
+SDCPP\r
+\r
+fsigned-char\r
+SDCPP\r
+Make \"char\" signed by default\r
+\r
+ftabstop=\r
+SDCPP Joined RejectNegative UInteger\r
+-ftabstop=<number>     Distance between tab stops for column reporting\r
+\r
+funsigned-char\r
+SDCPP\r
+Make \"char\" unsigned by default\r
+\r
+fwide-exec-charset=\r
+SDCPP Joined RejectNegative\r
+-fwide-exec-charset=<cset>     Convert all wide strings and character constants to character set <cset>\r
+\r
+fworking-directory\r
+SDCPP\r
+Generate a #line directive pointing at the current working directory\r
+\r
+idirafter\r
+SDCPP Joined Separate\r
+-idirafter <dir>       Add <dir> to the end of the system include path\r
+\r
+imacros\r
+SDCPP Joined Separate\r
+-imacros <file>        Accept definition of macros in <file>\r
+\r
+include\r
+SDCPP Joined Separate\r
+-include <file>        Include the contents of <file> before other files\r
+\r
+iprefix\r
+SDCPP Joined Separate\r
+-iprefix <path>        Specify <path> as a prefix for next two options\r
+\r
+isysroot\r
+SDCPP Joined Separate\r
+-isysroot <dir>        Set <dir> to be the system root directory\r
+\r
+isystem\r
+SDCPP Joined Separate\r
+-isystem <dir> Add <dir> to the start of the system include path\r
+\r
+iwithprefix\r
+SDCPP Joined Separate\r
+-iwithprefix <dir>     Add <dir> to the end of the system include path\r
+\r
+iwithprefixbefore\r
+SDCPP Joined Separate\r
+-iwithprefixbefore <dir>       Add <dir> to the end of the main include path\r
+\r
+lang-asm\r
+C Undocumented\r
+\r
+lang-objc\r
+SDCPP Undocumented\r
+\r
+nostdinc\r
+SDCPP\r
+Do not search standard system include directories (those specified with -isystem will still be used)\r
+\r
+o\r
+SDCPP Joined Separate\r
+-o <file>      Place output into <file>\r
+\r
+obj-ext=\r
+SDCPP Joined\r
+-obj-ext=<extension>   Define object file extension, used for generation of make dependencies\r
+\r
+pedantic\r
+SDCPP\r
+Issue warnings needed for strict compliance to the standard\r
+\r
+pedantic-errors\r
+SDCPP\r
+Like -pedantic but issue them as errors\r
+\r
+pedantic-parse-number\r
+SDCPP\r
+Pedantic parse number\r
+\r
+remap\r
+SDCPP\r
+Remap file names when including files\r
+\r
+std=c89\r
+SDCPP\r
+Conform to the ISO 1990 C standard\r
+\r
+std=c99\r
+SDCPP\r
+Conform to the ISO 1999 C standard\r
+\r
+std=iso9899:1990\r
+C ObjC\r
+Conform to the ISO 1990 C standard\r
+\r
+std=iso9899:199409\r
+SDCPP\r
+Conform to the ISO 1990 C standard as amended in 1994\r
+\r
+std=iso9899:1999\r
+C ObjC\r
+Conform to the ISO 1999 C standard\r
+\r
+traditional-cpp\r
+SDCPP\r
+Enable traditional preprocessing\r
+\r
+trigraphs\r
+SDCPP\r
+-trigraphs     Support ISO C trigraphs\r
+\r
+v\r
+SDCPP\r
+Enable verbose output\r
+\r
+w\r
+SDCPP\r
+Suppress warnings\r
+\r
+; This comment is to ensure we retain the blank line above.\r
diff --git a/support/cpp2/sdcppinit.c b/support/cpp2/sdcppinit.c
deleted file mode 100644 (file)
index 6b5551f..0000000
+++ /dev/null
@@ -1,1938 +0,0 @@
-/* CPP Library.
-   Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
-   Contributed by Per Bothner, 1994-95.
-   Based on CCCP program by Paul Rubin, June 1986
-   Adapted to ANSI C, Richard Stallman, Jan 1987
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
-
-#include "config.h"
-#include "system.h"
-#include "cpplib.h"
-#include "cpphash.h"
-#include "prefix.h"
-#include "version.h"
-#include "intl.h"
-#include "mkdeps.h"
-#include "cppdefault.h"
-
-/* Windows does not natively support inodes, and neither does MSDOS.
-   Cygwin's emulation can generate non-unique inodes, so don't use it.
-   VMS has non-numeric inodes.  */
-#ifdef VMS
-# define INO_T_EQ(A, B) (!memcmp (&(A), &(B), sizeof (A)))
-# define INO_T_COPY(DEST, SRC) memcpy(&(DEST), &(SRC), sizeof (SRC))
-#else
-# if (defined _WIN32 && ! defined (_UWIN)) || defined __MSDOS__
-#  define INO_T_EQ(A, B) 0
-# else
-#  define INO_T_EQ(A, B) ((A) == (B))
-# endif
-# define INO_T_COPY(DEST, SRC) (DEST) = (SRC)
-#endif
-
-/* Internal structures and prototypes.  */
-
-/* A `struct pending_option' remembers one -D, -A, -U, -include, or
-   -imacros switch.  */
-typedef void (* cl_directive_handler) PARAMS ((cpp_reader *, const char *));
-struct pending_option
-{
-  struct pending_option *next;
-  const char *arg;
-  cl_directive_handler handler;
-};
-
-/* The `pending' structure accumulates all the options that are not
-   actually processed until we hit cpp_read_main_file.  It consists of
-   several lists, one for each type of option.  We keep both head and
-   tail pointers for quick insertion.  */
-struct cpp_pending
-{
-  struct pending_option *directive_head, *directive_tail;
-
-  struct search_path *quote_head, *quote_tail;
-  struct search_path *brack_head, *brack_tail;
-  struct search_path *systm_head, *systm_tail;
-  struct search_path *after_head, *after_tail;
-
-  struct pending_option *imacros_head, *imacros_tail;
-  struct pending_option *include_head, *include_tail;
-};
-
-#ifdef __STDC__
-#define APPEND(pend, list, elt) \
-  do {  if (!(pend)->list##_head) (pend)->list##_head = (elt); \
-       else (pend)->list##_tail->next = (elt); \
-       (pend)->list##_tail = (elt); \
-  } while (0)
-#else
-#define APPEND(pend, list, elt) \
-  do {  if (!(pend)->list/**/_head) (pend)->list/**/_head = (elt); \
-       else (pend)->list/**/_tail->next = (elt); \
-       (pend)->list/**/_tail = (elt); \
-  } while (0)
-#endif
-
-static void print_help                  PARAMS ((void));
-static void path_include               PARAMS ((cpp_reader *,
-                                                char *, int));
-static void init_library               PARAMS ((void));
-static void init_builtins              PARAMS ((cpp_reader *));
-static void mark_named_operators       PARAMS ((cpp_reader *));
-static void append_include_chain       PARAMS ((cpp_reader *,
-                                                char *, int, int));
-static struct search_path * remove_dup_dir     PARAMS ((cpp_reader *,
-                                                struct search_path *,
-                                                struct search_path **));
-static struct search_path * remove_dup_nonsys_dirs PARAMS ((cpp_reader *,
-                                                struct search_path **,
-                                                struct search_path *));
-static struct search_path * remove_dup_dirs PARAMS ((cpp_reader *,
-                                                struct search_path **));
-static void merge_include_chains       PARAMS ((cpp_reader *));
-static bool push_include               PARAMS ((cpp_reader *,
-                                                struct pending_option *));
-static void free_chain                 PARAMS ((struct pending_option *));
-static void init_standard_includes     PARAMS ((cpp_reader *));
-static void read_original_filename     PARAMS ((cpp_reader *));
-static void new_pending_directive      PARAMS ((struct cpp_pending *,
-                                                const char *,
-                                                cl_directive_handler));
-static int parse_option                        PARAMS ((const char *));
-static void post_options               PARAMS ((cpp_reader *));
-
-/* Fourth argument to append_include_chain: chain to use.
-   Note it's never asked to append to the quote chain.  */
-enum { BRACKET = 0, SYSTEM, AFTER };
-
-/* If we have designated initializers (GCC >2.7) these tables can be
-   initialized, constant data.  Otherwise, they have to be filled in at
-   runtime.  */
-#if HAVE_DESIGNATED_INITIALIZERS
-
-#define init_trigraph_map()  /* Nothing.  */
-#define TRIGRAPH_MAP \
-__extension__ const uchar _cpp_trigraph_map[UCHAR_MAX + 1] = {
-
-#define END };
-#define s(p, v) [p] = v,
-
-#else
-
-#define TRIGRAPH_MAP uchar _cpp_trigraph_map[UCHAR_MAX + 1] = { 0 }; \
- static void init_trigraph_map PARAMS ((void)) { \
- unsigned char *x = _cpp_trigraph_map;
-
-#define END }
-#define s(p, v) x[p] = v;
-
-#endif
-
-TRIGRAPH_MAP
-  s('=', '#')  s(')', ']')     s('!', '|')
-  s('(', '[')  s('\'', '^')    s('>', '}')
-  s('/', '\\') s('<', '{')     s('-', '~')
-END
-
-#undef s
-#undef END
-#undef TRIGRAPH_MAP
-
-/* Given a colon-separated list of file names PATH,
-   add all the names to the search path for include files.  */
-static void
-path_include (pfile, list, path)
-     cpp_reader *pfile;
-     char *list;
-     int path;
-{
-  char *p, *q, *name;
-
-  p = list;
-
-  do
-    {
-      /* Find the end of this name.  */
-      q = p;
-      while (*q != 0 && *q != PATH_SEPARATOR) q++;
-      if (q == p)
-       {
-         /* An empty name in the path stands for the current directory.  */
-         name = (char *) xmalloc (2);
-         name[0] = '.';
-         name[1] = 0;
-       }
-      else
-       {
-         /* Otherwise use the directory that is named.  */
-         name = (char *) xmalloc (q - p + 1);
-         memcpy (name, p, q - p);
-         name[q - p] = 0;
-       }
-
-      append_include_chain (pfile, name, path, path == SYSTEM);
-
-      /* Advance past this name.  */
-      if (*q == 0)
-       break;
-      p = q + 1;
-    }
-  while (1);
-}
-
-/* Append DIR to include path PATH.  DIR must be allocated on the
-   heap; this routine takes responsibility for freeing it.  CXX_AWARE
-   is nonzero if the header contains extern "C" guards for C++,
-   otherwise it is zero.  */
-static void
-append_include_chain (pfile, dir, path, cxx_aware)
-     cpp_reader *pfile;
-     char *dir;
-     int path;
-     int cxx_aware;
-{
-  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
-  struct search_path *new;
-  struct stat st;
-  unsigned int len;
-
-  if (*dir == '\0')
-    {
-      free (dir);
-      dir = xstrdup (".");
-    }
-  _cpp_simplify_pathname (dir);
-
-  if (stat (dir, &st))
-    {
-      /* Dirs that don't exist are silently ignored.  */
-      if (errno != ENOENT)
-       cpp_errno (pfile, DL_ERROR, dir);
-      else if (CPP_OPTION (pfile, verbose))
-       fprintf (stderr, _("ignoring nonexistent directory \"%s\"\n"), dir);
-      free (dir);
-      return;
-    }
-
-  if (!S_ISDIR (st.st_mode))
-    {
-      cpp_error_with_line (pfile, DL_ERROR, 0, 0, "%s: Not a directory", dir);
-      free (dir);
-      return;
-    }
-
-  len = strlen (dir);
-  if (len > pfile->max_include_len)
-    pfile->max_include_len = len;
-
-  new = (struct search_path *) xmalloc (sizeof (struct search_path));
-  new->name = dir;
-  new->len = len;
-  INO_T_COPY (new->ino, st.st_ino);
-  new->dev  = st.st_dev;
-  /* Both systm and after include file lists should be treated as system
-     include files since these two lists are really just a concatenation
-     of one "system" list.  */
-  if (path == SYSTEM || path == AFTER)
-    new->sysp = cxx_aware ? 1 : 2;
-  else
-    new->sysp = 0;
-  new->name_map = NULL;
-  new->next = NULL;
-
-  switch (path)
-    {
-    case BRACKET:      APPEND (pend, brack, new); break;
-    case SYSTEM:       APPEND (pend, systm, new); break;
-    case AFTER:                APPEND (pend, after, new); break;
-    }
-}
-
-/* Handle a duplicated include path.  PREV is the link in the chain
-   before the duplicate, or NULL if the duplicate is at the head of
-   the chain.  The duplicate is removed from the chain and freed.
-   Returns PREV.  */
-static struct search_path *
-remove_dup_dir (pfile, prev, head_ptr)
-     cpp_reader *pfile;
-     struct search_path *prev;
-     struct search_path **head_ptr;
-{
-  struct search_path *cur;
-
-  if (prev != NULL)
-    {
-      cur = prev->next;
-      prev->next = cur->next;
-    }
-  else
-    {
-      cur = *head_ptr;
-      *head_ptr = cur->next;
-    }
-
-  if (CPP_OPTION (pfile, verbose))
-    fprintf (stderr, _("ignoring duplicate directory \"%s\"\n"), cur->name);
-
-  free ((PTR) cur->name);
-  free (cur);
-
-  return prev;
-}
-
-/* Remove duplicate non-system directories for which there is an equivalent
-   system directory latter in the chain.  The range for removal is between
-   *HEAD_PTR and END.  Returns the directory before END, or NULL if none.
-   This algorithm is quadratic in the number system directories, which is
-   acceptable since there aren't usually that many of them.  */
-static struct search_path *
-remove_dup_nonsys_dirs (pfile, head_ptr, end)
-     cpp_reader *pfile;
-     struct search_path **head_ptr;
-     struct search_path *end;
-{
-  int sysdir = 0;
-  struct search_path *prev = NULL, *cur, *other;
-
-  for (cur = *head_ptr; cur; cur = cur->next)
-    {
-      if (cur->sysp)
-       {
-         sysdir = 1;
-         for (other = *head_ptr, prev = NULL;
-              other != end;
-              other = other ? other->next : *head_ptr)
-           {
-             if (!other->sysp
-                 && INO_T_EQ (cur->ino, other->ino)
-                 && cur->dev == other->dev)
-               {
-                 other = remove_dup_dir (pfile, prev, head_ptr);
-                 if (CPP_OPTION (pfile, verbose))
-                   fprintf (stderr,
-  _("  as it is a non-system directory that duplicates a system directory\n"));
-               }
-             prev = other;
-           }
-       }
-    }
-
-  if (!sysdir)
-    for (cur = *head_ptr; cur != end; cur = cur->next)
-      prev = cur;
-
-  return prev;
-}
-
-/* Remove duplicate directories from a chain.  Returns the tail of the
-   chain, or NULL if the chain is empty.  This algorithm is quadratic
-   in the number of -I switches, which is acceptable since there
-   aren't usually that many of them.  */
-static struct search_path *
-remove_dup_dirs (pfile, head_ptr)
-     cpp_reader *pfile;
-     struct search_path **head_ptr;
-{
-  struct search_path *prev = NULL, *cur, *other;
-
-  for (cur = *head_ptr; cur; cur = cur->next)
-    {
-      for (other = *head_ptr; other != cur; other = other->next)
-       if (INO_T_EQ (cur->ino, other->ino) && cur->dev == other->dev)
-         {
-           cur = remove_dup_dir (pfile, prev, head_ptr);
-           break;
-         }
-      prev = cur;
-    }
-
-  return prev;
-}
-
-/* Merge the four include chains together in the order quote, bracket,
-   system, after.  Remove duplicate dirs (as determined by
-   INO_T_EQ()).  The system_include and after_include chains are never
-   referred to again after this function; all access is through the
-   bracket_include path.  */
-static void
-merge_include_chains (pfile)
-     cpp_reader *pfile;
-{
-  struct search_path *quote, *brack, *systm, *qtail;
-
-  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
-
-  quote = pend->quote_head;
-  brack = pend->brack_head;
-  systm = pend->systm_head;
-  qtail = pend->quote_tail;
-
-  /* Paste together bracket, system, and after include chains.  */
-  if (systm)
-    pend->systm_tail->next = pend->after_head;
-  else
-    systm = pend->after_head;
-
-  if (brack)
-    pend->brack_tail->next = systm;
-  else
-    brack = systm;
-
-  /* This is a bit tricky.  First we drop non-system dupes of system
-     directories from the merged bracket-include list.  Next we drop
-     dupes from the bracket and quote include lists.  Then we drop
-     non-system dupes from the merged quote-include list.  Finally,
-     if qtail and brack are the same directory, we cut out brack and
-     move brack up to point to qtail.
-
-     We can't just merge the lists and then uniquify them because
-     then we may lose directories from the <> search path that should
-     be there; consider -Ifoo -Ibar -I- -Ifoo -Iquux.  It is however
-     safe to treat -Ibar -Ifoo -I- -Ifoo -Iquux as if written
-     -Ibar -I- -Ifoo -Iquux.  */
-
-  remove_dup_nonsys_dirs (pfile, &brack, systm);
-  remove_dup_dirs (pfile, &brack);
-
-  if (quote)
-    {
-      qtail = remove_dup_dirs (pfile, &quote);
-      qtail->next = brack;
-
-      qtail = remove_dup_nonsys_dirs (pfile, &quote, brack);
-
-      /* If brack == qtail, remove brack as it's simpler.  */
-      if (qtail && brack && INO_T_EQ (qtail->ino, brack->ino)
-         && qtail->dev == brack->dev)
-       brack = remove_dup_dir (pfile, qtail, &quote);
-    }
-  else
-    quote = brack;
-
-  CPP_OPTION (pfile, quote_include) = quote;
-  CPP_OPTION (pfile, bracket_include) = brack;
-}
-
-/* A set of booleans indicating what CPP features each source language
-   requires.  */
-struct lang_flags
-{
-  char c99;
-  char cplusplus;
-  char extended_numbers;
-  char std;
-  char dollars_in_ident;
-  char cplusplus_comments;
-  char digraphs;
-};
-
-/* ??? Enable $ in identifiers in assembly? */
-static const struct lang_flags lang_defaults[] =
-{ /*              c99 c++ xnum std dollar c++comm digr  */
-  /* GNUC89 */  { 0,  0,  1,   0,   1,     1,      1     },
-  /* GNUC99 */  { 1,  0,  1,   0,   1,     1,      1     },
-  /* STDC89 */  { 0,  0,  0,   1,   0,     0,      0     },
-  /* STDC94 */  { 0,  0,  0,   1,   0,     0,      1     },
-  /* STDC99 */  { 1,  0,  1,   1,   0,     1,      1     },
-  /* GNUCXX */  { 0,  1,  1,   0,   1,     1,      1     },
-  /* CXX98  */  { 0,  1,  1,   1,   0,     1,      1     },
-  /* ASM    */  { 0,  0,  1,   0,   0,     1,      0     }
-};
-
-/* Sets internal flags correctly for a given language.  */
-void
-cpp_set_lang (pfile, lang)
-     cpp_reader *pfile;
-     enum c_lang lang;
-{
-  const struct lang_flags *l = &lang_defaults[(int) lang];
-
-  CPP_OPTION (pfile, lang) = lang;
-
-  CPP_OPTION (pfile, c99)               = l->c99;
-  CPP_OPTION (pfile, cplusplus)                 = l->cplusplus;
-  CPP_OPTION (pfile, extended_numbers)  = l->extended_numbers;
-  CPP_OPTION (pfile, std)               = l->std;
-  CPP_OPTION (pfile, trigraphs)                 = l->std;
-  CPP_OPTION (pfile, dollars_in_ident)  = l->dollars_in_ident;
-  CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments;
-  CPP_OPTION (pfile, digraphs)          = l->digraphs;
-}
-
-#ifdef HOST_EBCDIC
-static int opt_comp PARAMS ((const void *, const void *));
-
-/* Run-time sorting of options array.  */
-static int
-opt_comp (p1, p2)
-     const void *p1, *p2;
-{
-  return strcmp (((struct cl_option *) p1)->opt_text,
-                ((struct cl_option *) p2)->opt_text);
-}
-#endif
-
-/* init initializes library global state.  It might not need to
-   do anything depending on the platform and compiler.  */
-static void
-init_library ()
-{
-  static int initialized = 0;
-
-  if (! initialized)
-    {
-      initialized = 1;
-
-#ifdef HOST_EBCDIC
-      /* For non-ASCII hosts, the cl_options array needs to be sorted at
-        runtime.  */
-      qsort (cl_options, N_OPTS, sizeof (struct cl_option), opt_comp);
-#endif
-
-      /* Set up the trigraph map.  This doesn't need to do anything if
-        we were compiled with a compiler that supports C99 designated
-        initializers.  */
-      init_trigraph_map ();
-    }
-}
-
-/* Initialize a cpp_reader structure.  */
-cpp_reader *
-cpp_create_reader (lang)
-     enum c_lang lang;
-{
-  cpp_reader *pfile;
-
-  /* Initialize this instance of the library if it hasn't been already.  */
-  init_library ();
-
-  pfile = (cpp_reader *) xcalloc (1, sizeof (cpp_reader));
-
-  cpp_set_lang (pfile, lang);
-  CPP_OPTION (pfile, warn_import) = 1;
-  CPP_OPTION (pfile, warn_multichar) = 1;
-  CPP_OPTION (pfile, discard_comments) = 1;
-  CPP_OPTION (pfile, discard_comments_in_macro_exp) = 1;
-  CPP_OPTION (pfile, show_column) = 1;
-  CPP_OPTION (pfile, tabstop) = 8;
-  CPP_OPTION (pfile, operator_names) = 1;
-  CPP_OPTION (pfile, warn_endif_labels) = 1;
-  CPP_OPTION (pfile, warn_long_long) = !CPP_OPTION (pfile, c99);
-  CPP_OPTION (pfile, sysroot) = cpp_SYSROOT;
-  /* SDCC _asm specific */
-  CPP_OPTION (pfile, preproc_asm) = 1;
-
-  CPP_OPTION (pfile, pending) =
-    (struct cpp_pending *) xcalloc (1, sizeof (struct cpp_pending));
-
-  /* Default CPP arithmetic to something sensible for the host for the
-     benefit of dumb users like fix-header.  */
-  CPP_OPTION (pfile, precision) = CHAR_BIT * sizeof (long);
-  CPP_OPTION (pfile, char_precision) = CHAR_BIT;
-  CPP_OPTION (pfile, wchar_precision) = CHAR_BIT * sizeof (int);
-  CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int);
-  CPP_OPTION (pfile, unsigned_char) = 0;
-  CPP_OPTION (pfile, unsigned_wchar) = 1;
-
-  /* Initialize the line map.  Start at logical line 1, so we can use
-     a line number of zero for special states.  */
-  init_line_maps (&pfile->line_maps);
-  pfile->line = 1;
-
-  /* Initialize lexer state.  */
-  pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
-
-  /* Set up static tokens.  */
-  pfile->avoid_paste.type = CPP_PADDING;
-  pfile->avoid_paste.val.source = NULL;
-  pfile->eof.type = CPP_EOF;
-  pfile->eof.flags = 0;
-
-  /* Create a token buffer for the lexer.  */
-  _cpp_init_tokenrun (&pfile->base_run, 250);
-  pfile->cur_run = &pfile->base_run;
-  pfile->cur_token = pfile->base_run.base;
-
-  /* Initialize the base context.  */
-  pfile->context = &pfile->base_context;
-  pfile->base_context.macro = 0;
-  pfile->base_context.prev = pfile->base_context.next = 0;
-
-  /* Aligned and unaligned storage.  */
-  pfile->a_buff = _cpp_get_buff (pfile, 0);
-  pfile->u_buff = _cpp_get_buff (pfile, 0);
-
-  /* The expression parser stack.  */
-  _cpp_expand_op_stack (pfile);
-
-  /* Initialize the buffer obstack.  */
-  gcc_obstack_init (&pfile->buffer_ob);
-
-  _cpp_init_includes (pfile);
-
-  return pfile;
-}
-
-/* Free resources used by PFILE.  Accessing PFILE after this function
-   returns leads to undefined behavior.  Returns the error count.  */
-void
-cpp_destroy (pfile)
-     cpp_reader *pfile;
-{
-  struct search_path *dir, *dirn;
-  cpp_context *context, *contextn;
-  tokenrun *run, *runn;
-
-  free_chain (CPP_OPTION (pfile, pending)->include_head);
-  free (CPP_OPTION (pfile, pending));
-  free (pfile->op_stack);
-
-  while (CPP_BUFFER (pfile) != NULL)
-    _cpp_pop_buffer (pfile);
-
-  if (pfile->out.base)
-    free (pfile->out.base);
-
-  if (pfile->macro_buffer)
-    {
-      free ((PTR) pfile->macro_buffer);
-      pfile->macro_buffer = NULL;
-      pfile->macro_buffer_len = 0;
-    }
-
-  if (pfile->deps)
-    deps_free (pfile->deps);
-  obstack_free (&pfile->buffer_ob, 0);
-
-  _cpp_destroy_hashtable (pfile);
-  _cpp_cleanup_includes (pfile);
-
-  _cpp_free_buff (pfile->a_buff);
-  _cpp_free_buff (pfile->u_buff);
-  _cpp_free_buff (pfile->free_buffs);
-
-  for (run = &pfile->base_run; run; run = runn)
-    {
-      runn = run->next;
-      free (run->base);
-      if (run != &pfile->base_run)
-       free (run);
-    }
-
-  for (dir = CPP_OPTION (pfile, quote_include); dir; dir = dirn)
-    {
-      dirn = dir->next;
-      free ((PTR) dir->name);
-      free (dir);
-    }
-
-  for (context = pfile->base_context.next; context; context = contextn)
-    {
-      contextn = context->next;
-      free (context);
-    }
-
-  free_line_maps (&pfile->line_maps);
-  free (pfile);
-}
-
-/* This structure defines one built-in identifier.  A node will be
-   entered in the hash table under the name NAME, with value VALUE.
-
-   There are two tables of these.  builtin_array holds all the
-   "builtin" macros: these are handled by builtin_macro() in
-   cppmacro.c.  Builtin is somewhat of a misnomer -- the property of
-   interest is that these macros require special code to compute their
-   expansions.  The value is a "builtin_type" enumerator.
-
-   operator_array holds the C++ named operators.  These are keywords
-   which act as aliases for punctuators.  In C++, they cannot be
-   altered through #define, and #if recognizes them as operators.  In
-   C, these are not entered into the hash table at all (but see
-   <iso646.h>).  The value is a token-type enumerator.  */
-struct builtin
-{
-  const uchar *name;
-  unsigned short len;
-  unsigned short value;
-};
-
-#define B(n, t)    { DSC(n), t }
-static const struct builtin builtin_array[] =
-{
-  B("__TIME__",                 BT_TIME),
-  B("__DATE__",                 BT_DATE),
-  B("__FILE__",                 BT_FILE),
-  B("__BASE_FILE__",    BT_BASE_FILE),
-  B("__LINE__",                 BT_SPECLINE),
-  B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL),
-  /* Keep builtins not used for -traditional-cpp at the end, and
-     update init_builtins() if any more are added.  */
-  B("_Pragma",          BT_PRAGMA),
-  B("__STDC__",                 BT_STDC),
-};
-
-static const struct builtin operator_array[] =
-{
-  B("and",     CPP_AND_AND),
-  B("and_eq",  CPP_AND_EQ),
-  B("bitand",  CPP_AND),
-  B("bitor",   CPP_OR),
-  B("compl",   CPP_COMPL),
-  B("not",     CPP_NOT),
-  B("not_eq",  CPP_NOT_EQ),
-  B("or",      CPP_OR_OR),
-  B("or_eq",   CPP_OR_EQ),
-  B("xor",     CPP_XOR),
-  B("xor_eq",  CPP_XOR_EQ)
-};
-#undef B
-
-/* Mark the C++ named operators in the hash table.  */
-static void
-mark_named_operators (pfile)
-     cpp_reader *pfile;
-{
-  const struct builtin *b;
-
-  for (b = operator_array;
-       b < (operator_array + ARRAY_SIZE (operator_array));
-       b++)
-    {
-      cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
-      hp->flags |= NODE_OPERATOR;
-      hp->value.operator = b->value;
-    }
-}
-
-/* Subroutine of cpp_read_main_file; reads the builtins table above and
-   enters them, and language-specific macros, into the hash table.  */
-static void
-init_builtins (pfile)
-     cpp_reader *pfile;
-{
-  const struct builtin *b;
-  size_t n = ARRAY_SIZE (builtin_array);
-
-  if (CPP_OPTION (pfile, traditional))
-    n -= 2;
-
-  for(b = builtin_array; b < builtin_array + n; b++)
-    {
-      cpp_hashnode *hp = cpp_lookup (pfile, b->name, b->len);
-      hp->type = NT_MACRO;
-      hp->flags |= NODE_BUILTIN | NODE_WARN;
-      hp->value.builtin = b->value;
-    }
-
-  if (CPP_OPTION (pfile, cplusplus))
-    _cpp_define_builtin (pfile, "__cplusplus 1");
-  else if (CPP_OPTION (pfile, lang) == CLK_ASM)
-    _cpp_define_builtin (pfile, "__ASSEMBLER__ 1");
-  else if (CPP_OPTION (pfile, lang) == CLK_STDC94)
-    _cpp_define_builtin (pfile, "__STDC_VERSION__ 199409L");
-  else if (CPP_OPTION (pfile, c99))
-    _cpp_define_builtin (pfile, "__STDC_VERSION__ 199901L");
-
-  if (CPP_OPTION (pfile, objc))
-    _cpp_define_builtin (pfile, "__OBJC__ 1");
-
-  if (pfile->cb.register_builtins)
-    (*pfile->cb.register_builtins) (pfile);
-}
-
-/* And another subroutine.  This one sets up the standard include path.  */
-static void
-init_standard_includes (pfile)
-     cpp_reader *pfile;
-{
-  char *path;
-  const struct default_include *p;
-  const char *specd_prefix = CPP_OPTION (pfile, include_prefix);
-
-  /* Several environment variables may add to the include search path.
-     CPATH specifies an additional list of directories to be searched
-     as if specified with -I, while C_INCLUDE_PATH, CPLUS_INCLUDE_PATH,
-     etc. specify an additional list of directories to be searched as
-     if specified with -isystem, for the language indicated.  */
-
-  GET_ENVIRONMENT (path, "CPATH");
-  if (path != 0 && *path != 0)
-    path_include (pfile, path, BRACKET);
-
-  switch ((CPP_OPTION (pfile, objc) << 1) + CPP_OPTION (pfile, cplusplus))
-    {
-    case 0:
-      GET_ENVIRONMENT (path, "C_INCLUDE_PATH");
-      break;
-    case 1:
-      GET_ENVIRONMENT (path, "CPLUS_INCLUDE_PATH");
-      break;
-    case 2:
-      GET_ENVIRONMENT (path, "OBJC_INCLUDE_PATH");
-      break;
-    case 3:
-      GET_ENVIRONMENT (path, "OBJCPLUS_INCLUDE_PATH");
-      break;
-    }
-  if (path != 0 && *path != 0)
-    path_include (pfile, path, SYSTEM);
-
-  /* Search "translated" versions of GNU directories.
-     These have /usr/local/lib/gcc... replaced by specd_prefix.  */
-  if (specd_prefix != 0 && cpp_GCC_INCLUDE_DIR_len)
-    {
-      /* Remove the `include' from /usr/local/lib/gcc.../include.
-        GCC_INCLUDE_DIR will always end in /include.  */
-      int default_len = cpp_GCC_INCLUDE_DIR_len;
-      char *default_prefix = (char *) alloca (default_len + 1);
-      int specd_len = strlen (specd_prefix);
-
-      memcpy (default_prefix, cpp_GCC_INCLUDE_DIR, default_len);
-      default_prefix[default_len] = '\0';
-
-      for (p = cpp_include_defaults; p->fname; p++)
-       {
-         /* Some standard dirs are only for C++.  */
-         if (!p->cplusplus
-             || (CPP_OPTION (pfile, cplusplus)
-                 && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
-           {
-             /* Should we be translating sysrooted dirs too?  Assume
-                that iprefix and sysroot are mutually exclusive, for
-                now.  */
-             if (p->add_sysroot && CPP_OPTION (pfile, sysroot)
-                 && *(CPP_OPTION (pfile, sysroot)))
-               continue;
-
-              /* Does this dir start with the prefix?  */
-             if (!strncmp (p->fname, default_prefix, default_len))
-               {
-                 /* Yes; change prefix and add to search list.  */
-                 int flen = strlen (p->fname);
-                 int this_len = specd_len + flen - default_len;
-
-                  char *str = (char *) xmalloc (this_len + 1);
-                 memcpy (str, specd_prefix, specd_len);
-                 memcpy (str + specd_len,
-                         p->fname + default_len,
-                         flen - default_len + 1);
-
-                 append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
-               }
-           }
-       }
-    }
-
-  for (p = cpp_include_defaults; p->fname; p++)
-    {
-      /* Some standard dirs are only for C++.  */
-      if (!p->cplusplus
-         || (CPP_OPTION (pfile, cplusplus)
-             && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
-       {
-         char *str;
-
-         /* Should this dir start with the sysroot?  */
-         if (p->add_sysroot && CPP_OPTION (pfile, sysroot)
-             && *(CPP_OPTION (pfile, sysroot)))
-           str = concat (CPP_OPTION (pfile, sysroot), p->fname, NULL);
-
-         else
-           str = update_path (p->fname, p->component);
-
-         append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
-       }
-    }
-}
-
-/* Pushes a command line -imacro and -include file indicated by P onto
-   the buffer stack.  Returns nonzero if successful.  */
-static bool
-push_include (pfile, p)
-     cpp_reader *pfile;
-     struct pending_option *p;
-{
-  cpp_token header;
-
-  /* Later: maybe update this to use the #include "" search path
-     if cpp_read_file fails.  */
-  header.type = CPP_STRING;
-  header.val.str.text = (const unsigned char *) p->arg;
-  header.val.str.len = strlen (p->arg);
-  /* Make the command line directive take up a line.  */
-  pfile->line++;
-
-  return _cpp_execute_include (pfile, &header, IT_CMDLINE);
-}
-
-/* Frees a pending_option chain.  */
-static void
-free_chain (head)
-     struct pending_option *head;
-{
-  struct pending_option *next;
-
-  while (head)
-    {
-      next = head->next;
-      free (head);
-      head = next;
-    }
-}
-
-/* Sanity-checks are dependent on command-line options, so it is
-   called as a subroutine of cpp_read_main_file ().  */
-#if ENABLE_CHECKING
-static void sanity_checks PARAMS ((cpp_reader *));
-static void sanity_checks (pfile)
-     cpp_reader *pfile;
-{
-  cppchar_t test = 0;
-  size_t max_precision = 2 * CHAR_BIT * sizeof (cpp_num_part);
-
-  /* Sanity checks for assumptions about CPP arithmetic and target
-     type precisions made by cpplib.  */
-  test--;
-  if (test < 1)
-    cpp_error (pfile, DL_ICE, "cppchar_t must be an unsigned type");
-
-  if (CPP_OPTION (pfile, precision) > max_precision)
-    cpp_error (pfile, DL_ICE,
-              "preprocessor arithmetic has maximum precision of %lu bits; target requires %lu bits",
-              (unsigned long) max_precision,
-              (unsigned long) CPP_OPTION (pfile, precision));
-
-  if (CPP_OPTION (pfile, precision) < CPP_OPTION (pfile, int_precision))
-    cpp_error (pfile, DL_ICE,
-              "CPP arithmetic must be at least as precise as a target int");
-
-  if (CPP_OPTION (pfile, char_precision) < 8)
-    cpp_error (pfile, DL_ICE, "target char is less than 8 bits wide");
-
-  if (CPP_OPTION (pfile, wchar_precision) < CPP_OPTION (pfile, char_precision))
-    cpp_error (pfile, DL_ICE,
-              "target wchar_t is narrower than target char");
-
-  if (CPP_OPTION (pfile, int_precision) < CPP_OPTION (pfile, char_precision))
-    cpp_error (pfile, DL_ICE,
-              "target int is narrower than target char");
-
-  /* This is assumed in eval_token() and could be fixed if necessary.  */
-  if (sizeof (cppchar_t) > sizeof (cpp_num_part))
-    cpp_error (pfile, DL_ICE, "CPP half-integer narrower than CPP character");
-
-  if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T)
-    cpp_error (pfile, DL_ICE,
-              "CPP on this host cannot handle wide character constants over %lu bits, but the target requires %lu bits",
-              (unsigned long) BITS_PER_CPPCHAR_T,
-              (unsigned long) CPP_OPTION (pfile, wchar_precision));
-}
-#else
-# define sanity_checks(PFILE)
-#endif
-
-/* Add a dependency target.  Can be called any number of times before
-   cpp_read_main_file().  If no targets have been added before
-   cpp_read_main_file(), then the default target is used.  */
-void
-cpp_add_dependency_target (pfile, target, quote)
-     cpp_reader *pfile;
-     const char *target;
-     int quote;
-{
-  if (!pfile->deps)
-    pfile->deps = deps_init ();
-
-  deps_add_target (pfile->deps, target, quote);
-}
-
-/* This is called after options have been parsed, and partially
-   processed.  Setup for processing input from the file named FNAME,
-   or stdin if it is the empty string.  Return the original filename
-   on success (e.g. foo.i->foo.c), or NULL on failure.  */
-const char *
-cpp_read_main_file (pfile, fname, table)
-     cpp_reader *pfile;
-     const char *fname;
-     hash_table *table;
-{
-  sanity_checks (pfile);
-
-  post_options (pfile);
-
-  /* The front ends don't set up the hash table until they have
-     finished processing the command line options, so initializing the
-     hashtable is deferred until now.  */
-  _cpp_init_hashtable (pfile, table);
-
-  /* Set up the include search path now.  */
-  if (! CPP_OPTION (pfile, no_standard_includes))
-    init_standard_includes (pfile);
-
-  merge_include_chains (pfile);
-
-  /* With -v, print the list of dirs to search.  */
-  if (CPP_OPTION (pfile, verbose))
-    {
-      struct search_path *l;
-      fprintf (stderr, _("#include \"...\" search starts here:\n"));
-      for (l = CPP_OPTION (pfile, quote_include); l; l = l->next)
-       {
-         if (l == CPP_OPTION (pfile, bracket_include))
-           fprintf (stderr, _("#include <...> search starts here:\n"));
-         fprintf (stderr, " %s\n", l->name);
-       }
-      fprintf (stderr, _("End of search list.\n"));
-    }
-
-  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE)
-    {
-      if (!pfile->deps)
-       pfile->deps = deps_init ();
-
-      /* Set the default target (if there is none already).  */
-      deps_add_default_target (pfile, fname);
-    }
-
-  /* Open the main input file.  */
-  if (!_cpp_read_file (pfile, fname))
-    return NULL;
-
-  /* Set this here so the client can change the option if it wishes,
-     and after stacking the main file so we don't trace the main
-     file.  */
-  pfile->line_maps.trace_includes = CPP_OPTION (pfile, print_include_names);
-
-  /* For foo.i, read the original filename foo.c now, for the benefit
-     of the front ends.  */
-  if (CPP_OPTION (pfile, preprocessed))
-    read_original_filename (pfile);
-
-  return pfile->map->to_file;
-}
-
-/* For preprocessed files, if the first tokens are of the form # NUM.
-   handle the directive so we know the original file name.  This will
-   generate file_change callbacks, which the front ends must handle
-   appropriately given their state of initialization.  */
-static void
-read_original_filename (pfile)
-     cpp_reader *pfile;
-{
-  const cpp_token *token, *token1;
-
-  /* Lex ahead; if the first tokens are of the form # NUM, then
-     process the directive, otherwise back up.  */
-  token = _cpp_lex_direct (pfile);
-  if (token->type == CPP_HASH)
-    {
-      token1 = _cpp_lex_direct (pfile);
-      _cpp_backup_tokens (pfile, 1);
-
-      /* If it's a #line directive, handle it.  */
-      if (token1->type == CPP_NUMBER)
-       {
-         _cpp_handle_directive (pfile, token->flags & PREV_WHITE);
-         return;
-       }
-    }
-
-  /* Backup as if nothing happened.  */
-  _cpp_backup_tokens (pfile, 1);
-}
-
-/* Handle pending command line options: -D, -U, -A, -imacros and
-   -include.  This should be called after debugging has been properly
-   set up in the front ends.  */
-void
-cpp_finish_options (pfile)
-     cpp_reader *pfile;
-{
-  /* Mark named operators before handling command line macros.  */
-  if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, operator_names))
-    mark_named_operators (pfile);
-
-  /* Install builtins and process command line macros etc. in the order
-     they appeared, but only if not already preprocessed.  */
-  if (! CPP_OPTION (pfile, preprocessed))
-    {
-      struct pending_option *p;
-
-      /* Prevent -Wunused-macros with command-line redefinitions.  */
-      pfile->first_unused_line = (unsigned int) -1;
-      _cpp_do_file_change (pfile, LC_RENAME, _("<built-in>"), 1, 0);
-      init_builtins (pfile);
-      _cpp_do_file_change (pfile, LC_RENAME, _("<command line>"), 1, 0);
-      for (p = CPP_OPTION (pfile, pending)->directive_head; p; p = p->next)
-       (*p->handler) (pfile, p->arg);
-
-      /* Scan -imacros files after -D, -U, but before -include.
-        pfile->next_include_file is NULL, so _cpp_pop_buffer does not
-        push -include files.  */
-      for (p = CPP_OPTION (pfile, pending)->imacros_head; p; p = p->next)
-       if (push_include (pfile, p))
-         cpp_scan_nooutput (pfile);
-
-      pfile->next_include_file = &CPP_OPTION (pfile, pending)->include_head;
-      _cpp_maybe_push_include_file (pfile);
-    }
-
-  pfile->first_unused_line = pfile->line;
-
-  free_chain (CPP_OPTION (pfile, pending)->imacros_head);
-  free_chain (CPP_OPTION (pfile, pending)->directive_head);
-}
-
-/* Push the next buffer on the stack given by -include, if any.  */
-void
-_cpp_maybe_push_include_file (pfile)
-     cpp_reader *pfile;
-{
-  if (pfile->next_include_file)
-    {
-      struct pending_option *head = *pfile->next_include_file;
-
-      while (head && !push_include (pfile, head))
-       head = head->next;
-
-      if (head)
-       pfile->next_include_file = &head->next;
-      else
-       {
-         /* All done; restore the line map from <command line>.  */
-         _cpp_do_file_change (pfile, LC_RENAME,
-                              pfile->line_maps.maps[0].to_file, 1, 0);
-         /* Don't come back here again.  */
-         pfile->next_include_file = NULL;
-       }
-    }
-}
-
-/* This is called at the end of preprocessing.  It pops the last
-   buffer and writes dependency output, and returns the number of
-   errors.
-
-   Maybe it should also reset state, such that you could call
-   cpp_start_read with a new filename to restart processing.  */
-int
-cpp_finish (pfile, deps_stream)
-     cpp_reader *pfile;
-     FILE *deps_stream;
-{
-  /* Warn about unused macros before popping the final buffer.  */
-  if (CPP_OPTION (pfile, warn_unused_macros))
-    cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL);
-
-  /* cpplex.c leaves the final buffer on the stack.  This it so that
-     it returns an unending stream of CPP_EOFs to the client.  If we
-     popped the buffer, we'd dereference a NULL buffer pointer and
-     segfault.  It's nice to allow the client to do worry-free excess
-     cpp_get_token calls.  */
-  while (pfile->buffer)
-    _cpp_pop_buffer (pfile);
-
-  /* Don't write the deps file if there are errors.  */
-  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE
-      && deps_stream && pfile->errors == 0)
-    {
-      deps_write (pfile->deps, deps_stream, 72);
-
-      if (CPP_OPTION (pfile, deps.phony_targets))
-       deps_phony_targets (pfile->deps, deps_stream);
-    }
-
-  /* Report on headers that could use multiple include guards.  */
-  if (CPP_OPTION (pfile, print_include_names))
-    _cpp_report_missing_guards (pfile);
-
-  return pfile->errors;
-}
-
-/* Add a directive to be handled later in the initialization phase.  */
-static void
-new_pending_directive (pend, text, handler)
-     struct cpp_pending *pend;
-     const char *text;
-     cl_directive_handler handler;
-{
-  struct pending_option *o = (struct pending_option *)
-    xmalloc (sizeof (struct pending_option));
-
-  o->arg = text;
-  o->next = NULL;
-  o->handler = handler;
-  APPEND (pend, directive, o);
-}
-
-/* Irix6 "cc -n32" and OSF4 cc have problems with char foo[] = ("string");
-   I.e. a const string initializer with parens around it.  That is
-   what N_("string") resolves to, so we make no_* be macros instead.  */
-#define no_arg N_("argument missing after %s")
-#define no_ass N_("assertion missing after %s")
-#define no_dir N_("directory name missing after %s")
-#define no_fil N_("file name missing after %s")
-#define no_mac N_("macro name missing after %s")
-#define no_pth N_("path name missing after %s")
-#define no_num N_("number missing after %s")
-#define no_tgt N_("target missing after %s")
-
-/* This is the list of all command line options, with the leading
-   "-" removed.  It must be sorted in ASCII collating order.  */
-#define COMMAND_LINE_OPTIONS                                                  \
-  DEF_OPT("$",                        0,      OPT_dollar)                     \
-  DEF_OPT("+",                        0,      OPT_plus)                       \
-  DEF_OPT("-help",                    0,      OPT__help)                      \
-  DEF_OPT("-target-help",             0,      OPT_target__help)               \
-  DEF_OPT("-version",                 0,      OPT__version)                   \
-  DEF_OPT("A",                        no_ass, OPT_A)                          \
-  DEF_OPT("C",                        0,      OPT_C)                          \
-  DEF_OPT("D",                        no_mac, OPT_D)                          \
-  DEF_OPT("H",                        0,      OPT_H)                          \
-  DEF_OPT("I",                        no_dir, OPT_I)                          \
-  DEF_OPT("M",                        0,      OPT_M)                          \
-  DEF_OPT("MD",                       no_fil, OPT_MD)                         \
-  DEF_OPT("MF",                       no_fil, OPT_MF)                         \
-  DEF_OPT("MG",                       0,      OPT_MG)                         \
-  DEF_OPT("MM",                       0,      OPT_MM)                         \
-  DEF_OPT("MMD",                      no_fil, OPT_MMD)                        \
-  DEF_OPT("MP",                       0,      OPT_MP)                         \
-  DEF_OPT("MQ",                       no_tgt, OPT_MQ)                         \
-  DEF_OPT("MT",                       no_tgt, OPT_MT)                         \
-  DEF_OPT("P",                        0,      OPT_P)                          \
-  DEF_OPT("U",                        no_mac, OPT_U)                          \
-  DEF_OPT("W",                        no_arg, OPT_W)  /* arg optional */      \
-  DEF_OPT("d",                        no_arg, OPT_d)                          \
-  DEF_OPT("fno-operator-names",       0,      OPT_fno_operator_names)         \
-  DEF_OPT("fno-preprocessed",         0,      OPT_fno_preprocessed)           \
-  DEF_OPT("fno-show-column",          0,      OPT_fno_show_column)            \
-  DEF_OPT("fpreprocessed",            0,      OPT_fpreprocessed)              \
-  DEF_OPT("fshow-column",             0,      OPT_fshow_column)               \
-  DEF_OPT("fsigned-char",             0,      OPT_fsigned_char)               \
-  DEF_OPT("ftabstop=",                no_num, OPT_ftabstop)                   \
-  DEF_OPT("funsigned-char",           0,      OPT_funsigned_char)             \
-  DEF_OPT("h",                        0,      OPT_h)                          \
-  DEF_OPT("idirafter",                no_dir, OPT_idirafter)                  \
-  DEF_OPT("imacros",                  no_fil, OPT_imacros)                    \
-  DEF_OPT("include",                  no_fil, OPT_include)                    \
-  DEF_OPT("iprefix",                  no_pth, OPT_iprefix)                    \
-  DEF_OPT("isysroot",                 no_dir, OPT_isysroot)                   \
-  DEF_OPT("isystem",                  no_dir, OPT_isystem)                    \
-  DEF_OPT("iwithprefix",              no_dir, OPT_iwithprefix)                \
-  DEF_OPT("iwithprefixbefore",        no_dir, OPT_iwithprefixbefore)          \
-  DEF_OPT("lang-asm",                 0,      OPT_lang_asm)                   \
-  DEF_OPT("lang-c",                   0,      OPT_lang_c)                     \
-  DEF_OPT("lang-c++",                 0,      OPT_lang_cplusplus)             \
-  DEF_OPT("lang-c89",                 0,      OPT_lang_c89)                   \
-  DEF_OPT("nostdinc",                 0,      OPT_nostdinc)                   \
-  DEF_OPT("nostdinc++",               0,      OPT_nostdincplusplus)           \
-  DEF_OPT("o",                        no_fil, OPT_o)                          \
-  /* SDCC specific */                                                         \
-  DEF_OPT("obj-ext=",                 no_arg, OPT_obj_ext)                    \
-  DEF_OPT("pedantic",                 0,      OPT_pedantic)                   \
-  DEF_OPT("pedantic-errors",          0,      OPT_pedantic_errors)            \
-  /* SDCC specific */                                                         \
-  DEF_OPT("pedantic-parse-number",    0,      OPT_pedantic_parse_number)      \
-  DEF_OPT("remap",                    0,      OPT_remap)                      \
-  DEF_OPT("std=c++98",                0,      OPT_std_cplusplus98)            \
-  DEF_OPT("std=c89",                  0,      OPT_std_c89)                    \
-  DEF_OPT("std=c99",                  0,      OPT_std_c99)                    \
-  DEF_OPT("std=c9x",                  0,      OPT_std_c9x)                    \
-  DEF_OPT("std=gnu89",                0,      OPT_std_gnu89)                  \
-  DEF_OPT("std=gnu99",                0,      OPT_std_gnu99)                  \
-  DEF_OPT("std=gnu9x",                0,      OPT_std_gnu9x)                  \
-  DEF_OPT("std=iso9899:1990",         0,      OPT_std_iso9899_1990)           \
-  DEF_OPT("std=iso9899:199409",       0,      OPT_std_iso9899_199409)         \
-  DEF_OPT("std=iso9899:1999",         0,      OPT_std_iso9899_1999)           \
-  DEF_OPT("std=iso9899:199x",         0,      OPT_std_iso9899_199x)           \
-  DEF_OPT("trigraphs",                0,      OPT_trigraphs)                  \
-  DEF_OPT("v",                        0,      OPT_v)                          \
-  DEF_OPT("version",                  0,      OPT_version)                    \
-  DEF_OPT("w",                        0,      OPT_w)
-
-#define DEF_OPT(text, msg, code) code,
-enum opt_code
-{
-  COMMAND_LINE_OPTIONS
-  N_OPTS
-};
-#undef DEF_OPT
-
-struct cl_option
-{
-  const char *opt_text;
-  const char *msg;
-  size_t opt_len;
-  enum opt_code opt_code;
-};
-
-#define DEF_OPT(text, msg, code) { text, msg, sizeof(text) - 1, code },
-#ifdef HOST_EBCDIC
-static struct cl_option cl_options[] =
-#else
-static const struct cl_option cl_options[] =
-#endif
-{
-  COMMAND_LINE_OPTIONS
-};
-#undef DEF_OPT
-#undef COMMAND_LINE_OPTIONS
-
-/* Perform a binary search to find which, if any, option the given
-   command-line matches.  Returns its index in the option array,
-   negative on failure.  Complications arise since some options can be
-   suffixed with an argument, and multiple complete matches can occur,
-   e.g. -pedantic and -pedantic-errors.  */
-static int
-parse_option (input)
-     const char *input;
-{
-  unsigned int md, mn, mx;
-  size_t opt_len;
-  int comp;
-
-  mn = 0;
-  mx = N_OPTS;
-
-  while (mx > mn)
-    {
-      md = (mn + mx) / 2;
-
-      opt_len = cl_options[md].opt_len;
-      comp = strncmp (input, cl_options[md].opt_text, opt_len);
-
-      if (comp > 0)
-       mn = md + 1;
-      else if (comp < 0)
-       mx = md;
-      else
-       {
-         if (input[opt_len] == '\0')
-           return md;
-         /* We were passed more text.  If the option takes an argument,
-            we may match a later option or we may have been passed the
-            argument.  The longest possible option match succeeds.
-            If the option takes no arguments we have not matched and
-            continue the search (e.g. input="stdc++" match was "stdc").  */
-         mn = md + 1;
-         if (cl_options[md].msg)
-           {
-             /* Scan forwards.  If we get an exact match, return it.
-                Otherwise, return the longest option-accepting match.
-                This loops no more than twice with current options.  */
-             mx = md;
-             for (; mn < (unsigned int) N_OPTS; mn++)
-               {
-                 opt_len = cl_options[mn].opt_len;
-                 if (strncmp (input, cl_options[mn].opt_text, opt_len))
-                   break;
-                 if (input[opt_len] == '\0')
-                   return mn;
-                 if (cl_options[mn].msg)
-                   mx = mn;
-               }
-             return mx;
-           }
-       }
-    }
-
-  return -1;
-}
-
-/* Handle one command-line option in (argc, argv).
-   Can be called multiple times, to handle multiple sets of options.
-   Returns number of strings consumed.  */
-int
-cpp_handle_option (pfile, argc, argv)
-     cpp_reader *pfile;
-     int argc;
-     char **argv;
-{
-  int i = 0;
-  struct cpp_pending *pend = CPP_OPTION (pfile, pending);
-
-  /* Interpret "-" or a non-option as a file name.  */
-  if (argv[i][0] != '-' || argv[i][1] == '\0')
-    {
-      if (CPP_OPTION (pfile, in_fname) == NULL)
-       CPP_OPTION (pfile, in_fname) = argv[i];
-      else if (CPP_OPTION (pfile, out_fname) == NULL)
-       CPP_OPTION (pfile, out_fname) = argv[i];
-      else
-       cpp_error (pfile, DL_ERROR, "too many filenames. Type %s --help for usage info",
-                  progname);
-    }
-  else
-    {
-      enum opt_code opt_code;
-      int opt_index;
-      const char *arg = 0;
-
-      /* Skip over '-'.  */
-      opt_index = parse_option (&argv[i][1]);
-      if (opt_index < 0)
-       return i;
-
-      opt_code = cl_options[opt_index].opt_code;
-      if (cl_options[opt_index].msg)
-       {
-         arg = &argv[i][cl_options[opt_index].opt_len + 1];
-         /* Yuk. Special case for -W as it must not swallow
-            up any following argument.  If this becomes common, add
-            another field to the cl_options table.  */
-         if (arg[0] == '\0' && opt_code != OPT_W)
-           {
-             arg = argv[++i];
-             if (!arg)
-               {
-                 cpp_error (pfile, DL_ERROR,
-                            cl_options[opt_index].msg, argv[i - 1]);
-                 return argc;
-               }
-           }
-       }
-
-      switch (opt_code)
-       {
-       case N_OPTS: /* Shut GCC up.  */
-         break;
-       case OPT_fno_operator_names:
-         CPP_OPTION (pfile, operator_names) = 0;
-         break;
-       case OPT_fpreprocessed:
-         CPP_OPTION (pfile, preprocessed) = 1;
-         break;
-       case OPT_fno_preprocessed:
-         CPP_OPTION (pfile, preprocessed) = 0;
-         break;
-       case OPT_fshow_column:
-         CPP_OPTION (pfile, show_column) = 1;
-         break;
-       case OPT_fno_show_column:
-         CPP_OPTION (pfile, show_column) = 0;
-         break;
-       case OPT_ftabstop:
-         /* Silently ignore empty string, non-longs and silly values.  */
-         if (arg[0] != '\0')
-           {
-             char *endptr;
-             long tabstop = strtol (arg, &endptr, 10);
-             if (*endptr == '\0' && tabstop >= 1 && tabstop <= 100)
-               CPP_OPTION (pfile, tabstop) = tabstop;
-           }
-         break;
-        case OPT_fsigned_char:
-          CPP_OPTION (pfile, unsigned_char) = 0;
-         break;
-        case OPT_funsigned_char:
-          CPP_OPTION (pfile, unsigned_char) = 1;
-         break;
-       case OPT_w:
-         CPP_OPTION (pfile, inhibit_warnings) = 1;
-         break;
-       case OPT_h:
-       case OPT__help:
-         print_help ();
-         CPP_OPTION (pfile, help_only) = 1;
-         break;
-       case OPT_target__help:
-          /* Print if any target specific options. cpplib has none, but
-            make sure help_only gets set.  */
-         CPP_OPTION (pfile, help_only) = 1;
-          break;
-
-         /* --version inhibits compilation, -version doesn't. -v means
-            verbose and -version.  Historical reasons, don't ask.  */
-       case OPT__version:
-         CPP_OPTION (pfile, help_only) = 1;
-         pfile->print_version = 1;
-         break;
-       case OPT_v:
-         CPP_OPTION (pfile, verbose) = 1;
-         pfile->print_version = 1;
-         break;
-       case OPT_version:
-         pfile->print_version = 1;
-         break;
-
-       case OPT_C:
-         CPP_OPTION (pfile, discard_comments) = 0;
-         break;
-       case OPT_P:
-         CPP_OPTION (pfile, no_line_commands) = 1;
-         break;
-       case OPT_dollar:        /* Don't include $ in identifiers.  */
-         CPP_OPTION (pfile, dollars_in_ident) = 0;
-         break;
-       case OPT_H:
-         CPP_OPTION (pfile, print_include_names) = 1;
-         break;
-       case OPT_D:
-         new_pending_directive (pend, arg, cpp_define);
-         break;
-       case OPT_pedantic_errors:
-         CPP_OPTION (pfile, pedantic_errors) = 1;
-         /* fall through */
-       case OPT_pedantic:
-         CPP_OPTION (pfile, pedantic) = 1;
-         break;
-        case OPT_pedantic_parse_number:
-          CPP_OPTION (pfile, pedantic_parse_number) = 1;
-          break;
-       case OPT_trigraphs:
-         CPP_OPTION (pfile, trigraphs) = 1;
-         break;
-       case OPT_plus:
-         CPP_OPTION (pfile, cplusplus) = 1;
-         CPP_OPTION (pfile, cplusplus_comments) = 1;
-         break;
-       case OPT_remap:
-         CPP_OPTION (pfile, remap) = 1;
-         break;
-       case OPT_iprefix:
-         CPP_OPTION (pfile, include_prefix) = arg;
-         CPP_OPTION (pfile, include_prefix_len) = strlen (arg);
-         break;
-       case OPT_isysroot:
-         CPP_OPTION (pfile, sysroot) = arg;
-         break;
-        case OPT_lang_c:
-         cpp_set_lang (pfile, CLK_GNUC89);
-         break;
-       case OPT_lang_cplusplus:
-         cpp_set_lang (pfile, CLK_GNUCXX);
-         break;
-       case OPT_lang_asm:
-         cpp_set_lang (pfile, CLK_ASM);
-         break;
-       case OPT_std_cplusplus98:
-         cpp_set_lang (pfile, CLK_CXX98);
-         break;
-       case OPT_std_gnu89:
-         cpp_set_lang (pfile, CLK_GNUC89);
-         break;
-       case OPT_std_gnu9x:
-       case OPT_std_gnu99:
-         cpp_set_lang (pfile, CLK_GNUC99);
-         break;
-       case OPT_std_iso9899_199409:
-         cpp_set_lang (pfile, CLK_STDC94);
-         break;
-       case OPT_std_iso9899_1990:
-       case OPT_std_c89:
-       case OPT_lang_c89:
-         cpp_set_lang (pfile, CLK_STDC89);
-         break;
-       case OPT_std_iso9899_199x:
-       case OPT_std_iso9899_1999:
-       case OPT_std_c9x:
-       case OPT_std_c99:
-         cpp_set_lang (pfile, CLK_STDC99);
-         break;
-       case OPT_nostdinc:
-         /* -nostdinc causes no default include directories.
-            You must specify all include-file directories with -I.  */
-         CPP_OPTION (pfile, no_standard_includes) = 1;
-         break;
-       case OPT_nostdincplusplus:
-         /* -nostdinc++ causes no default C++-specific include directories.  */
-         CPP_OPTION (pfile, no_standard_cplusplus_includes) = 1;
-         break;
-       case OPT_o:
-         if (CPP_OPTION (pfile, out_fname) == NULL)
-           CPP_OPTION (pfile, out_fname) = arg;
-         else
-           {
-             cpp_error (pfile, DL_ERROR, "output filename specified twice");
-             return argc;
-           }
-         break;
-       case OPT_d:
-         /* Args to -d specify what parts of macros to dump.
-            Silently ignore unrecognised options; they may
-            be aimed at the compiler proper.  */
-         {
-           char c;
-
-           while ((c = *arg++) != '\0')
-             switch (c)
-               {
-               case 'M':
-                 CPP_OPTION (pfile, dump_macros) = dump_only;
-                 break;
-               case 'N':
-                 CPP_OPTION (pfile, dump_macros) = dump_names;
-                 break;
-               case 'D':
-                 CPP_OPTION (pfile, dump_macros) = dump_definitions;
-                 break;
-               case 'I':
-                 CPP_OPTION (pfile, dump_includes) = 1;
-                 break;
-               }
-         }
-         break;
-
-       case OPT_MG:
-         CPP_OPTION (pfile, deps.missing_files) = 1;
-         break;
-       case OPT_M:
-         /* When doing dependencies with -M or -MM, suppress normal
-            preprocessed output, but still do -dM etc. as software
-            depends on this.  Preprocessed output occurs if -MD, -MMD
-            or environment var dependency generation is used.  */
-         CPP_OPTION (pfile, deps.style) = 2;
-         CPP_OPTION (pfile, no_output) = 1;
-         break;
-       case OPT_MM:
-         CPP_OPTION (pfile, deps.style) = 1;
-         CPP_OPTION (pfile, no_output) = 1;
-         break;
-       case OPT_MF:
-         CPP_OPTION (pfile, deps.file) = arg;
-         break;
-       case OPT_MP:
-         CPP_OPTION (pfile, deps.phony_targets) = 1;
-         break;
-       case OPT_MQ:
-       case OPT_MT:
-         /* Add a target.  -MQ quotes for Make.  */
-         deps_add_target (pfile->deps, arg, opt_code == OPT_MQ);
-         break;
-
-       case OPT_MD:
-         CPP_OPTION (pfile, deps.style) = 2;
-         CPP_OPTION (pfile, deps.file) = arg;
-         break;
-       case OPT_MMD:
-         CPP_OPTION (pfile, deps.style) = 1;
-         CPP_OPTION (pfile, deps.file) = arg;
-         break;
-
-       case OPT_A:
-         if (arg[0] == '-')
-           {
-             /* -A with an argument beginning with '-' acts as
-                #unassert on whatever immediately follows the '-'.
-                If "-" is the whole argument, we eliminate all
-                predefined macros and assertions, including those
-                that were specified earlier on the command line.
-                That way we can get rid of any that were passed
-                automatically in from GCC.  */
-
-             if (arg[1] == '\0')
-               {
-                 free_chain (pend->directive_head);
-                 pend->directive_head = NULL;
-                 pend->directive_tail = NULL;
-               }
-             else
-               new_pending_directive (pend, arg + 1, cpp_unassert);
-           }
-         else
-           new_pending_directive (pend, arg, cpp_assert);
-         break;
-       case OPT_U:
-         new_pending_directive (pend, arg, cpp_undef);
-         break;
-       case OPT_I:           /* Add directory to path for includes.  */
-         if (!strcmp (arg, "-"))
-           {
-             /* -I- means:
-                Use the preceding -I directories for #include "..."
-                but not #include <...>.
-                Don't search the directory of the present file
-                for #include "...".  (Note that -I. -I- is not the same as
-                the default setup; -I. uses the compiler's working dir.)  */
-             if (! CPP_OPTION (pfile, ignore_srcdir))
-               {
-                 pend->quote_head = pend->brack_head;
-                 pend->quote_tail = pend->brack_tail;
-                 pend->brack_head = 0;
-                 pend->brack_tail = 0;
-                 CPP_OPTION (pfile, ignore_srcdir) = 1;
-               }
-             else
-               {
-                 cpp_error (pfile, DL_ERROR, "-I- specified twice");
-                 return argc;
-               }
-           }
-         else
-           append_include_chain (pfile, (char *)xstrdup (arg), BRACKET, 0);
-         break;
-       case OPT_isystem:
-         /* Add directory to beginning of system include path, as a system
-            include directory.  */
-         append_include_chain (pfile, (char *)xstrdup (arg), SYSTEM, 0);
-         break;
-       case OPT_include:
-       case OPT_imacros:
-         {
-           struct pending_option *o = (struct pending_option *)
-             xmalloc (sizeof (struct pending_option));
-           o->arg = arg;
-           o->next = NULL;
-
-           if (opt_code == OPT_include)
-             APPEND (pend, include, o);
-           else
-             APPEND (pend, imacros, o);
-         }
-         break;
-       case OPT_iwithprefix:
-         /* Add directory to end of path for includes,
-            with the default prefix at the front of its name.  */
-         /* fall through */
-       case OPT_iwithprefixbefore:
-         /* Add directory to main path for includes,
-            with the default prefix at the front of its name.  */
-         {
-           char *fname;
-           int len;
-
-           len = strlen (arg);
-
-           if (CPP_OPTION (pfile, include_prefix) != 0)
-             {
-               size_t ipl = CPP_OPTION (pfile, include_prefix_len);
-               fname = xmalloc (ipl + len + 1);
-               memcpy (fname, CPP_OPTION (pfile, include_prefix), ipl);
-               memcpy (fname + ipl, arg, len + 1);
-             }
-           else if (cpp_GCC_INCLUDE_DIR_len)
-             {
-               fname = xmalloc (cpp_GCC_INCLUDE_DIR_len + len + 1);
-               memcpy (fname, cpp_GCC_INCLUDE_DIR, cpp_GCC_INCLUDE_DIR_len);
-               memcpy (fname + cpp_GCC_INCLUDE_DIR_len, arg, len + 1);
-             }
-           else
-             fname = xstrdup (arg);
-
-           append_include_chain (pfile, fname,
-                         opt_code == OPT_iwithprefix ? SYSTEM: BRACKET, 0);
-         }
-         break;
-       case OPT_idirafter:
-         /* Add directory to end of path for includes.  */
-         append_include_chain (pfile, (char *)xstrdup (arg), AFTER, 0);
-         break;
-       case OPT_W:
-         /* Silently ignore unrecognised options.  */
-         if (!strcmp (argv[i], "-Wall"))
-           {
-             CPP_OPTION (pfile, warn_trigraphs) = 1;
-             CPP_OPTION (pfile, warn_comments) = 1;
-           }
-         else if (!strcmp (argv[i], "-Wtraditional"))
-           CPP_OPTION (pfile, warn_traditional) = 1;
-         else if (!strcmp (argv[i], "-Wtrigraphs"))
-           CPP_OPTION (pfile, warn_trigraphs) = 1;
-         else if (!strcmp (argv[i], "-Wcomment"))
-           CPP_OPTION (pfile, warn_comments) = 1;
-         else if (!strcmp (argv[i], "-Wcomments"))
-           CPP_OPTION (pfile, warn_comments) = 1;
-         else if (!strcmp (argv[i], "-Wundef"))
-           CPP_OPTION (pfile, warn_undef) = 1;
-         else if (!strcmp (argv[i], "-Wimport"))
-           CPP_OPTION (pfile, warn_import) = 1;
-         else if (!strcmp (argv[i], "-Werror"))
-           CPP_OPTION (pfile, warnings_are_errors) = 1;
-         else if (!strcmp (argv[i], "-Wsystem-headers"))
-           CPP_OPTION (pfile, warn_system_headers) = 1;
-         else if (!strcmp (argv[i], "-Wno-traditional"))
-           CPP_OPTION (pfile, warn_traditional) = 0;
-         else if (!strcmp (argv[i], "-Wno-trigraphs"))
-           CPP_OPTION (pfile, warn_trigraphs) = 0;
-         else if (!strcmp (argv[i], "-Wno-comment"))
-           CPP_OPTION (pfile, warn_comments) = 0;
-         else if (!strcmp (argv[i], "-Wno-comments"))
-           CPP_OPTION (pfile, warn_comments) = 0;
-         else if (!strcmp (argv[i], "-Wno-undef"))
-           CPP_OPTION (pfile, warn_undef) = 0;
-         else if (!strcmp (argv[i], "-Wno-import"))
-           CPP_OPTION (pfile, warn_import) = 0;
-         else if (!strcmp (argv[i], "-Wno-error"))
-           CPP_OPTION (pfile, warnings_are_errors) = 0;
-         else if (!strcmp (argv[i], "-Wno-system-headers"))
-           CPP_OPTION (pfile, warn_system_headers) = 0;
-         break;
-       /* SDCC specific */
-       case OPT_obj_ext:
-         CPP_OPTION (pfile, obj_ext) = arg;
-         break;
-       }
-    }
-  return i + 1;
-}
-
-/* Handle command-line options in (argc, argv).
-   Can be called multiple times, to handle multiple sets of options.
-   Returns if an unrecognized option is seen.
-   Returns number of strings consumed.  */
-int
-cpp_handle_options (pfile, argc, argv)
-     cpp_reader *pfile;
-     int argc;
-     char **argv;
-{
-  int i;
-  int strings_processed;
-
-  for (i = 0; i < argc; i += strings_processed)
-    {
-      strings_processed = cpp_handle_option (pfile, argc - i, argv + i);
-      if (strings_processed == 0)
-       break;
-    }
-
-  return i;
-}
-
-static void
-post_options (pfile)
-     cpp_reader *pfile;
-{
-  /* -Wtraditional is not useful in C++ mode.  */
-  if (CPP_OPTION (pfile, cplusplus))
-    CPP_OPTION (pfile, warn_traditional) = 0;
-
-  /* Permanently disable macro expansion if we are rescanning
-     preprocessed text.  Read preprocesed source in ISO mode.  */
-  if (CPP_OPTION (pfile, preprocessed))
-    {
-      pfile->state.prevent_expansion = 1;
-      CPP_OPTION (pfile, traditional) = 0;
-    }
-
-  /* Traditional CPP does not accurately track column information.  */
-  if (CPP_OPTION (pfile, traditional))
-    CPP_OPTION (pfile, show_column) = 0;
-}
-
-/* Handle --help output.  */
-static void
-print_help ()
-{
-  /* To keep the lines from getting too long for some compilers, limit
-     to about 500 characters (6 lines) per chunk.  */
-  fputs (_("\
-Switches:\n\
-  -include <file>           Include the contents of <file> before other files\n\
-  -imacros <file>           Accept definition of macros in <file>\n\
-  -iprefix <path>           Specify <path> as a prefix for next two options\n\
-  -iwithprefix <dir>        Add <dir> to the end of the system include path\n\
-  -iwithprefixbefore <dir>  Add <dir> to the end of the main include path\n\
-  -isystem <dir>            Add <dir> to the start of the system include path\n\
-  -isysroot <dir>           Set <dir> to be the system root directory\n\
-"), stdout);
-  fputs (_("\
-  -idirafter <dir>          Add <dir> to the end of the system include path\n\
-  -I <dir>                  Add <dir> to the end of the main include path\n\
-  -I-                       Fine-grained include path control; see info docs\n\
-  -nostdinc                 Do not search system include directories\n\
-                             (dirs specified with -isystem will still be used)\n\
-  -nostdinc++               Do not search system include directories for C++\n\
-  -o <file>                 Put output into <file>\n\
-"), stdout);
-  fputs (_("\
-  -pedantic                 Issue all warnings demanded by strict ISO C\n\
-  -pedantic-errors          Issue -pedantic warnings as errors instead\n\
-  -trigraphs                Support ISO C trigraphs\n\
-  -lang-c                   Assume that the input sources are in C\n\
-  -lang-c89                 Assume that the input sources are in C89\n\
-"), stdout);
-  /* SDCC specific */
-  fputs (_("\
-  -pedantic-parse-number    Pedantic parse number\n\
-"), stdout);
-  fputs (_("\
-  -lang-c++                 Assume that the input sources are in C++\n\
-  -lang-asm                 Assume that the input sources are in assembler\n\
-"), stdout);
-  fputs (_("\
-  -std=<std name>           Specify the conformance standard; one of:\n\
-                            gnu89, gnu99, c89, c99, iso9899:1990,\n\
-                            iso9899:199409, iso9899:1999\n\
-  -+                        Allow parsing of C++ style features\n\
-  -w                        Inhibit warning messages\n\
-  -Wtrigraphs               Warn if trigraphs are encountered\n\
-  -Wno-trigraphs            Do not warn about trigraphs\n\
-  -Wcomment{s}              Warn if one comment starts inside another\n\
-"), stdout);
-  fputs (_("\
-  -Wno-comment{s}           Do not warn about comments\n\
-  -Wtraditional             Warn about features not present in traditional C\n\
-  -Wno-traditional          Do not warn about traditional C\n\
-  -Wundef                   Warn if an undefined macro is used by #if\n\
-  -Wno-undef                Do not warn about testing undefined macros\n\
-  -Wimport                  Warn about the use of the #import directive\n\
-"), stdout);
-  fputs (_("\
-  -Wno-import               Do not warn about the use of #import\n\
-  -Werror                   Treat all warnings as errors\n\
-  -Wno-error                Do not treat warnings as errors\n\
-  -Wsystem-headers          Do not suppress warnings from system headers\n\
-  -Wno-system-headers       Suppress warnings from system headers\n\
-  -Wall                     Enable all preprocessor warnings\n\
-"), stdout);
-  fputs (_("\
-  -M                        Generate make dependencies\n\
-  -MM                       As -M, but ignore system header files\n\
-  -MD                       Generate make dependencies and compile\n\
-  -MMD                      As -MD, but ignore system header files\n\
-  -MF <file>                Write dependency output to the given file\n\
-  -MG                       Treat missing header file as generated files\n\
-"), stdout);
-  fputs (_("\
-  -MP                       Generate phony targets for all headers\n\
-  -MQ <target>              Add a MAKE-quoted target\n\
-  -MT <target>              Add an unquoted target\n\
-"), stdout);
-  /* SDCC specific */
-  fputs (_("\
-  -obj-ext=<extension>      Define object file extension, used for generation\n\
-                            of make dependencies\n\
-"), stdout);
-  fputs (_("\
-  -D<macro>                 Define a <macro> with string '1' as its value\n\
-  -D<macro>=<val>           Define a <macro> with <val> as its value\n\
-  -A<question>=<answer>     Assert the <answer> to <question>\n\
-  -A-<question>=<answer>    Disable the <answer> to <question>\n\
-  -U<macro>                 Undefine <macro> \n\
-  -v                        Display the version number\n\
-"), stdout);
-  fputs (_("\
-  -H                        Print the name of header files as they are used\n\
-  -C                        Do not discard comments\n\
-  -dM                       Display a list of macro definitions active at end\n\
-  -dD                       Preserve macro definitions in output\n\
-  -dN                       As -dD except that only the names are preserved\n\
-  -dI                       Include #include directives in the output\n\
-"), stdout);
-  fputs (_("\
-  -fpreprocessed            Treat the input file as already preprocessed\n\
-  -ftabstop=<number>        Distance between tab stops for column reporting\n\
-  -fsigned-char             Make \"char\" signed by default\n\
-  -funsigned-char           Make \"char\" unsigned by default\n\
-  -P                        Do not generate #line directives\n\
-  -$                        Do not allow '$' in identifiers\n\
-  -remap                    Remap file names when including files\n\
-  --version                 Display version information\n\
-  -h or --help              Display this information\n\
-"), stdout);
-}
diff --git a/support/cpp2/sdcppmain.c b/support/cpp2/sdcppmain.c
deleted file mode 100644 (file)
index 48f3f00..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*-------------------------------------------------------------------------
-    sdcppmain.c - sdcpp: SDCC preprocessor main file, using cpplib.
-
-    Written by Borut Razem, 2006.
-
-    This program is free software; you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by the
-    Free Software Foundation; either version 2, or (at your option) any
-    later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-    In other words, you are welcome to use, share and improve this program.
-    You are forbidden to forbid anyone else to use, share and improve
-    what you give them.   Help stamp out software-hoarding!
--------------------------------------------------------------------------*/
-
-#include "config.h"
-#include "system.h"
-#include "cpplib.h"
-#include "cpphash.h"
-#include "version.h"
-#include "mkdeps.h"
-
-#define _
-
-#define CPP_FATAL_LIMIT 1000
-/* True if we have seen a "fatal" error.  */
-#define CPP_FATAL_ERRORS(PFILE) (cpp_errors (PFILE) >= CPP_FATAL_LIMIT)
-
-
-const char *progname;          /* Needs to be global.  */
-
-
-/* Set up dependency-file output.  On exit, if deps.style is non-zero
-   then deps.file is not NULL; stdout is the empty string.  */
-static void
-init_dependency_output (cpp_reader *pfile)
-{
-  char *spec, *s, *output_file;
-
-  /* Either of two environment variables can specify output of deps.
-     Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET",
-     where OUTPUT_FILE is the file to write deps info to
-     and DEPS_TARGET is the target to mention in the deps.  */
-
-  if (CPP_OPTION (pfile, deps.style) == 0)
-    {
-      spec = getenv ("DEPENDENCIES_OUTPUT");
-      if (spec)
-       CPP_OPTION (pfile, deps.style) = 1;
-      else
-       {
-         spec = getenv ("SUNPRO_DEPENDENCIES");
-         if (spec)
-           {
-             CPP_OPTION (pfile, deps.style) = 2;
-             CPP_OPTION (pfile, deps.ignore_main_file) = 1;
-           }
-         else
-           return;
-       }
-
-      /* Find the space before the DEPS_TARGET, if there is one.  */
-      s = strchr (spec, ' ');
-      if (s)
-       {
-         /* Let the caller perform MAKE quoting.  */
-         deps_add_target (pfile->deps, s + 1, 0);
-         output_file = (char *) xmalloc (s - spec + 1);
-         memcpy (output_file, spec, s - spec);
-         output_file[s - spec] = 0;
-       }
-      else
-       output_file = spec;
-
-      /* Command line -MF overrides environment variables and default.  */
-      if (CPP_OPTION (pfile, deps.file) == 0)
-       CPP_OPTION (pfile, deps.file) = output_file;
-
-      CPP_OPTION (pfile, deps.append) = 1;
-    }
-  else if (CPP_OPTION (pfile, deps.file) == 0)
-    /* If -M or -MM was seen without -MF, default output to wherever
-       was specified with -o.  out_fname is non-NULL here.  */
-    CPP_OPTION (pfile, deps.file) = CPP_OPTION (pfile, out_fname);
-}
-
-static void
-sdcpp_post_options (cpp_reader *pfile)
-{
-  if (pfile->print_version)
-    {
-      fprintf (stderr, _("GNU CPP version %s (cpplib)"), version_string);
-#ifdef TARGET_VERSION
-      TARGET_VERSION;
-#endif
-      fputc ('\n', stderr);
-    }
-
-  /* Canonicalize in_fname and out_fname.  We guarantee they are not
-     NULL, and that the empty string represents stdin / stdout.  */
-  if (CPP_OPTION (pfile, in_fname) == NULL
-      || !strcmp (CPP_OPTION (pfile, in_fname), "-"))
-    CPP_OPTION (pfile, in_fname) = "";
-
-  if (CPP_OPTION (pfile, out_fname) == NULL
-      || !strcmp (CPP_OPTION (pfile, out_fname), "-"))
-    CPP_OPTION (pfile, out_fname) = "";
-
-  /* -dM makes no normal output.  This is set here so that -dM -dD
-     works as expected.  */
-  if (CPP_OPTION (pfile, dump_macros) == dump_only)
-    CPP_OPTION (pfile, no_output) = 1;
-
-  /* Disable -dD, -dN and -dI if we should make no normal output
-     (such as with -M). Allow -M -dM since some software relies on
-     this.  */
-  if (CPP_OPTION (pfile, no_output))
-    {
-      if (CPP_OPTION (pfile, dump_macros) != dump_only)
-       CPP_OPTION (pfile, dump_macros) = dump_none;
-      CPP_OPTION (pfile, dump_includes) = 0;
-    }
-
-  /* We need to do this after option processing and before
-     cpp_start_read, as cppmain.c relies on the options->no_output to
-     set its callbacks correctly before calling cpp_start_read.  */
-  init_dependency_output (pfile);
-
-  /* After checking the environment variables, check if -M or -MM has
-     not been specified, but other -M options have.  */
-  if (CPP_OPTION (pfile, deps.style) == 0 &&
-      (CPP_OPTION (pfile, deps.missing_files)
-       || CPP_OPTION (pfile, deps.file)
-       || CPP_OPTION (pfile, deps.phony_targets)))
-    cpp_error (pfile, DL_ERROR, "you must additionally specify either -M or -MM");
-}
-
-/* Store the program name, and set the locale.  */
-static void
-general_init (const char *argv0)
-{
-  progname = argv0 + strlen (argv0);
-
-  while (progname != argv0 && ! IS_DIR_SEPARATOR (progname[-1]))
-    --progname;
-
-  hex_init ();
-}
-
-/* Handle switches, preprocess and output.  */
-static void
-do_preprocessing (cpp_reader *pfile, int argc, char **argv)
-{
-  FILE *outf;
-  int argi = 1;  /* Next argument to handle.  */
-
-  argi += cpp_handle_options (pfile, argc - argi , argv + argi);
-  if (CPP_FATAL_ERRORS (pfile))
-    return;
-
-  if (argi < argc)
-    {
-      cpp_error (pfile, DL_ERROR, "invalid option %s", argv[argi]);
-      return;
-    }
-
-  sdcpp_post_options (pfile);
-  if (CPP_FATAL_ERRORS (pfile))
-    return;
-
-  /* If cpp_handle_options saw --help or --version on the command
-     line, it will have set pfile->help_only to indicate this.  Exit
-     successfully.  [The library does not exit itself, because
-     e.g. cc1 needs to print its own --help message at this point.]  */
-  if (pfile->opts.help_only)
-    return;
-
-  /* Open the output now.  We must do so even if no_output is on,
-     because there may be other output than from the actual
-     preprocessing (e.g. from -dM).  */
-  if (CPP_OPTION(pfile, out_fname)[0] == '\0')
-    outf = stdout;
-  else
-    {
-      outf = fopen (CPP_OPTION(pfile, out_fname), "w");
-      if (outf == NULL)
-       {
-         cpp_errno (pfile, DL_ERROR, CPP_OPTION(pfile, out_fname));
-         return;
-       }
-    }
-
-  cpp_preprocess_file (pfile, pfile->opts.in_fname, outf);
-}
-
-/* Print a fatal I/O error message.  Argument are like printf.
-   Also include a system error message based on `errno'.  */
-void
-fatal_io_error (const char *msgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, msgid);
-  fprintf (stderr, "%s: %s: ", progname, xstrerror (errno));
-  vfprintf(stderr, msgid, ap);
-  va_end (ap);
-  exit (FATAL_EXIT_CODE);
-}
-
-/* Common finish hook for the C, ObjC and C++ front ends.  */
-void
-common_finish (cpp_reader *pfile)
-{
-  FILE *deps_stream = NULL;
-
-  if (CPP_OPTION (pfile, deps.style) != DEPS_NONE)
-    {
-      const char *const deps_mode =
-        CPP_OPTION (pfile, deps.append) ? "a" : "w";
-
-      /* If -M or -MM was seen without -MF, default output to the
-         output stream.  */
-      if (CPP_OPTION (pfile, deps.file)[0] == '\0')
-        deps_stream = stdout;
-      else
-        {
-          deps_stream = fopen (CPP_OPTION (pfile, deps.file), deps_mode);
-          if (deps_stream == 0)
-           {
-             cpp_errno (pfile, DL_ERROR, CPP_OPTION (pfile, deps.file));
-             return;
-           }
-        }
-    }
-
-  /* For performance, avoid tearing down cpplib's internal structures
-     with cpp_destroy ().  */
-  cpp_finish (pfile, deps_stream);
-
-  if (deps_stream && deps_stream != stdout
-      && (ferror (deps_stream) || fclose (deps_stream)))
-    fatal_io_error ("closing dependency file %s", CPP_OPTION (pfile, deps.file));
-}
-
-int
-main (int argc, char **argv)
-{
-  cpp_reader *pfile;
-
-  general_init (argv[0]);
-
-  /* Construct a reader with default language GNU C89.  */
-  pfile = cpp_create_reader (CLK_GNUC89);
-
-  do_preprocessing (pfile, argc, argv);
-
-  common_finish(pfile);
-
-  cpp_destroy (pfile);
-
-  return SUCCESS_EXIT_CODE;
-}
index 28b1137de44ea5ff29c3ee1cf77d6b0b965bcf25..676483c1eeb69deaa635e5b4c018c13d8097231a 100644 (file)
@@ -1,6 +1,7 @@
 /* Get common system includes and various definitions and declarations based
    on autoconf macros.
-   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -23,14 +24,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #ifndef GCC_SYSTEM_H
 #define GCC_SYSTEM_H
 
-#include "ansidecl.h"
-
-/* We must include stdarg.h/varargs.h before stdio.h.  */
-#ifdef ANSI_PROTOTYPES
+/* We must include stdarg.h before stdio.h.  */
 #include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
 
 #ifndef va_copy
 # ifdef __va_copy
@@ -46,13 +41,66 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include <stdio.h>
 
-#define CHAR_BIT 8
-
 /* Define a generic NULL if one hasn't already been defined.  */
 #ifndef NULL
 #define NULL 0
 #endif
 
+/* The compiler is not a multi-threaded application and therefore we
+   do not have to use the locking functions.  In fact, using the locking
+   functions can cause the compiler to be significantly slower under
+   I/O bound conditions (such as -g -O0 on very large source files).
+
+   HAVE_DECL_PUTC_UNLOCKED actually indicates whether or not the stdio
+   code is multi-thread safe by default.  If it is set to 0, then do
+   not worry about using the _unlocked functions.
+
+   fputs_unlocked, fwrite_unlocked, and fprintf_unlocked are
+   extensions and need to be prototyped by hand (since we do not
+   define _GNU_SOURCE).  */
+
+#if defined HAVE_DECL_PUTC_UNLOCKED && HAVE_DECL_PUTC_UNLOCKED
+
+# ifdef HAVE_PUTC_UNLOCKED
+#  undef putc
+#  define putc(C, Stream) putc_unlocked (C, Stream)
+# endif
+# ifdef HAVE_FPUTC_UNLOCKED
+#  undef fputc
+#  define fputc(C, Stream) fputc_unlocked (C, Stream)
+# endif
+
+# ifdef HAVE_FPUTS_UNLOCKED
+#  undef fputs
+#  define fputs(String, Stream) fputs_unlocked (String, Stream)
+#  if defined (HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED
+extern int fputs_unlocked (const char *, FILE *);
+#  endif
+# endif
+# ifdef HAVE_FWRITE_UNLOCKED
+#  undef fwrite
+#  define fwrite(Ptr, Size, N, Stream) fwrite_unlocked (Ptr, Size, N, Stream)
+#  if defined (HAVE_DECL_FWRITE_UNLOCKED) && !HAVE_DECL_FWRITE_UNLOCKED
+extern int fwrite_unlocked (const void *, size_t, size_t, FILE *);
+#  endif
+# endif
+# ifdef HAVE_FPRINTF_UNLOCKED
+#  undef fprintf
+/* We can't use a function-like macro here because we don't know if
+   we have varargs macros.  */
+#  define fprintf fprintf_unlocked
+#  if defined (HAVE_DECL_FPRINTF_UNLOCKED) && !HAVE_DECL_FPRINTF_UNLOCKED
+extern int fprintf_unlocked (FILE *, const char *, ...);
+#  endif
+# endif
+
+#endif
+
+/* ??? Glibc's fwrite/fread_unlocked macros cause
+   "warning: signed and unsigned type in conditional expression".  */
+#undef fread_unlocked
+#undef fwrite_unlocked
+
 /* There are an extraordinary number of issues with <ctype.h>.
    The last straw is that it varies with the locale.  Use libiberty's
    replacement instead.  */
@@ -70,6 +118,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 extern int errno;
 #endif
 
+/* Some of glibc's string inlines cause warnings.  Plus we'd rather
+   rely on (and therefore test) GCC's string builtins.  */
+#define __NO_STRING_INLINES
+
 #ifdef STRING_WITH_STRINGS
 # include <string.h>
 # include <strings.h>
@@ -232,23 +284,39 @@ extern int errno;
    is running so be careful to test "defined (HAVE_DECL_*)".  */
 
 #if defined (HAVE_DECL_ATOF) && !HAVE_DECL_ATOF
-extern double atof PARAMS ((const char *));
+extern double atof (const char *);
 #endif
 
 #if defined (HAVE_DECL_ATOL) && !HAVE_DECL_ATOL
-extern long atol PARAMS ((const char *));
+extern long atol (const char *);
 #endif
 
 #if defined (HAVE_DECL_FREE) && !HAVE_DECL_FREE
-extern void free PARAMS ((PTR));
+extern void free (void *);
+#endif
+
+#if defined (HAVE_DECL_GETCWD) && !HAVE_DECL_GETCWD
+extern char *getcwd (char *, size_t);
 #endif
 
 #if defined (HAVE_DECL_GETENV) && !HAVE_DECL_GETENV
-extern char *getenv PARAMS ((const char *));
+extern char *getenv (const char *);
+#endif
+
+#if defined (HAVE_DECL_GETOPT) && !HAVE_DECL_GETOPT
+extern int getopt (int, char * const *, const char *);
+#endif
+
+#if defined (HAVE_DECL_GETWD) && !HAVE_DECL_GETWD
+extern char *getwd (char *);
+#endif
+
+#if defined (HAVE_DECL_SBRK) && !HAVE_DECL_SBRK
+extern void *sbrk (int);
 #endif
 
 #if defined (HAVE_DECL_STRSTR) && !HAVE_DECL_STRSTR
-extern char *strstr PARAMS ((const char *, const char *));
+extern char *strstr (const char *, const char *);
 #endif
 
 #ifdef HAVE_MALLOC_H
@@ -256,23 +324,50 @@ extern char *strstr PARAMS ((const char *, const char *));
 #endif
 
 #if defined (HAVE_DECL_MALLOC) && !HAVE_DECL_MALLOC
-extern PTR malloc PARAMS ((size_t));
+extern void *malloc (size_t);
 #endif
 
 #if defined (HAVE_DECL_CALLOC) && !HAVE_DECL_CALLOC
-extern PTR calloc PARAMS ((size_t, size_t));
+extern void *calloc (size_t, size_t);
 #endif
 
 #if defined (HAVE_DECL_REALLOC) && !HAVE_DECL_REALLOC
-extern PTR realloc PARAMS ((PTR, size_t));
+extern void *realloc (void *, size_t);
+#endif
+
+/* If the system doesn't provide strsignal, we get it defined in
+   libiberty but no declaration is supplied.  */
+#if !defined (HAVE_STRSIGNAL) \
+    || (defined (HAVE_DECL_STRSIGNAL) && !HAVE_DECL_STRSIGNAL)
+# ifndef strsignal
+extern const char *strsignal (int);
+# endif
+#endif
+
+#ifdef HAVE_GETRLIMIT
+# if defined (HAVE_DECL_GETRLIMIT) && !HAVE_DECL_GETRLIMIT
+#  ifndef getrlimit
+struct rlimit;
+extern int getrlimit (int, struct rlimit *);
+#  endif
+# endif
 #endif
 
-#if !defined(__STDC__) && !defined(volatile)
-#define volatile
+#ifdef HAVE_SETRLIMIT
+# if defined (HAVE_DECL_SETRLIMIT) && !HAVE_DECL_SETRLIMIT
+#  ifndef setrlimit
+struct rlimit;
+extern int setrlimit (int, const struct rlimit *);
+#  endif
+# endif
 #endif
 
 #if defined (HAVE_DECL_ABORT) && !HAVE_DECL_ABORT
-extern void abort PARAMS ((void));
+extern void abort (void);
+#endif
+
+#if defined (HAVE_DECL_SNPRINTF) && !HAVE_DECL_SNPRINTF
+extern int snprintf (char *, size_t, const char *, ...);
 #endif
 
 /* 1 if we have C99 designated initializers.  */
@@ -285,6 +380,13 @@ extern void abort PARAMS ((void));
 #endif
 #endif
 
+/* 1 if we have _Bool.  */
+#ifndef HAVE__BOOL
+# define HAVE__BOOL \
+   ((GCC_VERSION >= 3000) || (__STDC_VERSION__ >= 199901L))
+#endif
+
+
 #if HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
@@ -357,10 +459,12 @@ extern void abort PARAMS ((void));
 #ifndef HOST_PTR_PRINTF
 # ifdef HAVE_PRINTF_PTR
 #  define HOST_PTR_PRINTF "%p"
+# elif SIZEOF_INT == SIZEOF_VOID_P
+#  define HOST_PTR_PRINTF "%x"
+# elif SIZEOF_LONG == SIZEOF_VOID_P
+#  define HOST_PTR_PRINTF "%lx"
 # else
-#  define HOST_PTR_PRINTF \
-    (sizeof (int) == sizeof (char *) ? "%x" \
-     : sizeof (long) == sizeof (char *) ? "%lx" : "%llx")
+#  define HOST_PTR_PRINTF "%llx"
 # endif
 #endif /* ! HOST_PTR_PRINTF */
 
@@ -369,34 +473,19 @@ extern void abort PARAMS ((void));
 #define PATH_SEPARATOR ':'
 #endif
 
+/* Filename handling macros.  */
+#include "filenames.h"
+
+/* These should be phased out in favor of IS_DIR_SEPARATOR, where possible.  */
 #ifndef DIR_SEPARATOR
-#define DIR_SEPARATOR '/'
-#endif
-
-/* Define IS_DIR_SEPARATOR.  */
-#ifndef DIR_SEPARATOR_2
-# define IS_DIR_SEPARATOR(CH) ((CH) == DIR_SEPARATOR)
-#else /* DIR_SEPARATOR_2 */
-# define IS_DIR_SEPARATOR(CH) \
-       (((CH) == DIR_SEPARATOR) || ((CH) == DIR_SEPARATOR_2))
-#endif /* DIR_SEPARATOR_2 */
-
-/* Say how to test for an absolute pathname.  On Unix systems, this is if
-   it starts with a leading slash or a '$', the latter meaning the value of
-   an environment variable is to be used.  On machien with DOS-based
-   file systems, it is also absolute if it starts with a drive identifier.  */
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
-#define IS_ABSOLUTE_PATHNAME(STR) \
-  (IS_DIR_SEPARATOR ((STR)[0]) || (STR)[0] == '$' \
-   || ((STR)[0] != '\0' && (STR)[1] == ':' && IS_DIR_SEPARATOR ((STR)[2])))
-#else
-#define IS_ABSOLUTE_PATHNAME(STR) \
-  (IS_DIR_SEPARATOR ((STR)[0]) || (STR)[0] == '$')
+# define DIR_SEPARATOR '/'
+# ifdef HAVE_DOS_BASED_FILE_SYSTEM
+#  define DIR_SEPARATOR_2 '\\'
+# endif
 #endif
 
 /* Get libiberty declarations.  */
 #include "libiberty.h"
-#include "symcat.h"
 
 /* Provide a default for the HOST_BIT_BUCKET.
    This suffices for POSIX-like hosts.  */
@@ -409,23 +498,21 @@ extern void abort PARAMS ((void));
    FIXME: provide a complete autoconf test for buggy enum bitfields.  */
 
 #if (GCC_VERSION > 2000)
-#define ENUM_BITFIELD(TYPE) enum TYPE
+#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
 #else
 #define ENUM_BITFIELD(TYPE) unsigned int
 #endif
 
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER)
+/* We only use bool bitfields with gcc3.  Some supposedly C99
+   compilers don't handle them correctly.  */
+#if (GCC_VERSION >= 3000)
+#define BOOL_BITFIELD _Bool
+#else
+#define BOOL_BITFIELD unsigned int
 #endif
 
-/* Traditional C cannot initialize union members of structs.  Provide
-   a macro which expands appropriately to handle it.  This only works
-   if you intend to initialize the union member to zero since it relies
-   on default initialization to zero in the traditional C case.  */
-#ifdef __STDC__
-#define UNION_INIT_ZERO , {0}
-#else
-#define UNION_INIT_ZERO
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER)
 #endif
 
 /* Various error reporting routines want to use __FUNCTION__.  */
@@ -480,6 +567,13 @@ typedef char _Bool;
 #define really_call_calloc calloc
 #define really_call_realloc realloc
 
+#if defined(FLEX_SCANNER) || defined(YYBISON) || defined(YYBYACC)
+/* Flex and bison use malloc and realloc.  Yuk.  Note that this means
+   really_call_* cannot be used in a .l or .y file.  */
+#define malloc xmalloc
+#define realloc xrealloc
+#endif
+
 #if (GCC_VERSION >= 3000)
 
 /* Note autoconf checks for prototype declarations and includes
@@ -491,11 +585,7 @@ typedef char _Bool;
 #undef strdup
  #pragma GCC poison calloc strdup
 
-#if defined(FLEX_SCANNER) || defined (YYBISON) || defined(YYBYACC)
-/* Flex and bison use malloc and realloc.  Yuk.  */
-#define malloc xmalloc
-#define realloc xrealloc
-#else
+#if !defined(FLEX_SCANNER) && !defined(YYBISON)
 #undef malloc
 #undef realloc
  #pragma GCC poison malloc realloc
@@ -513,13 +603,20 @@ typedef char _Bool;
        ASM_OUTPUT_DESTRUCTOR SIGNED_CHAR_SPEC MAX_CHAR_TYPE_SIZE       \
        WCHAR_UNSIGNED UNIQUE_SECTION SELECT_SECTION SELECT_RTX_SECTION \
        ENCODE_SECTION_INFO STRIP_NAME_ENCODING ASM_GLOBALIZE_LABEL     \
-       ASM_OUTPUT_MI_THUNK
+       ASM_OUTPUT_MI_THUNK CONST_COSTS RTX_COSTS DEFAULT_RTX_COSTS     \
+       ADDRESS_COST MACHINE_DEPENDENT_REORG ASM_FILE_START ASM_FILE_END \
+       ASM_SIMPLIFY_DWARF_ADDR INIT_TARGET_OPTABS INIT_SUBTARGET_OPTABS \
+       INIT_GOFAST_OPTABS MULSI3_LIBCALL MULDI3_LIBCALL DIVSI3_LIBCALL \
+       DIVDI3_LIBCALL UDIVSI3_LIBCALL UDIVDI3_LIBCALL MODSI3_LIBCALL   \
+       MODDI3_LIBCALL UMODSI3_LIBCALL UMODDI3_LIBCALL BUILD_VA_LIST_TYPE \
+       PRETEND_OUTGOING_VARARGS_NAMED STRUCT_VALUE_INCOMING_REGNUM     \
+       SPLIT_COMPLEX_ARGS
 
 /* Other obsolete target macros, or macros that used to be in target
    headers and were not used, and may be obsolete or may never have
    been used.  */
- #pragma GCC poison INT_ASM_OP ASM_OUTPUT_EH_REGION_BEG                           \
-       ASM_OUTPUT_EH_REGION_END ASM_OUTPUT_LABELREF_AS_INT                \
+ #pragma GCC poison INT_ASM_OP ASM_OUTPUT_EH_REGION_BEG CPP_PREDEFINES    \
+       ASM_OUTPUT_EH_REGION_END ASM_OUTPUT_LABELREF_AS_INT SMALL_STACK    \
        DOESNT_NEED_UNWINDER EH_TABLE_LOOKUP OBJC_SELECTORS_WITHOUT_LABELS \
        OMIT_EH_TABLE EASY_DIV_EXPR IMPLICIT_FIX_EXPR                      \
        LONGJMP_RESTORE_FROM_STACK MAX_INT_TYPE_SIZE ASM_IDENTIFY_GCC      \
@@ -530,12 +627,35 @@ typedef char _Bool;
        BLOCK_PROFILER BLOCK_PROFILER_CODE FUNCTION_BLOCK_PROFILER         \
        FUNCTION_BLOCK_PROFILER_EXIT MACHINE_STATE_SAVE                    \
        MACHINE_STATE_RESTORE SCCS_DIRECTIVE SECTION_ASM_OP                \
-       ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+       ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL ASM_OUTPUT_INTERNAL_LABEL \
+       OBJC_PROLOGUE ALLOCATE_TRAMPOLINE HANDLE_PRAGMA ROUND_TYPE_SIZE    \
+       ROUND_TYPE_SIZE_UNIT CONST_SECTION_ASM_OP CRT_GET_RFIB_TEXT        \
+       DBX_LBRAC_FIRST DBX_OUTPUT_ENUM DBX_OUTPUT_SOURCE_FILENAME         \
+       DBX_WORKING_DIRECTORY INSN_CACHE_DEPTH INSN_CACHE_SIZE             \
+       INSN_CACHE_LINE_WIDTH INIT_SECTION_PREAMBLE NEED_ATEXIT ON_EXIT    \
+       EXIT_BODY OBJECT_FORMAT_ROSE MULTIBYTE_CHARS MAP_CHARACTER         \
+       LIBGCC_NEEDS_DOUBLE FINAL_PRESCAN_LABEL DEFAULT_CALLER_SAVES       \
+       LOAD_ARGS_REVERSED MAX_INTEGER_COMPUTATION_MODE                    \
+       CONVERT_HARD_REGISTER_TO_SSA_P ASM_OUTPUT_MAIN_SOURCE_FILENAME     \
+       FIRST_INSN_ADDRESS TEXT_SECTION SHARED_BSS_SECTION_ASM_OP          \
+       PROMOTED_MODE EXPAND_BUILTIN_VA_END                                \
+       LINKER_DOES_NOT_WORK_WITH_DWARF2
 
 /* Hooks that are no longer used.  */
  #pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE  \
-       LANG_HOOKS_MARK_TREE
-
+       LANG_HOOKS_MARK_TREE LANG_HOOKS_INSERT_DEFAULT_ATTRIBUTES
+
+/* Libiberty macros that are no longer used in GCC.  */
+#undef ANSI_PROTOTYPES
+#undef PTR_CONST
+#undef LONG_DOUBLE
+#undef VPARAMS
+#undef VA_OPEN
+#undef VA_FIXEDARG
+#undef VA_CLOSE
+#undef VA_START
+ #pragma GCC poison ANSI_PROTOTYPES PTR_CONST LONG_DOUBLE VPARAMS VA_OPEN \
+  VA_FIXEDARG VA_CLOSE VA_START
 #endif /* IN_GCC */
 
 /* Note: not all uses of the `index' token (e.g. variable names and
@@ -549,6 +669,6 @@ typedef char _Bool;
 #endif /* GCC >= 3.0 */
 
 /* SDCC specific */
-#include "sdcc.h"
+#include "sdcpp.h"
 
 #endif /* ! GCC_SYSTEM_H */
index 582349b0b049b09b93e275cea6cd84a89d6929f5..1918d6960a4bb9202445f3169314838c1ca781c4 100644 (file)
@@ -1,4 +1,3 @@
-#include "ansidecl.h"
 #include "version.h"
 
 /* This is the string reported as the version number by all components
@@ -6,7 +5,7 @@
    please modify this string to indicate that, e.g. by putting your
    organization's name in parentheses at the end of the string.  */
 
-const char version_string[] = "3.3.6 + SDCC";
+const char version_string[] = "3.4.6 + SDCC";
 
 /* This is the location of the online document giving instructions for
    reporting bugs.  If you distribute a modified version of GCC,
diff --git a/support/cpp2/win32/dirent.c b/support/cpp2/win32/dirent.c
new file mode 100644 (file)
index 0000000..dd9d654
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * dirent.c
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is a part of the mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within the package.
+ *
+ * Derived from DIRLIB.C by Matt J. Weinstein 
+ * This note appears in the DIRLIB.H
+ * DIRLIB.H by M. J. Weinstein   Released to public domain 1-Jan-89
+ *
+ * Updated by Jeremy Bettis <jeremy@hksys.com>
+ * Significantly revised and rewinddir, seekdir and telldir added by Colin
+ * Peters <colin@fu.is.saga-u.ac.jp>
+ *     
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <io.h>
+#include <direct.h>
+#include <dirent.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h> /* for GetFileAttributes */
+
+#include <tchar.h>
+
+#ifdef _UNICODE
+#define _tdirent       _wdirent
+#define _TDIR          _WDIR
+#define _topendir      _wopendir
+#define _tclosedir     _wclosedir
+#define _treaddir      _wreaddir
+#define _trewinddir    _wrewinddir
+#define _ttelldir      _wtelldir
+#define _tseekdir      _wseekdir
+#else
+#define _tdirent       dirent
+#define _TDIR          DIR
+#define _topendir      opendir
+#define _tclosedir     closedir
+#define _treaddir      readdir
+#define _trewinddir    rewinddir
+#define _ttelldir      telldir
+#define _tseekdir      seekdir
+#endif
+
+#define SUFFIX _T("*")
+#define        SLASH   _T("\\")
+
+
+/*
+ * opendir
+ *
+ * Returns a pointer to a DIR structure appropriately filled in to begin
+ * searching a directory.
+ */
+_TDIR * 
+_topendir (const _TCHAR *szPath)
+{
+  _TDIR *nd;
+  unsigned int rc;
+  _TCHAR szFullPath[MAX_PATH];
+       
+  errno = 0;
+
+  if (!szPath)
+    {
+      errno = EFAULT;
+      return (_TDIR *) 0;
+    }
+
+  if (szPath[0] == _T('\0'))
+    {
+      errno = ENOTDIR;
+      return (_TDIR *) 0;
+    }
+
+  /* Attempt to determine if the given path really is a directory. */
+  rc = GetFileAttributes (szPath);
+  if (rc == (unsigned int)-1)
+    {
+      /* call GetLastError for more error info */
+      errno = ENOENT;
+      return (_TDIR *) 0;
+    }
+  if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
+    {
+      /* Error, entry exists but not a directory. */
+      errno = ENOTDIR;
+      return (_TDIR *) 0;
+    }
+
+  /* Make an absolute pathname.  */
+  _tfullpath (szFullPath, szPath, MAX_PATH);
+
+  /* Allocate enough space to store DIR structure and the complete
+   * directory path given. */
+  nd = (_TDIR *) malloc (sizeof (_TDIR) + (_tcslen(szFullPath) + _tcslen (SLASH) +
+                        _tcslen(SUFFIX) + 1) * sizeof(_TCHAR));
+
+  if (!nd)
+    {
+      /* Error, out of memory. */
+      errno = ENOMEM;
+      return (_TDIR *) 0;
+    }
+
+  /* Create the search expression. */
+  _tcscpy (nd->dd_name, szFullPath);
+
+  /* Add on a slash if the path does not end with one. */
+  if (nd->dd_name[0] != _T('\0') &&
+      nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('/') &&
+      nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('\\'))
+    {
+      _tcscat (nd->dd_name, SLASH);
+    }
+
+  /* Add on the search pattern */
+  _tcscat (nd->dd_name, SUFFIX);
+
+  /* Initialize handle to -1 so that a premature closedir doesn't try
+   * to call _findclose on it. */
+  nd->dd_handle = -1;
+
+  /* Initialize the status. */
+  nd->dd_stat = 0;
+
+  /* Initialize the dirent structure. ino and reclen are invalid under
+   * Win32, and name simply points at the appropriate part of the
+   * findfirst_t structure. */
+  nd->dd_dir.d_ino = 0;
+  nd->dd_dir.d_reclen = 0;
+  nd->dd_dir.d_namlen = 0;
+  memset (nd->dd_dir.d_name, 0, FILENAME_MAX);
+
+  return nd;
+}
+
+
+/*
+ * readdir
+ *
+ * Return a pointer to a dirent structure filled with the information on the
+ * next entry in the directory.
+ */
+struct _tdirent *
+_treaddir (_TDIR * dirp)
+{
+  errno = 0;
+
+  /* Check for valid DIR struct. */
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return (struct _tdirent *) 0;
+    }
+
+  if (dirp->dd_stat < 0)
+    {
+      /* We have already returned all files in the directory
+       * (or the structure has an invalid dd_stat). */
+      return (struct _tdirent *) 0;
+    }
+  else if (dirp->dd_stat == 0)
+    {
+      /* We haven't started the search yet. */
+      /* Start the search */
+      dirp->dd_handle = _tfindfirst (dirp->dd_name, &(dirp->dd_dta));
+
+         if (dirp->dd_handle == -1)
+       {
+         /* Whoops! Seems there are no files in that
+          * directory. */
+         dirp->dd_stat = -1;
+       }
+      else
+       {
+         dirp->dd_stat = 1;
+       }
+    }
+  else
+    {
+      /* Get the next search entry. */
+      if (_tfindnext (dirp->dd_handle, &(dirp->dd_dta)))
+       {
+         /* We are off the end or otherwise error.     
+            _findnext sets errno to ENOENT if no more file
+            Undo this. */ 
+         DWORD winerr = GetLastError();
+         if (winerr == ERROR_NO_MORE_FILES)
+           errno = 0;  
+         _findclose (dirp->dd_handle);
+         dirp->dd_handle = -1;
+         dirp->dd_stat = -1;
+       }
+      else
+       {
+         /* Update the status to indicate the correct
+          * number. */
+         dirp->dd_stat++;
+       }
+    }
+
+  if (dirp->dd_stat > 0)
+    {
+      /* Successfully got an entry. Everything about the file is
+       * already appropriately filled in except the length of the
+       * file name. */
+      dirp->dd_dir.d_namlen = _tcslen (dirp->dd_dta.name);
+      _tcscpy (dirp->dd_dir.d_name, dirp->dd_dta.name);
+      return &dirp->dd_dir;
+    }
+
+  return (struct _tdirent *) 0;
+}
+
+
+/*
+ * closedir
+ *
+ * Frees up resources allocated by opendir.
+ */
+int
+_tclosedir (_TDIR * dirp)
+{
+  int rc;
+
+  errno = 0;
+  rc = 0;
+
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return -1;
+    }
+
+  if (dirp->dd_handle != -1)
+    {
+      rc = _findclose (dirp->dd_handle);
+    }
+
+  /* Delete the dir structure. */
+  free (dirp);
+
+  return rc;
+}
+
+/*
+ * rewinddir
+ *
+ * Return to the beginning of the directory "stream". We simply call findclose
+ * and then reset things like an opendir.
+ */
+void
+_trewinddir (_TDIR * dirp)
+{
+  errno = 0;
+
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return;
+    }
+
+  if (dirp->dd_handle != -1)
+    {
+      _findclose (dirp->dd_handle);
+    }
+
+  dirp->dd_handle = -1;
+  dirp->dd_stat = 0;
+}
+
+/*
+ * telldir
+ *
+ * Returns the "position" in the "directory stream" which can be used with
+ * seekdir to go back to an old entry. We simply return the value in stat.
+ */
+long
+_ttelldir (_TDIR * dirp)
+{
+  errno = 0;
+
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return -1;
+    }
+  return dirp->dd_stat;
+}
+
+/*
+ * seekdir
+ *
+ * Seek to an entry previously returned by telldir. We rewind the directory
+ * and call readdir repeatedly until either dd_stat is the position number
+ * or -1 (off the end). This is not perfect, in that the directory may
+ * have changed while we weren't looking. But that is probably the case with
+ * any such system.
+ */
+void
+_tseekdir (_TDIR * dirp, long lPos)
+{
+  errno = 0;
+
+  if (!dirp)
+    {
+      errno = EFAULT;
+      return;
+    }
+
+  if (lPos < -1)
+    {
+      /* Seeking to an invalid position. */
+      errno = EINVAL;
+      return;
+    }
+  else if (lPos == -1)
+    {
+      /* Seek past end. */
+      if (dirp->dd_handle != -1)
+       {
+         _findclose (dirp->dd_handle);
+       }
+      dirp->dd_handle = -1;
+      dirp->dd_stat = -1;
+    }
+  else
+    {
+      /* Rewind and read forward to the appropriate index. */
+      _trewinddir (dirp);
+
+      while ((dirp->dd_stat < lPos) && _treaddir (dirp))
+       ;
+    }
+}
diff --git a/support/cpp2/win32/dirent.h b/support/cpp2/win32/dirent.h
new file mode 100644 (file)
index 0000000..53c4dc8
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * DIRENT.H (formerly DIRLIB.H)
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is a part of the mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within the package.
+ *
+ */
+#ifndef _DIRENT_H_
+#define _DIRENT_H_
+
+#include <stdio.h>
+#include <io.h>
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dirent
+{
+       long            d_ino;          /* Always zero. */
+       unsigned short  d_reclen;       /* Always zero. */
+       unsigned short  d_namlen;       /* Length of name in d_name. */
+       char            d_name[FILENAME_MAX]; /* File name. */
+};
+
+/*
+ * This is an internal data structure. Good programmers will not use it
+ * except as an argument to one of the functions below.
+ * dd_stat field is now int (was short in older versions).
+ */
+typedef struct
+{
+       /* disk transfer area for this dir */
+       struct _finddata_t      dd_dta;
+
+       /* dirent struct to return from dir (NOTE: this makes this thread
+        * safe as long as only one thread uses a particular DIR struct at
+        * a time) */
+       struct dirent           dd_dir;
+
+       /* _findnext handle */
+       long                    dd_handle;
+
+       /*
+         * Status of search:
+        *   0 = not started yet (next entry to read is first entry)
+        *  -1 = off the end
+        *   positive = 0 based index of next entry
+        */
+       int                     dd_stat;
+
+       /* given path for dir with search pattern (struct is extended) */
+       char                    dd_name[1];
+} DIR;
+
+DIR* __cdecl opendir (const char*);
+struct dirent* __cdecl readdir (DIR*);
+int __cdecl closedir (DIR*);
+void __cdecl rewinddir (DIR*);
+long __cdecl telldir (DIR*);
+void __cdecl seekdir (DIR*, long);
+
+
+/* wide char versions */
+
+struct _wdirent
+{
+       long            d_ino;          /* Always zero. */
+       unsigned short  d_reclen;       /* Always zero. */
+       unsigned short  d_namlen;       /* Length of name in d_name. */
+       wchar_t         d_name[FILENAME_MAX]; /* File name. */
+};
+
+/*
+ * This is an internal data structure. Good programmers will not use it
+ * except as an argument to one of the functions below.
+ */
+typedef struct
+{
+       /* disk transfer area for this dir */
+       struct _wfinddata_t     dd_dta;
+
+       /* dirent struct to return from dir (NOTE: this makes this thread
+        * safe as long as only one thread uses a particular DIR struct at
+        * a time) */
+       struct _wdirent         dd_dir;
+
+       /* _findnext handle */
+       long                    dd_handle;
+
+       /*
+         * Status of search:
+        *   0 = not started yet (next entry to read is first entry)
+        *  -1 = off the end
+        *   positive = 0 based index of next entry
+        */
+       int                     dd_stat;
+
+       /* given path for dir with search pattern (struct is extended) */
+       wchar_t                 dd_name[1];
+} _WDIR;
+
+
+
+_WDIR* __cdecl _wopendir (const wchar_t*);
+struct _wdirent*  __cdecl _wreaddir (_WDIR*);
+int __cdecl _wclosedir (_WDIR*);
+void __cdecl _wrewinddir (_WDIR*);
+long __cdecl _wtelldir (_WDIR*);
+void __cdecl _wseekdir (_WDIR*, long);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* Not RC_INVOKED */
+
+#endif /* Not _DIRENT_H_ */