+2006-12-31 Borut Razem <borut.razem AT siol.net>
+
+ * SDCPP synchronized with GCC CPP release version 4.1.1,
+ currently the latest release:
+ * support/cpp2/libcpp, support/cpp2/libcpp/include,
+ support/cpp2/libcpp/include/cpp-id-data.h
+ support/cpp2/libiberty/fopen_unlocked.c
+ support/cpp2/libiberty/md5.c
+ support/cpp2/md5.h
+ support/cpp2/opt-functions.awk
+ support/cpp2/opt-gather.awk
+ support/cpp2/optc-gen.awk
+ support/cpp2/opth-gen.awk:
+ added
+ * support/cpp2/Makefile.in, support/cpp2/auto-host_vc_in.h,
+ 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/cppdefault.c,
+ support/cpp2/cppdefault.h, support/cpp2/diagnostic.c,
+ support/cpp2/diagnostic.h, support/cpp2/except.h,
+ support/cpp2/hwint.h, support/cpp2/input.h,
+ support/cpp2/intl.h, support/cpp2/move-if-change,
+ support/cpp2/opts.c, support/cpp2/opts.h,
+ support/cpp2/output.h, support/cpp2/prefix.c,
+ support/cpp2/prefix.h, support/cpp2/pretty-print.c,
+ support/cpp2/pretty-print.h, support/cpp2/sdcpp-opts.c,
+ support/cpp2/sdcpp.c, support/cpp2/sdcpp.dsp,
+ support/cpp2/sdcpp.h, support/cpp2/sdcpp.opt,
+ support/cpp2/sdcppa.dsp, support/cpp2/symcat.h,
+ support/cpp2/version.c:
+ modified
+ * support/cpp2/libcpp/charset.c, support/cpp2/libcpp/directives.c,
+ support/cpp2/libcpp/errors.c, support/cpp2/libcpp/expr.c,
+ support/cpp2/libcpp/files.c, support/cpp2/libcpp/identifiers.c,
+ support/cpp2/libcpp/include/cpplib.h, support/cpp2/libcpp/include/line-map.h,
+ support/cpp2/libcpp/include/mkdeps.h, support/cpp2/libcpp/include/symtab.h,
+ support/cpp2/libcpp/init.c, support/cpp2/libcpp/internal.h,
+ support/cpp2/libcpp/lex.c, support/cpp2/libcpp/line-map.c,
+ support/cpp2/libcpp/macro.c, support/cpp2/libcpp/mkdeps.c,
+ support/cpp2/libcpp/symtab.c, support/cpp2/libcpp/system.h,
+ support/cpp2/libcpp/traditional.c, support/cpp2/libcpp/ucnid.h,
+ support/cpp2/libiberty/hashtab.c, support/cpp2/libiberty/hashtab.h:
+ moved
+ * support/cpp2/cppcharset.c, 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, support/cpp2/hashtab.c,
+ support/cpp2/hashtab.h, support/cpp2/hashtable.c,
+ support/cpp2/hashtable.h, support/cpp2/line-map.c,
+ support/cpp2/line-map.h, support/cpp2/mkdeps.c,
+ support/cpp2/mkdeps.h, support/cpp2/options_vc_in.c,
+ support/cpp2/options_vc_in.h, support/cpp2/opts.sh,
+ support/cpp2/system.h:
+ deleted / moved
+
2006-12-31 Borut Razem <borut.razem AT siol.net>
* configure.in, configure: fixed bug #1538756: configure dies if bison
# Where to find some libiberty headers.
LIBIBERTY_DIR = $(srcdir)/libiberty
+LIBCPP_DIR = $(srcdir)/libcpp
OBSTACK_H = $(LIBIBERTY_DIR)/obstack.h
SPLAY_TREE_H= $(LIBIBERTY_DIR)/splay-tree.h
transform = @program_transform_name@
lang_opt_files=$(srcdir)/sdcpp.opt
+# All option source files
+ALL_OPT_FILES=$(lang_opt_files) $(extra_opt_files)
+
# Top build directory, relative to here.
top_builddir = @top_builddir@
#@build_overrides@
#\f
-INCLUDES = -I$(srcdir) -I$(LIBIBERTY_DIR) -I.
+INCLUDES = -I$(srcdir) -I$(LIBCPP_DIR) -I$(LIBCPP_DIR)/include -I$(LIBIBERTY_DIR) -I.
# Always use -I$(srcdir)/config when compiling.
.c.o:
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)
+optionlist: s-options ; @true
+s-options: $(ALL_OPT_FILES) Makefile $(srcdir)/opt-gather.awk
+ $(AWK) -f $(srcdir)/opt-gather.awk $(ALL_OPT_FILES) > tmp-optionlist
+ $(SHELL) $(srcdir)/move-if-change tmp-optionlist optionlist
+ $(STAMP) s-options
+
+options.c: optionlist $(srcdir)/opt-functions.awk $(srcdir)/optc-gen.awk
+ $(AWK) -f $(srcdir)/opt-functions.awk -f $(srcdir)/optc-gen.awk \
+ -v header_name="config.h system.h options.h" < $< > $@
+
+options.h: s-options-h ; @true
+s-options-h: optionlist $(srcdir)/opt-functions.awk $(srcdir)/opth-gen.awk
+ $(AWK) -f $(srcdir)/opt-functions.awk -f $(srcdir)/opth-gen.awk \
+ < $< > tmp-options.h
+ $(SHELL) $(srcdir)/move-if-change tmp-options.h options.h
+ $(STAMP) $@
version.o: version.c version.h
hashtable.o: hashtable.c hashtable.h $(CONFIG_H) $(SYSTEM_H) $(OBSTACK_H)
-hashtab.o: hashtab.c hashtab.h $(CONFIG_H)
-
cppcharset.o: cppcharset.c $(CONFIG_H) $(SYSTEM_H)
prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) Makefile prefix.h
-DCROSS_INCLUDE_DIR=\"$(gcc_tooldir)/sys-include\" \
-DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\"
-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 \
- line-map.o cpptrad.o cppcharset.o hashtab.o \
- opts.o options.o diagnostic.o pretty-print.o c-incpath.o
+##########################
+# Libcpp
+
+LIBCPP_OBJS = charset.o directives.o errors.o expr.o files.o identifiers.o \
+ init.o lex.o line-map.o macro.o mkdeps.o symtab.o traditional.o
-LIBCPP_DEPS = cpplib.h cpphash.h hashtable.h intl.h options.h $(OBSTACK_H) $(SYSTEM_H)
+
+##LIBCPP_DEPS = cpplib.h cpphash.h hashtable.h intl.h options.h $(OBSTACK_H) $(SYSTEM_H)
# Most of the other archives built/used by this makefile are for
# targets. This one is strictly for the host.
$(AR) $(AR_FLAGS) libcpp.a $(LIBCPP_OBJS)
-$(RANLIB) libcpp.a
-MY_LIBIBERTY_BITS = concat.o getpwd.o hex.o lbasename.o obstack.o \
- safe-ctype.o splay-tree.o vasprintf.o xexit.o xmalloc.o \
- xmemdup.o xstrdup.o xstrerror.o
+charset.o: $(LIBCPP_DIR)/charset.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-$(TARGET): sdcpp.o sdcpp-opts.o $(MY_LIBIBERTY_BITS) libcpp.a $(LIBDEPS)
- mkdir -p $(dir $@)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ sdcpp.o sdcpp-opts.o \
- $(MY_LIBIBERTY_BITS) libcpp.a $(LIBS)
+directives.o: $(LIBCPP_DIR)/directives.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-sdcpp.o: sdcpp.c $(CONFIG_H) cpplib.h $(SYSTEM_H) options.h
-sdcpp-opts.o: sdcpp-opts.c $(CONFIG_H) $(LIBCPP_DEPS) options.h
+errors.o: $(LIBCPP_DIR)/errors.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-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)
-cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS)
-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
+expr.o: $(LIBCPP_DIR)/expr.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
+files.o: $(LIBCPP_DIR)/files.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+identifiers.o: $(LIBCPP_DIR)/identifiers.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+init.o: $(LIBCPP_DIR)/init.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+lex.o: $(LIBCPP_DIR)/lex.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+line-map.o: $(LIBCPP_DIR)/line-map.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+macro.o: $(LIBCPP_DIR)/macro.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+mkdeps.o: $(LIBCPP_DIR)/mkdeps.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-mkdeps.o: mkdeps.c $(CONFIG_H) $(SYSTEM_H) mkdeps.h
+symtab.o: $(LIBCPP_DIR)/symtab.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+traditional.o: $(LIBCPP_DIR)/traditional.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+##########################
# Libiberty
-concat.o: $(LIBIBERTY_DIR)/concat.c $(CONFIG_H) $(LIBCPP_DEPS)
+MY_LIBIBERTY_BITS = concat.o fopen_unlocked.o getpwd.o hashtab.o hex.o \
+ lbasename.o md5.o obstack.o safe-ctype.o splay-tree.o \
+ vasprintf.o xexit.o xmalloc.o xmemdup.o xstrdup.o \
+ xstrerror.o
+
+concat.o: $(LIBIBERTY_DIR)/concat.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+fopen_unlocked.o: $(LIBIBERTY_DIR)/fopen_unlocked.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+getpwd.o: $(LIBIBERTY_DIR)/getpwd.c $(CONFIG_H) $(LIBCPP_DEPS)
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-getpwd.o: $(LIBIBERTY_DIR)/getpwd.c $(CONFIG_H) $(LIBCPP_DEPS)
+hashtab.o: $(LIBIBERTY_DIR)/hashtab.c $(CONFIG_H) $(LIBCPP_DEPS)
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-hex.o: $(LIBIBERTY_DIR)/hex.c $(CONFIG_H) $(LIBCPP_DEPS)
+hex.o: $(LIBIBERTY_DIR)/hex.c $(CONFIG_H) $(LIBCPP_DEPS)
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
-lbasename.o: $(LIBIBERTY_DIR)/lbasename.c $(CONFIG_H) $(LIBCPP_DEPS)
+lbasename.o: $(LIBIBERTY_DIR)/lbasename.c $(CONFIG_H) $(LIBCPP_DEPS)
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+md5.o: $(LIBIBERTY_DIR)/md5.c $(LIBIBERTY_DIR)/obstack.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)
xstrerror.o: $(LIBIBERTY_DIR)/xstrerror.c $(CONFIG_H) $(LIBCPP_DEPS)
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+
+##########################
+# Sdcpp
+
+SDCC_OBJS = sdcpp.o sdcpp-opts.o c-ppoutput.o cppdefault.o prefix.o version.o opts.o options.o diagnostic.o pretty-print.o c-incpath.o
+
+$(TARGET): $(SDCC_OBJS) $(MY_LIBIBERTY_BITS) libcpp.a $(LIBDEPS)
+ mkdir -p $(dir $@)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(SDCC_OBJS) \
+ $(MY_LIBIBERTY_BITS) libcpp.a $(LIBS)
+
+sdcpp.o: sdcpp.c $(CONFIG_H) $(SYSTEM_H) options.h
+
+sdcpp-opts.o: sdcpp-opts.c $(CONFIG_H) $(LIBCPP_DEPS) options.h
+
+c-ppoutput.o: c-ppoutput.c $(CONFIG_H) $(SYSTEM_H)
+
+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
#include <sys/stat.h>
#include <io.h>
#include <malloc.h>
+#include <stdio.h>
#define HAVE_STRINGIZE
-#define STDC_HEADERS
+#define STDC_HEADERS 1
#define PACKAGE "sdcc"
#define LOCALEDIR ""
#define PREFIX ""
/* 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
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.\r
\r
Broken out of cppinit.c and cppfiles.c and rewritten Mar 2003.\r
\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
+Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */\r
\r
#include "config.h"\r
#include "system.h"\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
+# 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
path[q - p] = '\0';\r
}\r
\r
- add_path (path, chain, chain == SYSTEM);\r
+ add_path (path, chain, chain == SYSTEM, false);\r
}\r
}\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
+ "Translate" them, i.e. replace /usr/local/lib/gcc... with\r
IPREFIX and search them first. */\r
for (p = cpp_include_defaults; p->fname; p++)\r
{\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
+ add_path (str, SYSTEM, p->cxx_aware, false);\r
}\r
}\r
}\r
else\r
str = update_path (p->fname, p->component);\r
\r
- add_path (str, SYSTEM, p->cxx_aware);\r
+ add_path (str, SYSTEM, p->cxx_aware, false);\r
}\r
}\r
}\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
+\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
if (errno != ENOENT)\r
cpp_errno (pfile, CPP_DL_ERROR, cur->name);\r
else\r
- reason = REASON_NOENT;\r
+ {\r
+ /* If -Wmissing-include-dirs is given, warn. */\r
+ cpp_options *opts = cpp_get_options (pfile);\r
+ if (opts->warn_missing_include_dirs && cur->user_supplied_p)\r
+ cpp_errno (pfile, CPP_DL_WARNING, cur->name);\r
+ reason = REASON_NOENT;\r
+ }\r
}\r
else if (!S_ISDIR (st.st_mode))\r
cpp_error_with_line (pfile, CPP_DL_ERROR, 0, 0,\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
+ if (INO_T_EQ (tmp->ino, cur->ino) && tmp->dev == cur->dev\r
+ && cur->construct == tmp->construct)\r
break;\r
\r
if (!tmp)\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
+ if (INO_T_EQ (cur->ino, tmp->ino) && cur->dev == tmp->dev\r
+ && cur->construct == tmp->construct)\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
+ && cur->dev == join->dev\r
+ && cur->construct == join->construct))\r
{\r
/* Unique, so keep this directory. */\r
pcur = &cur->next;\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
+ there; consider -iquote foo -iquote bar -Ifoo -Iquux. It is\r
+ however safe to treat -iquote bar -iquote foo -Ifoo -Iquux as if\r
+ written -iquote bar -Ifoo -Iquux. */\r
+\r
static void\r
merge_include_chains (cpp_reader *pfile, int verbose)\r
{\r
quote_ignores_source_dir = true;\r
}\r
\r
+/* Add P to the chain specified by CHAIN. */\r
+\r
+void\r
+add_cpp_dir_path (cpp_dir *p, int chain)\r
+{\r
+ if (tails[chain])\r
+ tails[chain]->next = p;\r
+ else\r
+ heads[chain] = p;\r
+ tails[chain] = p;\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
+add_path (char *path, int chain, int cxx_aware, bool user_supplied_p)\r
{\r
- struct cpp_dir *p;\r
+ 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
+ function does not recognize 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
if (*c == '\\') *c = '/';\r
#endif\r
\r
- p = xmalloc (sizeof (struct cpp_dir));\r
+ p = xmalloc (sizeof (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
+ p->construct = 0;\r
+ p->user_supplied_p = user_supplied_p;\r
\r
- if (tails[chain])\r
- tails[chain]->next = p;\r
- else\r
- heads[chain] = p;\r
- tails[chain] = p;\r
+ add_cpp_dir_path (p, chain);\r
}\r
\r
/* Exported function to handle include chain merging, duplicate\r
add_env_var_paths ("CPATH", BRACKET);\r
add_env_var_paths (lang_env_vars[idx], SYSTEM);\r
\r
+ target_c_incpath.extra_pre_includes (sysroot, iprefix, stdinc);\r
+\r
/* Finally chain on the standard directories. */\r
if (stdinc)\r
add_standard_paths (sysroot, iprefix, cxx_stdinc);\r
\r
+ target_c_incpath.extra_includes (sysroot, iprefix, 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
+#if !(defined TARGET_EXTRA_INCLUDES) || !(defined TARGET_EXTRA_PRE_INCLUDES)\r
+static void hook_void_charptr_charptr_int (const char *sysroot ATTRIBUTE_UNUSED,\r
+ const char *iprefix ATTRIBUTE_UNUSED,\r
+ int stdinc ATTRIBUTE_UNUSED)\r
+{\r
+}\r
+#endif\r
+\r
+#ifndef TARGET_EXTRA_INCLUDES\r
+#define TARGET_EXTRA_INCLUDES hook_void_charptr_charptr_int\r
+#endif\r
+#ifndef TARGET_EXTRA_PRE_INCLUDES\r
+#define TARGET_EXTRA_PRE_INCLUDES hook_void_charptr_charptr_int\r
+#endif\r
+\r
+struct target_c_incpath_s target_c_incpath = { TARGET_EXTRA_PRE_INCLUDES, TARGET_EXTRA_INCLUDES };\r
+\r
/* Set up combined include path for the preprocessor.
- Copyright (C) 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 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
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. */
+Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
extern void split_quote_chain (void);
-extern void add_path (char *, int, int);
+extern void add_path (char *, int, int, bool);
extern void register_include_chains (cpp_reader *, const char *,
const char *, int, int, int);
+extern void add_cpp_dir_path (struct cpp_dir *, int);
+
+struct target_c_incpath_s {
+ /* Do extra includes processing. STDINC is false iff -nostdinc was given. */
+ void (*extra_pre_includes) (const char *, const char *, int);
+ void (*extra_includes) (const char *, const char *, int);
+};
+
+extern struct target_c_incpath_s target_c_incpath;
enum { QUOTE = 0, BRACKET, SYSTEM, AFTER };
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. */
+Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "cpplib.h"
-#include "cpphash.h"
+#include "../libcpp/internal.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. */
+ int src_line; /* Line number currently being written. */
unsigned char printed; /* Nonzero if something output at line. */
+ bool first_time; /* pp_file_change hasn't been called yet. */
} print;
/* General output routines. */
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);
+static void print_line (source_location, const char *);
+static void maybe_print_line (source_location);
/* 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);
+static void cb_define (cpp_reader *, source_location, cpp_hashnode *);
+static void cb_undef (cpp_reader *, source_location, cpp_hashnode *);
+static void cb_include (cpp_reader *, source_location, const unsigned char *,
+ const char *, int, const cpp_token **);
+static void cb_ident (cpp_reader *, source_location, const cpp_string *);
+static void cb_def_pragma (cpp_reader *, source_location);
+#if 0
+static void cb_read_pch (cpp_reader *pfile, const char *name,
+ int fd, const char *orig_name);
+#endif
/* Preprocess and output. */
void
if (flag_dump_includes)
cb->include = cb_include;
+#if 0
+ if (flag_pch_preprocess)
+ {
+ cb->valid_pch = c_common_valid_pch;
+ cb->read_pch = cb_read_pch;
+ }
+#endif
+
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
+ /* Initialize the print structure. Setting print.src_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.src_line = -1;
print.printed = 0;
print.prev = 0;
- print.map = 0;
print.outf = out_stream;
+ print.first_time = 1;
}
/* Writes out the preprocessed file, handling spacing and paste
}
}
-/* Adjust print.line for newlines embedded in output. */
+/* Adjust print.src_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++;
+ print.src_line++;
}
/* Writes out a traditionally preprocessed file. */
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);
+ maybe_print_line (pfile->out.first_line);
fwrite (pfile->out.base, 1, len, print.outf);
print.printed = 1;
if (!CPP_OPTION (pfile, discard_comments))
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)
+maybe_print_line (source_location src_loc)
{
+ const struct line_map *map = linemap_lookup (&line_table, src_loc);
+ int src_line = SOURCE_LINE (map, src_loc);
/* End the previous line of text. */
if (print.printed)
{
putc ('\n', print.outf);
- print.line++;
+ print.src_line++;
print.printed = 0;
}
- if (line >= print.line && line < print.line + 8)
+ if (src_line >= print.src_line && src_line < print.src_line + 8)
{
- while (line > print.line)
+ while (src_line > print.src_line)
{
putc ('\n', print.outf);
- print.line++;
+ print.src_line++;
}
}
else
- print_line (map, line, "");
+ print_line (src_loc, "");
}
/* 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)
+print_line (source_location src_loc, 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)
{
+ const struct line_map *map = linemap_lookup (&line_table, src_loc);
+
size_t to_file_len = strlen (map->to_file);
unsigned char *to_file_quoted = alloca (to_file_len * 4 + 1);
unsigned char *p;
+ print.src_line = SOURCE_LINE (map, src_loc);
+
/* 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);
+ (unsigned char *) map->to_file, to_file_len);
*p = '\0';
fprintf (print.outf, "# %u \"%s\"%s",
- SOURCE_LINE (map, print.line),
+ print.src_line == 0 ? 1 : print.src_line,
to_file_quoted, special_flags);
if (map->sysp == 2)
cb_line_change (cpp_reader *pfile, const cpp_token *token,
int parsing_args)
{
+ source_location src_loc = token->src_loc;
+
if (token->type == CPP_EOF || parsing_args)
return;
- maybe_print_line (print.map, token->line);
+ maybe_print_line (src_loc);
print.prev = 0;
print.source = 0;
ought to care. Some things do care; the fault lies with them. */
if (!CPP_OPTION (pfile, traditional))
{
+ const struct line_map *map = linemap_lookup (&line_table, src_loc);
+ int spaces = SOURCE_COLUMN (map, src_loc) - 2;
print.printed = 1;
- if (token->col > 2)
- {
- unsigned int spaces = token->col - 2;
- while (spaces--)
- putc (' ', print.outf);
- }
+ while (-- spaces >= 0)
+ putc (' ', print.outf);
}
}
static void
-cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line,
+cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line,
const cpp_string *str)
{
- maybe_print_line (print.map, line);
+ maybe_print_line (line);
fprintf (print.outf, "#ident %s\n", str->text);
- print.line++;
+ print.src_line++;
}
static void
-cb_define (cpp_reader *pfile, fileline line, cpp_hashnode *node)
+cb_define (cpp_reader *pfile, source_location line, cpp_hashnode *node)
{
- maybe_print_line (print.map, line);
+ maybe_print_line (line);
fputs ("#define ", print.outf);
/* 'D' is whole definition; 'N' is name only. */
fputs ((const char *) NODE_NAME (node), print.outf);
putc ('\n', print.outf);
- print.line++;
+ print.src_line++;
}
static void
-cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line,
+cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line,
cpp_hashnode *node)
{
- maybe_print_line (print.map, line);
+ maybe_print_line (line);
fprintf (print.outf, "#undef %s\n", NODE_NAME (node));
- print.line++;
+ print.src_line++;
}
static void
-cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, fileline line,
- const unsigned char *dir, const char *header, int angle_brackets)
+cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line,
+ const unsigned char *dir, const char *header, int angle_brackets,
+ const cpp_token **comments)
{
- maybe_print_line (print.map, line);
+ maybe_print_line (line);
if (angle_brackets)
- fprintf (print.outf, "#%s <%s>\n", dir, header);
+ fprintf (print.outf, "#%s <%s>", dir, header);
else
- fprintf (print.outf, "#%s \"%s\"\n", dir, header);
- print.line++;
+ fprintf (print.outf, "#%s \"%s\"", dir, header);
+
+ if (comments != NULL)
+ {
+ while (*comments != NULL)
+ {
+ if ((*comments)->flags & PREV_WHITE)
+ putc (' ', print.outf);
+ cpp_output_token (*comments, print.outf);
+ ++comments;
+ }
+ }
+
+ putc ('\n', print.outf);
+ print.src_line++;
}
/* Callback called when -fworking-director and -E to emit working
- diretory in cpp output file. */
+ directory in cpp output file. */
void
pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *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. */
+ /* 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. */
+ described in MAP. */
void
pp_file_change (const struct line_map *map)
if (map != NULL)
{
- /* First time? */
- if (print.map == NULL)
+ if (print.first_time)
{
/* 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);
+ print_line (map->start_location, flags);
+ print.first_time = 0;
}
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);
-
+ {
+ const struct line_map *from = INCLUDED_FROM (&line_table, map);
+ maybe_print_line (LAST_SOURCE_LINE_LOCATION (from));
+ }
if (map->reason == LC_ENTER)
flags = " 1";
else if (map->reason == LC_LEAVE)
flags = " 2";
- print_line (map, map->from_line, flags);
+ print_line (map->start_location, flags);
}
}
-
- print.map = map;
}
/* Copy a #pragma directive to the preprocessed output. */
static void
-cb_def_pragma (cpp_reader *pfile, fileline line)
+cb_def_pragma (cpp_reader *pfile, source_location line)
{
- maybe_print_line (print.map, line);
+ maybe_print_line (line);
fputs ("#pragma ", print.outf);
cpp_output_line (pfile, print.outf);
- print.line++;
+ print.src_line++;
}
/* Dump out the hash table. */
fputs ((const char *) cpp_macro_definition (pfile, node),
print.outf);
putc ('\n', print.outf);
- print.line++;
+ print.src_line++;
}
return 1;
}
+
+#if 0
+/* Load in the PCH file NAME, open on FD. It was originally searched for
+ by ORIG_NAME. Also, print out a #include command so that the PCH
+ file can be loaded when the preprocessed output is compiled. */
+
+static void
+cb_read_pch (cpp_reader *pfile, const char *name,
+ int fd, const char *orig_name ATTRIBUTE_UNUSED)
+{
+ c_common_read_pch (pfile, name, fd, orig_name);
+
+ fprintf (print.outf, "#pragma GCC pch_preprocess \"%s\"\n", name);
+ print.src_line++;
+}
+#endif
\ No newline at end of file
/* Subroutines common to both C and C++ pretty-printers.
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
+#include "real.h"
#include "c-pretty-print.h"
/* The pretty-printer code is primarily designed to closely follow
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);
pp_base (pp)->padding = pp_none;
}
+void
+pp_c_left_bracket (c_pretty_printer *pp)
+{
+ pp_left_bracket (pp);
+ pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_right_bracket (c_pretty_printer *pp)
+{
+ pp_right_bracket (pp);
+ pp_base (pp)->padding = pp_none;
+}
+
void
pp_c_dot (c_pretty_printer *pp)
{
pp_base (pp)->padding = pp_none;
}
+void
+pp_c_star (c_pretty_printer *pp)
+{
+ pp_star (pp);
+ pp_base (pp)->padding = pp_none;
+}
+
void
pp_c_arrow (c_pretty_printer *pp)
{
}
void
-pp_c_semicolon(c_pretty_printer *pp)
+pp_c_semicolon (c_pretty_printer *pp)
{
pp_semicolon (pp);
pp_base (pp)->padding = pp_none;
}
+void
+pp_c_complement (c_pretty_printer *pp)
+{
+ pp_complement (pp);
+ pp_base (pp)->padding = pp_none;
+}
+
+void
+pp_c_exclamation (c_pretty_printer *pp)
+{
+ pp_exclamation (pp);
+ pp_base (pp)->padding = pp_none;
+}
+
+/* Print out the external representation of CV-QUALIFIER. */
+
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 == '*')
+ /* The C programming language does not have references, but it is much
+ simpler to handle those here rather than going through the same
+ logic in the C++ pretty-printer. */
+ if (p != NULL && (*p == '*' || *p == '&'))
pp_c_whitespace (pp);
pp_c_identifier (pp, cv);
}
pp_c_right_paren (pp);
}
+/* We're about to pretty-print a pointer type as indicated by T.
+ Output a whitespace, if needed, preparing for subsequent output. */
+
void
pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t)
{
pp_c_type_qualifier_list (c_pretty_printer *pp, tree t)
{
int qualifiers;
-
+
if (!TYPE_P (t))
t = TREE_TYPE (t);
pp_c_type_qualifier_list (pp, t);
break;
+ /* ??? This node is now in GENERIC and so shouldn't be here. But
+ we'll fix that later. */
+ case DECL_EXPR:
+ pp_declaration (pp, DECL_EXPR_DECL (t));
+ pp_needs_newline (pp) = true;
+ break;
+
default:
pp_unsupported_tree (pp, t);
}
break;
case IDENTIFIER_NODE:
- pp_c_tree_identifier (pp, t);
+ pp_c_tree_decl_identifier (pp, t);
break;
case VOID_TYPE:
case INTEGER_TYPE:
case REAL_TYPE:
if (TYPE_NAME (t))
- t = TYPE_NAME (t);
+ {
+ t = TYPE_NAME (t);
+ pp_c_type_specifier (pp, t);
+ }
else
- t = c_common_type_for_mode (TYPE_MODE (t), TREE_UNSIGNED (t));
- pp_c_type_specifier (pp, t);
+ {
+ int prec = TYPE_PRECISION (t);
+ t = c_common_type_for_mode (TYPE_MODE (t), TYPE_UNSIGNED (t));
+ if (TYPE_NAME (t))
+ {
+ pp_c_type_specifier (pp, t);
+ if (TYPE_PRECISION (t) != prec)
+ {
+ pp_string (pp, ":");
+ pp_decimal_int (pp, prec);
+ }
+ }
+ else
+ {
+ switch (code)
+ {
+ case INTEGER_TYPE:
+ pp_string (pp, (TYPE_UNSIGNED (t)
+ ? "<unnamed-unsigned:"
+ : "<unnamed-signed:"));
+ break;
+ case REAL_TYPE:
+ pp_string (pp, "<unnamed-float:");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ pp_decimal_int (pp, prec);
+ pp_string (pp, ">");
+ }
+ }
break;
case TYPE_DECL:
pp_c_whitespace (pp);
pp_c_left_paren (pp);
}
+ else if (!c_dialect_cxx ())
+ pp_c_whitespace (pp);
pp_ptr_operator (pp, t);
}
break;
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));
case ARRAY_TYPE:
pp_c_left_bracket (pp);
- if (TYPE_DOMAIN (t))
+ if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (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));
case COMPLEX_TYPE:
case TYPE_DECL:
break;
-
+
default:
pp_unsupported_tree (pp, t);
break;
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 ( parameter-type-list )
direct-declarator ( identifier-list(opt) ) */
void
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));
- }
+ pp_c_space_for_pointer_operator (pp, TREE_TYPE (t));
+ pp_c_tree_decl_identifier (pp, t);
+ break;
+
case ARRAY_TYPE:
case POINTER_TYPE:
pp_abstract_declarator (pp, TREE_TYPE (t));
case FUNCTION_DECL:
pp_c_space_for_pointer_operator (pp, TREE_TYPE (TREE_TYPE (t)));
- pp_c_tree_identifier (pp, DECL_NAME (t));
+ pp_c_tree_decl_identifier (pp, t);
if (pp_c_base (pp)->flags & pp_c_flag_abstract)
pp_abstract_declarator (pp, TREE_TYPE (t));
else
pp_direct_declarator (pp, t);
break;
-
+
default:
pp_unsupported_tree (pp, t);
break;
\f
/* Expressions. */
-/* Print out a c-char. */
+/* Print out a c-char. This is called solely for characters which are
+ in the *target* execution character set. We ought to convert them
+ back to the *host* execution character set before printing, but we
+ have no way to do this at present. A decent compromise is to print
+ all characters as if they were in the host execution character set,
+ and not attempt to recover any named escape characters, but render
+ all unprintables as octal escapes. If the host and target character
+ sets are the same, this produces relatively readable output. If they
+ are not the same, strings may appear as gibberish, but that's okay
+ (in fact, it may well be what the reader wants, e.g. if they are looking
+ to see if conversion to the target character set happened correctly).
+
+ A special case: we need to prefix \, ", and ' with backslashes. It is
+ correct to do so for the *host*'s \, ", and ', because the rest of the
+ file appears in the host character set. */
static void
pp_c_char (c_pretty_printer *pp, int c)
{
- switch (c)
+ if (ISPRINT (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;
+ switch (c)
+ {
+ case '\\': pp_string (pp, "\\\\"); break;
+ case '\'': pp_string (pp, "\\\'"); break;
+ case '\"': pp_string (pp, "\\\""); break;
+ default: pp_character (pp, c);
+ }
}
+ else
+ pp_scalar (pp, "\\%03o", (unsigned) c);
}
/* Print out a STRING literal. */
pp_doublequote (pp);
}
+/* Pretty-print an INTEGER literal. */
+
static void
pp_c_integer_constant (c_pretty_printer *pp, tree i)
{
{
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));
+ pp_character (pp, '-');
+ i = build_int_cst_wide (NULL_TREE,
+ -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))
+ if (TYPE_UNSIGNED (type))
pp_character (pp, 'u');
if (type == long_integer_type_node || type == long_unsigned_type_node)
pp_character (pp, 'l');
{
tree type = TREE_TYPE (c);
if (type == wchar_type_node)
- pp_character (pp, 'L');
+ 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)));
+ if (host_integerp (c, TYPE_UNSIGNED (type)))
+ pp_c_char (pp, tree_low_cst (c, TYPE_UNSIGNED (type)));
else
pp_scalar (pp, "\\x%x", (unsigned) TREE_INT_CST_LOW (c));
pp_quote (pp);
}
/* Pretty-print a compound literal expression. GNU extensions include
- vector constants. */
+ vector constants. */
static void
pp_c_compound_literal (c_pretty_printer *pp, tree e)
{
- tree type = TREE_TYPE (e);
+ tree type = TREE_TYPE (e);
pp_c_type_cast (pp, type);
switch (TREE_CODE (type))
pp_c_character_constant (pp, e);
else if (TREE_CODE (type) == ENUMERAL_TYPE
&& pp_c_enumeration_constant (pp, e))
- ;
- else
+ ;
+ else
pp_c_integer_constant (pp, e);
}
break;
}
}
+/* Pretty-print an IDENTIFIER_NODE, preceded by whitespace is necessary. */
+
void
pp_c_identifier (c_pretty_printer *pp, const char *id)
{
- pp_c_maybe_whitespace (pp);
- pp_identifier (pp, id);
+ pp_c_maybe_whitespace (pp);
+ pp_identifier (pp, id);
pp_base (pp)->padding = pp_before;
}
case CONST_DECL:
case FUNCTION_DECL:
case LABEL_DECL:
- e = DECL_NAME (e);
- /* Fall through. */
+ pp_c_tree_decl_identifier (pp, e);
+ break;
+
case IDENTIFIER_NODE:
pp_c_tree_identifier (pp, e);
break;
pp_c_constant (pp, e);
break;
- case STMT_EXPR:
+ case TARGET_EXPR:
+ pp_c_identifier (pp, "__builtin_memcpy");
pp_c_left_paren (pp);
- pp_statement (pp, STMT_EXPR_STMT (e));
+ pp_ampersand (pp);
+ pp_primary_expression (pp, TREE_OPERAND (e, 0));
+ pp_separate_with (pp, ',');
+ pp_ampersand (pp);
+ pp_initializer (pp, TREE_OPERAND (e, 1));
+ if (TREE_OPERAND (e, 2))
+ {
+ pp_separate_with (pp, ',');
+ pp_c_expression (pp, TREE_OPERAND (e, 2));
+ }
pp_c_right_paren (pp);
break;
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));
- }
+ pp_c_brace_enclosed_initializer_list (pp, e);
else
pp_expression (pp, e);
}
pp_c_init_declarator (c_pretty_printer *pp, tree t)
{
pp_declarator (pp, t);
- if (DECL_INITIAL (t))
+ /* We don't want to output function definitions here. There are handled
+ elsewhere (and the syntactic form is bogus anyway). */
+ if (TREE_CODE (t) != FUNCTION_DECL && DECL_INITIAL (t))
{
tree init = DECL_INITIAL (t);
/* This C++ bit is handled here because it is easier to do so.
pp_separate_with (pp, ',');
}
}
- break;
+ return;
case VECTOR_TYPE:
- pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e));
- break;
+ if (TREE_CODE (e) == VECTOR_CST)
+ pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e));
+ else if (TREE_CODE (e) == CONSTRUCTOR)
+ pp_c_constructor_elts (pp, CONSTRUCTOR_ELTS (e));
+ else
+ break;
+ return;
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;
+ if (TREE_CODE (e) == CONSTRUCTOR)
+ pp_c_constructor_elts (pp, CONSTRUCTOR_ELTS (e));
+ else if (TREE_CODE (e) == COMPLEX_CST || TREE_CODE (e) == COMPLEX_EXPR)
+ {
+ 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));
+ }
+ else
+ break;
+ return;
default:
- pp_unsupported_tree (pp, type);
break;
}
+
+ pp_unsupported_tree (pp, type);
}
/* Pretty-print a brace-enclosed initializer-list. */
case FUNCTION_DECL:
case FIELD_DECL:
case LABEL_DECL:
- t = DECL_NAME (t);
+ pp_c_tree_decl_identifier (pp, t);
+ break;
+
case IDENTIFIER_NODE:
pp_c_tree_identifier (pp, t);
break;
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_c_call_argument_list (pp, TREE_OPERAND (e, 1));
break;
+ case UNORDERED_EXPR:
+ pp_c_identifier (pp, flag_isoc99
+ ? "isunordered"
+ : "__builtin_isunordered");
+ goto two_args_fun;
+
+ case ORDERED_EXPR:
+ pp_c_identifier (pp, flag_isoc99
+ ? "!isunordered"
+ : "!__builtin_isunordered");
+ goto two_args_fun;
+
+ case UNLT_EXPR:
+ pp_c_identifier (pp, flag_isoc99
+ ? "!isgreaterequal"
+ : "!__builtin_isgreaterequal");
+ goto two_args_fun;
+
+ case UNLE_EXPR:
+ pp_c_identifier (pp, flag_isoc99
+ ? "!isgreater"
+ : "!__builtin_isgreater");
+ goto two_args_fun;
+
+ case UNGT_EXPR:
+ pp_c_identifier (pp, flag_isoc99
+ ? "!islessequal"
+ : "!__builtin_islessequal");
+ goto two_args_fun;
+
+ case UNGE_EXPR:
+ pp_c_identifier (pp, flag_isoc99
+ ? "!isless"
+ : "!__builtin_isless");
+ goto two_args_fun;
+
+ case UNEQ_EXPR:
+ pp_c_identifier (pp, flag_isoc99
+ ? "!islessgreater"
+ : "!__builtin_islessgreater");
+ goto two_args_fun;
+
+ case LTGT_EXPR:
+ pp_c_identifier (pp, flag_isoc99
+ ? "islessgreater"
+ : "__builtin_islessgreater");
+ goto two_args_fun;
+
+ two_args_fun:
+ pp_c_left_paren (pp);
+ pp_expression (pp, TREE_OPERAND (e, 0));
+ pp_separate_with (pp, ',');
+ pp_expression (pp, TREE_OPERAND (e, 1));
+ pp_c_right_paren (pp);
+ break;
+
case ABS_EXPR:
pp_c_identifier (pp, "__builtin_abs");
pp_c_left_paren (pp);
}
}
+/* Print out V, which contains the elements of a constructor. */
+
+void
+pp_c_constructor_elts (c_pretty_printer *pp, VEC(constructor_elt,gc) *v)
+{
+ unsigned HOST_WIDE_INT ix;
+ tree value;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (v, ix, value)
+ {
+ pp_expression (pp, value);
+ if (ix != VEC_length (constructor_elt, v) - 1)
+ pp_separate_with (pp, ',');
+ }
+}
+
/* Print out an expression-list in parens, as in a function call. */
void
unary-operator: one of
* & + - ! ~
-
+
GNU extensions.
unary-expression:
__alignof__ unary-expression
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__");
else
pp_minus (pp);
pp_c_whitespace (pp);
- pp_multiplicative_expression (pp, TREE_OPERAND (e, 1));
+ pp_multiplicative_expression (pp, TREE_OPERAND (e, 1));
break;
default:
/* assignment-expression:
conditional-expression
- unary-expression assignment-operator assignment-expression
+ unary-expression assignment-operator assignment-expression
assignment-expression: one of
= *= /= %= += -= >>= <<= &= ^= |= */
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 ORDERED_EXPR:
+ case UNORDERED_EXPR:
+ case LTGT_EXPR:
+ case UNEQ_EXPR:
+ case UNLE_EXPR:
+ case UNLT_EXPR:
+ case UNGE_EXPR:
+ case UNGT_EXPR:
case ABS_EXPR:
case CONSTRUCTOR:
case COMPOUND_LITERAL_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);
case NE_EXPR:
pp_c_equality_expression (pp, e);
break;
-
+
case COND_EXPR:
pp_conditional_expression (pp, e);
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;
+ if (pp_needs_newline (pp))
+ pp_newline_and_indent (pp, 0);
- /* 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);
- }
+ dump_generic_node (pp_base (pp), stmt, pp_indentation (pp), 0, true);
}
\f
pp->assignment_expression = pp_c_assignment_expression;
pp->expression = pp_c_expression;
}
+
+
+/* Print the tree T in full, on file FILE. */
+
+void
+print_c_tree (FILE *file, tree t)
+{
+ static c_pretty_printer pp_rec;
+ static bool initialized = 0;
+ c_pretty_printer *pp = &pp_rec;
+
+ if (!initialized)
+ {
+ initialized = 1;
+ pp_construct (pp_base (pp), NULL, 0);
+ pp_c_pretty_printer_init (pp);
+ pp_needs_newline (pp) = true;
+ }
+ pp_base (pp)->buffer->stream = file;
+
+ pp_statement (pp, t);
+
+ pp_newline (pp);
+ pp_flush (pp);
+}
+
+/* Print the tree T in full, on stderr. */
+
+void
+debug_c_tree (tree t)
+{
+ print_c_tree (stderr, t);
+ fputc ('\n', stderr);
+}
+
+/* Output the DECL_NAME of T. If T has no DECL_NAME, output a string made
+ up of T's memory address. */
+
+void
+pp_c_tree_decl_identifier (c_pretty_printer *pp, tree t)
+{
+ const char *name;
+
+ gcc_assert (DECL_P (t));
+
+ if (DECL_NAME (t))
+ name = IDENTIFIER_POINTER (DECL_NAME (t));
+ else
+ {
+ static char xname[8];
+ sprintf (xname, "<U%4x>", ((unsigned)((unsigned long)(t) & 0xffff)));
+ name = xname;
+ }
+
+ pp_c_identifier (pp, name);
+}
/* Various declarations for the C and C++ pretty-printers.
- Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#ifndef GCC_C_PRETTY_PRINTER
#define GCC_C_PRETTY_PRINTER
typedef enum
{
pp_c_flag_abstract = 1 << 1,
- pp_c_flag_last_bit = 2
+ pp_c_flag_last_bit = 2
} pp_c_pretty_print_flags;
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;
#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))
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_left_bracket (c_pretty_printer *);
+void pp_c_right_bracket (c_pretty_printer *);
void pp_c_dot (c_pretty_printer *);
void pp_c_ampersand (c_pretty_printer *);
+void pp_c_star (c_pretty_printer *);
void pp_c_arrow (c_pretty_printer *);
void pp_c_semicolon (c_pretty_printer *);
+void pp_c_complement (c_pretty_printer *);
+void pp_c_exclamation (c_pretty_printer *);
void pp_c_space_for_pointer_operator (c_pretty_printer *, tree);
/* Declarations. */
+void pp_c_tree_decl_identifier (c_pretty_printer *, tree);
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_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_constructor_elts (c_pretty_printer *, VEC(constructor_elt,gc) *);
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_identifier (c_pretty_printer *, const char *);
void pp_c_string_literal (c_pretty_printer *, tree);
+void print_c_tree (FILE *file, tree t);
+
#endif /* GCC_C_PRETTY_PRINTER */
+++ /dev/null
-/* 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;
-}
/* CPP Library.
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 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
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. */
+Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
const char cpp_GCC_INCLUDE_DIR[] = "";
const size_t cpp_GCC_INCLUDE_DIR_len = 0;
#endif
-
-#ifdef TARGET_SYSTEM_ROOT
-const char *cpp_SYSROOT = TARGET_SYSTEM_ROOT;
-#else
-const char *cpp_SYSROOT = "";
-#endif
/* CPP Library.
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 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
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. */
+Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef GCC_CPPDEFAULT_H
#define GCC_CPPDEFAULT_H
extern const char cpp_GCC_INCLUDE_DIR[];
extern const size_t cpp_GCC_INCLUDE_DIR_len;
-extern const char *cpp_SYSROOT;
-
#endif /* ! GCC_CPPDEFAULT_H */
+++ /dev/null
-/* Default error handlers for CPP Library.
- Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000,
- 2001, 2002 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
-
-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 "intl.h"
-
-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 (cpp_reader *pfile, fileline line, unsigned int col)
-{
- if (line == 0)
- fprintf (stderr, "%s: ", progname);
- else
- {
- const struct line_map *map;
- unsigned int lin;
-
- map = linemap_lookup (&pfile->line_maps, line);
- linemap_print_containing_files (&pfile->line_maps, map);
-
- lin = SOURCE_LINE (map, line);
- if (col == 0)
- col = 1;
-
- if (lin == 0)
- fprintf (stderr, "%s:", map->to_file);
- else if (CPP_OPTION (pfile, show_column) == 0)
- fprintf (stderr, "%s:%u:", map->to_file, lin);
- else
- fprintf (stderr, "%s:%u:%u:", map->to_file, lin, col);
-
- fputc (' ', stderr);
- }
-}
-
-/* Set up for a diagnostic: print the file and line, bump the error
- counter, etc. LINE is the logical line number; zero means to print
- at the location of the previously lexed token, which tends to be
- the correct place by default. Returns 0 if the error has been
- suppressed. */
-int
-_cpp_begin_message (cpp_reader *pfile, int code, fileline line,
- unsigned int column)
-{
- int level = CPP_DL_EXTRACT (code);
-
- switch (level)
- {
- 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 CPP_DL_WARNING_SYSHDR:
- if (CPP_OPTION (pfile, warnings_are_errors)
- || (level == CPP_DL_PEDWARN && CPP_OPTION (pfile, pedantic_errors)))
- {
- if (CPP_OPTION (pfile, inhibit_errors))
- return 0;
- level = CPP_DL_ERROR;
- pfile->errors++;
- }
- else if (CPP_OPTION (pfile, inhibit_warnings))
- return 0;
- break;
-
- case CPP_DL_ERROR:
- if (CPP_OPTION (pfile, inhibit_errors))
- return 0;
- /* ICEs cannot be inhibited. */
- case CPP_DL_ICE:
- pfile->errors++;
- break;
- }
-
- print_location (pfile, line, column);
- if (CPP_DL_WARNING_P (level))
- fputs (_("warning: "), stderr);
- else if (level == CPP_DL_ICE)
- fputs (_("internal error: "), stderr);
-
- return 1;
-}
-
-/* Don't remove the blank before do, as otherwise the exgettext
- script will mistake this as a function definition */
-#define v_message(msgid, ap) \
- do { vfprintf (stderr, _(msgid), ap); putc ('\n', stderr); } while (0)
-
-/* Exported interface. */
-
-/* Print an error at the location of the previously lexed token. */
-void
-cpp_error (cpp_reader * pfile, int level, const char *msgid, ...)
-{
- fileline line;
- unsigned int column;
- va_list ap;
-
- va_start (ap, msgid);
-
- if (CPP_OPTION (pfile, traditional))
- {
- if (pfile->state.in_directive)
- line = pfile->directive_line;
- else
- line = pfile->line;
- column = 0;
- }
- else
- {
- 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_end (ap);
-}
-
-/* Print an error at a specific location. */
-void
-cpp_error_with_line (cpp_reader *pfile, int level,
- fileline line, unsigned int column,
- const char *msgid, ...)
-{
- va_list ap;
-
- va_start (ap, msgid);
-
- if (_cpp_begin_message (pfile, level, line, column))
- v_message (msgid, ap);
-
- va_end (ap);
-}
-
-void
-cpp_errno (cpp_reader *pfile, int level, const char *msgid)
-{
- if (msgid[0] == '\0')
- msgid = _("stdout");
-
- cpp_error (pfile, level, "%s: %s", msgid, xstrerror (errno));
-}
+++ /dev/null
-/* Parse C expressions for cpplib.
- Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
- 2002 Free Software Foundation.
- Contributed by Per Bothner, 1994.
-
-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"
-
-#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
-#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
-#define LOW_PART(num_part) (num_part & HALF_MASK)
-#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
-
-struct op
-{
- const cpp_token *token; /* The token forming op (for diagnostics). */
- cpp_num value; /* The value logically "right" of op. */
- enum cpp_ttype 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 (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)
-#define CPP_UMINUS (CPP_LAST_CPP_OP + 2)
-
-/* 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, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)
-#define SYNTAX_ERROR2(msgid, arg) \
- 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 (const uchar *s, size_t len)
-{
- size_t f = 0, l = 0, i = 0;
-
- while (len--)
- switch (s[len])
- {
- case 'f': case 'F': f++; break;
- case 'l': case 'L': l++; break;
- case 'i': case 'I':
- case 'j': case 'J': i++; break;
- default:
- return 0;
- }
-
- if (f + l > 1 || i > 1)
- return 0;
-
- return ((i ? CPP_N_IMAGINARY : 0)
- | (f ? CPP_N_SMALL :
- l ? CPP_N_LARGE : CPP_N_MEDIUM));
-}
-
-/* Subroutine of cpp_classify_number. S points to an integer suffix
- of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
- flag vector describing the suffix. */
-static unsigned int
-interpret_int_suffix (const uchar *s, size_t len)
-{
- size_t u, l, i;
-
- u = l = i = 0;
-
- while (len--)
- switch (s[len])
- {
- case 'u': case 'U': u++; break;
- case 'i': case 'I':
- case 'j': case 'J': i++; break;
- case 'l': case 'L': l++;
- /* If there are two Ls, they must be adjacent and the same case. */
- if (l == 2 && s[len] != s[len + 1])
- return 0;
- break;
- default:
- return 0;
- }
-
- if (l > 2 || u > 1 || i > 1)
- return 0;
-
- return ((i ? CPP_N_IMAGINARY : 0)
- | (u ? CPP_N_UNSIGNED : 0)
- | ((l == 0) ? CPP_N_SMALL
- : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
-}
-
-/* Categorize numeric constants according to their field (integer,
- floating point, or invalid), radix (decimal, octal, hexadecimal),
- and type suffixes. */
-unsigned int
-cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
-{
- const uchar *str = token->val.str.text;
- const uchar *limit;
- unsigned int max_digit, result, radix;
- enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
-
- /* If the lexer has done its job, length one can only be a single
- digit. Fast-path this very common case. */
- if (token->val.str.len == 1)
- return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL;
-
- limit = str + token->val.str.len;
- float_flag = NOT_FLOAT;
- max_digit = 0;
- radix = 10;
-
- /* First, interpret the radix. */
- if (*str == '0')
- {
- radix = 8;
- str++;
-
- /* Require at least one hex digit to classify it as hex. */
- if ((*str == 'x' || *str == 'X')
- && (str[1] == '.' || ISXDIGIT (str[1])))
- {
- radix = 16;
- str++;
- }
- }
-
- /* Now scan for a well-formed integer or float. */
- for (;;)
- {
- unsigned int c = *str++;
-
- if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
- {
- c = hex_value (c);
- if (c > max_digit)
- max_digit = c;
- }
- else if (c == '.')
- {
- if (float_flag == NOT_FLOAT)
- float_flag = AFTER_POINT;
- else
- SYNTAX_ERROR ("too many decimal points in number");
- }
- else if ((radix <= 10 && (c == 'e' || c == 'E'))
- || (radix == 16 && (c == 'p' || c == 'P')))
- {
- float_flag = AFTER_EXPON;
- break;
- }
- else
- {
- /* Start of suffix. */
- str--;
- break;
- }
- }
-
- if (float_flag != NOT_FLOAT && radix == 8)
- radix = 10;
-
- if (max_digit >= radix)
- SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit);
-
- if (float_flag != NOT_FLOAT)
- {
- if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
- cpp_error (pfile, CPP_DL_PEDWARN,
- "use of C99 hexadecimal floating constant");
-
- if (float_flag == AFTER_EXPON)
- {
- if (*str == '+' || *str == '-')
- str++;
-
- /* Exponent is decimal, even if string is a hex float. */
- if (!ISDIGIT (*str))
- SYNTAX_ERROR ("exponent has no digits");
-
- do
- str++;
- while (ISDIGIT (*str));
- }
- else if (radix == 16)
- SYNTAX_ERROR ("hexadecimal floating constants require an exponent");
-
- result = interpret_float_suffix (str, limit - str);
- if (result == 0)
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "invalid suffix \"%.*s\" on floating constant",
- (int) (limit - str), str);
- return CPP_N_INVALID;
- }
-
- /* Traditional C didn't accept any floating suffixes. */
- if (limit != str
- && CPP_WTRADITIONAL (pfile)
- && ! cpp_sys_macro_p (pfile))
- cpp_error (pfile, CPP_DL_WARNING,
- "traditional C rejects the \"%.*s\" suffix",
- (int) (limit - str), str);
-
- result |= CPP_N_FLOATING;
- }
- else
- {
- result = interpret_int_suffix (str, limit - str);
- if (result == 0)
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "invalid suffix \"%.*s\" on integer constant",
- (int) (limit - str), str);
- return CPP_N_INVALID;
- }
-
- /* Traditional C only accepted the 'L' suffix.
- Suppress warning about 'LL' with -Wno-long-long. */
- if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile))
- {
- int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY));
- int large = (result & CPP_N_WIDTH) == CPP_N_LARGE;
-
- if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long)))
- cpp_error (pfile, CPP_DL_WARNING,
- "traditional C rejects the \"%.*s\" suffix",
- (int) (limit - str), str);
- }
-
- if ((result & CPP_N_WIDTH) == CPP_N_LARGE
- && ! CPP_OPTION (pfile, c99)
- && CPP_OPTION (pfile, warn_long_long))
- 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, CPP_DL_PEDWARN,
- "imaginary constants are a GCC extension");
-
- if (radix == 10)
- result |= CPP_N_DECIMAL;
- else if (radix == 16)
- result |= CPP_N_HEX;
- else
- result |= CPP_N_OCTAL;
-
- return result;
-
- syntax_error:
- return CPP_N_INVALID;
-}
-
-/* cpp_interpret_integer converts an integer constant into a cpp_num,
- of precision options->precision.
-
- We do not provide any interface for decimal->float conversion,
- 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 (cpp_reader *pfile, const cpp_token *token,
- unsigned int type)
-{
- const uchar *p, *end;
- cpp_num result;
-
- result.low = 0;
- result.high = 0;
- result.unsignedp = !!(type & CPP_N_UNSIGNED);
- result.overflow = false;
-
- p = token->val.str.text;
- end = p + token->val.str.len;
-
- /* Common case of a single digit. */
- if (token->val.str.len == 1)
- result.low = p[0] - '0';
- else
- {
- cpp_num_part max;
- size_t precision = CPP_OPTION (pfile, precision);
- unsigned int base = 10, c = 0;
- bool overflow = false;
-
- if ((type & CPP_N_RADIX) == CPP_N_OCTAL)
- {
- base = 8;
- p++;
- }
- else if ((type & CPP_N_RADIX) == CPP_N_HEX)
- {
- base = 16;
- p += 2;
- }
-
- /* We can add a digit to numbers strictly less than this without
- needing the precision and slowness of double integers. */
- max = ~(cpp_num_part) 0;
- if (precision < PART_PRECISION)
- max >>= PART_PRECISION - precision;
- max = (max - base + 1) / base + 1;
-
- for (; p < end; p++)
- {
- c = *p;
-
- if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
- c = hex_value (c);
- else
- break;
-
- /* Strict inequality for when max is set to zero. */
- if (result.low < max)
- result.low = result.low * base + c;
- else
- {
- result = append_digit (result, c, base, precision);
- overflow |= result.overflow;
- max = 0;
- }
- }
-
- if (overflow)
- 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
- we still honor an explicit U suffix); but we only have
- traditional semantics in directives. */
- else if (!result.unsignedp
- && !(CPP_OPTION (pfile, traditional)
- && pfile->state.in_directive)
- && !num_positive (result, precision))
- {
- if (base == 10)
- cpp_error (pfile, CPP_DL_WARNING,
- "integer constant is so large that it is unsigned");
- result.unsignedp = true;
- }
- }
-
- return result;
-}
-
-/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE. */
-static cpp_num
-append_digit (cpp_num num, int digit, int base, size_t precision)
-{
- cpp_num result;
- unsigned int shift = 3 + (base == 16);
- bool overflow;
- cpp_num_part add_high, add_low;
-
- /* Multiply by 8 or 16. Catching this overflow here means we don't
- need to worry about add_high overflowing. */
- overflow = !!(num.high >> (PART_PRECISION - shift));
- result.high = num.high << shift;
- result.low = num.low << shift;
- result.high |= num.low >> (PART_PRECISION - shift);
-
- if (base == 10)
- {
- add_low = num.low << 1;
- add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1));
- }
- else
- add_high = add_low = 0;
-
- if (add_low + digit < add_low)
- add_high++;
- add_low += digit;
-
- if (result.low + add_low < result.low)
- add_high++;
- if (result.high + add_high < result.high)
- overflow = true;
-
- result.low += add_low;
- result.high += add_high;
-
- /* The above code catches overflow of a cpp_num type. This catches
- overflow of the (possibly shorter) target precision. */
- num.low = result.low;
- num.high = result.high;
- result = num_trim (result, precision);
- if (!num_eq (result, num))
- overflow = true;
-
- result.unsignedp = num.unsignedp;
- result.overflow = overflow;
- return result;
-}
-
-/* Handle meeting "defined" in a preprocessor expression. */
-static cpp_num
-parse_defined (cpp_reader *pfile)
-{
- cpp_num result;
- int paren = 0;
- cpp_hashnode *node = 0;
- const cpp_token *token;
- cpp_context *initial_context = pfile->context;
-
- /* Don't expand macros. */
- pfile->state.prevent_expansion++;
-
- token = cpp_get_token (pfile);
- if (token->type == CPP_OPEN_PAREN)
- {
- paren = 1;
- token = cpp_get_token (pfile);
- }
-
- if (token->type == CPP_NAME)
- {
- node = token->val.node;
- if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
- {
- cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\"");
- node = 0;
- }
- }
- else
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "operator \"defined\" requires an identifier");
- if (token->flags & NAMED_OP)
- {
- cpp_token op;
-
- op.flags = 0;
- op.type = token->type;
- 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));
- }
- }
-
- if (node)
- {
- if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
- cpp_error (pfile, CPP_DL_WARNING,
- "this use of \"defined\" may not be portable");
-
- _cpp_mark_macro_used (node);
-
- /* A possible controlling macro of the form #if !defined ().
- _cpp_parse_expr checks there was no other junk on the line. */
- pfile->mi_ind_cmacro = node;
- }
-
- pfile->state.prevent_expansion--;
-
- result.unsignedp = false;
- result.high = 0;
- result.overflow = false;
- result.low = node && node->type == NT_MACRO;
- return result;
-}
-
-/* Convert a token into a CPP_NUMBER (an interpreted preprocessing
- number or character constant, or the result of the "defined" or "#"
- operators). */
-static cpp_num
-eval_token (cpp_reader *pfile, const cpp_token *token)
-{
- cpp_num result;
- unsigned int temp;
- int unsignedp = 0;
-
- switch (token->type)
- {
- case CPP_NUMBER:
- temp = cpp_classify_number (pfile, token);
- switch (temp & CPP_N_CATEGORY)
- {
- case CPP_N_FLOATING:
- 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, CPP_DL_ERROR,
- "imaginary number in preprocessor expression");
- break;
-
- case CPP_N_INVALID:
- /* Error already issued. */
- break;
- }
- result.high = result.low = 0;
- break;
-
- case CPP_WCHAR:
- case CPP_CHAR:
- {
- cppchar_t cc = cpp_interpret_charconst (pfile, token,
- &temp, &unsignedp);
-
- result.high = 0;
- result.low = cc;
- /* Sign-extend the result if necessary. */
- if (!unsignedp && (cppchar_signed_t) cc < 0)
- {
- if (PART_PRECISION > BITS_PER_CPPCHAR_T)
- result.low |= ~(~(cpp_num_part) 0
- >> (PART_PRECISION - BITS_PER_CPPCHAR_T));
- result.high = ~(cpp_num_part) 0;
- result = num_trim (result, CPP_OPTION (pfile, precision));
- }
- }
- break;
-
- case CPP_NAME:
- if (token->val.node == pfile->spec_nodes.n_defined)
- return parse_defined (pfile);
- else if (CPP_OPTION (pfile, cplusplus)
- && (token->val.node == pfile->spec_nodes.n_true
- || token->val.node == pfile->spec_nodes.n_false))
- {
- result.high = 0;
- result.low = (token->val.node == pfile->spec_nodes.n_true);
- }
- else
- {
- result.high = 0;
- result.low = 0;
- if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
- cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined",
- NODE_NAME (token->val.node));
- }
- break;
-
- default: /* CPP_HASH */
- _cpp_test_assertion (pfile, &temp);
- result.high = 0;
- result.low = temp;
- }
-
- result.unsignedp = !!unsignedp;
- result.overflow = false;
- return result;
-}
-\f
-/* Operator precedence and flags table.
-
-After an operator is returned from the lexer, if it has priority less
-than the operator on the top of the stack, we reduce the stack by one
-operator and repeat the test. Since equal priorities do not reduce,
-this is naturally right-associative.
-
-We handle left-associative operators by decrementing the priority of
-just-lexed operators by one, but retaining the priority of operators
-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
-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.
-
-The parser assumes all shifted operators require a left operand unless
-the flag NO_L_OPERAND is set. These semantics are automatic; any
-extra semantics need to be handled with operator-specific code. */
-
-/* Flags. If CHECK_PROMOTION, we warn if the effective sign of an
- operand changes because of integer promotions. */
-#define NO_L_OPERAND (1 << 0)
-#define LEFT_ASSOC (1 << 1)
-#define CHECK_PROMOTION (1 << 2)
-
-/* Operator to priority map. Must be in the same order as the first
- N entries of enum cpp_ttype. */
-static const struct operator
-{
- uchar prio;
- uchar flags;
-} optab[] =
-{
- /* EQ */ {0, 0}, /* Shouldn't happen. */
- /* NOT */ {16, NO_L_OPERAND},
- /* GREATER */ {12, LEFT_ASSOC | CHECK_PROMOTION},
- /* LESS */ {12, LEFT_ASSOC | CHECK_PROMOTION},
- /* PLUS */ {14, LEFT_ASSOC | CHECK_PROMOTION},
- /* MINUS */ {14, LEFT_ASSOC | CHECK_PROMOTION},
- /* MULT */ {15, LEFT_ASSOC | CHECK_PROMOTION},
- /* DIV */ {15, LEFT_ASSOC | CHECK_PROMOTION},
- /* MOD */ {15, LEFT_ASSOC | CHECK_PROMOTION},
- /* AND */ {9, LEFT_ASSOC | CHECK_PROMOTION},
- /* OR */ {7, LEFT_ASSOC | CHECK_PROMOTION},
- /* XOR */ {8, LEFT_ASSOC | CHECK_PROMOTION},
- /* RSHIFT */ {13, LEFT_ASSOC},
- /* LSHIFT */ {13, LEFT_ASSOC},
-
- /* MIN */ {10, LEFT_ASSOC | CHECK_PROMOTION},
- /* MAX */ {10, LEFT_ASSOC | CHECK_PROMOTION},
-
- /* COMPL */ {16, NO_L_OPERAND},
- /* AND_AND */ {6, LEFT_ASSOC},
- /* OR_OR */ {5, LEFT_ASSOC},
- /* QUERY */ {3, 0},
- /* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION},
- /* COMMA */ {2, LEFT_ASSOC},
- /* OPEN_PAREN */ {1, NO_L_OPERAND},
- /* CLOSE_PAREN */ {0, 0},
- /* EOF */ {0, 0},
- /* EQ_EQ */ {11, LEFT_ASSOC},
- /* NOT_EQ */ {11, LEFT_ASSOC},
- /* GREATER_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION},
- /* LESS_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION},
- /* UPLUS */ {16, NO_L_OPERAND},
- /* UMINUS */ {16, NO_L_OPERAND}
-};
-
-/* Parse and evaluate a C expression, reading from PFILE.
- Returns the truth value of the expression.
-
- The implementation is an operator precedence parser, i.e. a
- bottom-up parser, using a stack for not-yet-reduced tokens.
-
- The stack base is op_stack, and the current stack pointer is 'top'.
- There is a stack element for each operator (only), and the most
- recently pushed operator is 'top->op'. An operand (value) is
- stored in the 'value' field of the stack element of the operator
- that precedes it. */
-bool
-_cpp_parse_expr (cpp_reader *pfile)
-{
- struct op *top = pfile->op_stack;
- unsigned int lex_count;
- bool saw_leading_not, want_value = true;
-
- pfile->state.skip_eval = 0;
-
- /* Set up detection of #if ! defined(). */
- pfile->mi_ind_cmacro = 0;
- saw_leading_not = false;
- lex_count = 0;
-
- /* Lowest priority operator prevents further reductions. */
- top->op = CPP_EOF;
-
- for (;;)
- {
- struct op op;
-
- lex_count++;
- op.token = cpp_get_token (pfile);
- op.op = op.token->type;
-
- switch (op.op)
- {
- /* These tokens convert into values. */
- case CPP_NUMBER:
- case CPP_CHAR:
- case CPP_WCHAR:
- case CPP_NAME:
- case CPP_HASH:
- if (!want_value)
- SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
- cpp_token_as_text (pfile, op.token));
- want_value = false;
- top->value = eval_token (pfile, op.token);
- continue;
-
- case CPP_NOT:
- saw_leading_not = lex_count == 1;
- break;
- case CPP_PLUS:
- if (want_value)
- op.op = CPP_UPLUS;
- break;
- case CPP_MINUS:
- if (want_value)
- op.op = CPP_UMINUS;
- break;
-
- default:
- if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
- SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
- cpp_token_as_text (pfile, op.token));
- break;
- }
-
- /* Check we have a value or operator as appropriate. */
- if (optab[op.op].flags & NO_L_OPERAND)
- {
- if (!want_value)
- SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
- cpp_token_as_text (pfile, op.token));
- }
- else if (want_value)
- {
- /* 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);
- if (!top)
- goto syntax_error;
-
- if (op.op == CPP_EOF)
- break;
-
- switch (op.op)
- {
- case CPP_CLOSE_PAREN:
- continue;
- case CPP_OR_OR:
- if (!num_zerop (top->value))
- pfile->state.skip_eval++;
- break;
- case CPP_AND_AND:
- case CPP_QUERY:
- if (num_zerop (top->value))
- pfile->state.skip_eval++;
- break;
- case CPP_COLON:
- if (top->op != CPP_QUERY)
- SYNTAX_ERROR (" ':' without preceding '?'");
- if (!num_zerop (top[-1].value)) /* Was '?' condition true? */
- pfile->state.skip_eval++;
- else
- pfile->state.skip_eval--;
- default:
- break;
- }
-
- want_value = true;
-
- /* Check for and handle stack overflow. */
- if (++top == pfile->op_limit)
- top = _cpp_expand_op_stack (pfile);
-
- top->op = op.op;
- top->token = op.token;
- }
-
- /* The controlling macro expression is only valid if we called lex 3
- times: <!> <defined expression> and <EOF>. push_conditional ()
- checks that we are at top-of-file. */
- if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
- pfile->mi_ind_cmacro = 0;
-
- if (top != pfile->op_stack)
- {
- cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in #if");
- syntax_error:
- return false; /* Return false on syntax error. */
- }
-
- return !num_zerop (top->value);
-}
-
-/* Reduce the operator / value stack if possible, in preparation for
- pushing operator OP. Returns NULL on error, otherwise the top of
- the stack. */
-static struct 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, CPP_DL_ICE, "impossible operator '%u'", top->op);
- return 0;
- }
-
- if (op == CPP_OPEN_PAREN)
- return top;
-
- /* Decrement the priority of left-associative operators to force a
- reduction with operators of otherwise equal priority. */
- prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
- while (prio < optab[top->op].prio)
- {
- if (CPP_OPTION (pfile, warn_num_sign_change)
- && optab[top->op].flags & CHECK_PROMOTION)
- check_promotion (pfile, top);
-
- switch (top->op)
- {
- case CPP_UPLUS:
- case CPP_UMINUS:
- case CPP_NOT:
- case CPP_COMPL:
- top[-1].value = num_unary_op (pfile, top->value, top->op);
- break;
-
- case CPP_PLUS:
- case CPP_MINUS:
- case CPP_RSHIFT:
- case CPP_LSHIFT:
- case CPP_MIN:
- case CPP_MAX:
- case CPP_COMMA:
- top[-1].value = num_binary_op (pfile, top[-1].value,
- top->value, top->op);
- break;
-
- case CPP_GREATER:
- case CPP_LESS:
- case CPP_GREATER_EQ:
- case CPP_LESS_EQ:
- top[-1].value
- = num_inequality_op (pfile, top[-1].value, top->value, top->op);
- break;
-
- case CPP_EQ_EQ:
- case CPP_NOT_EQ:
- top[-1].value
- = num_equality_op (pfile, top[-1].value, top->value, top->op);
- break;
-
- case CPP_AND:
- case CPP_OR:
- case CPP_XOR:
- top[-1].value
- = num_bitwise_op (pfile, top[-1].value, top->value, top->op);
- break;
-
- case CPP_MULT:
- top[-1].value = num_mul (pfile, top[-1].value, top->value);
- break;
-
- case CPP_DIV:
- case CPP_MOD:
- top[-1].value = num_div_op (pfile, top[-1].value,
- top->value, top->op);
- break;
-
- case CPP_OR_OR:
- top--;
- if (!num_zerop (top->value))
- pfile->state.skip_eval--;
- top->value.low = (!num_zerop (top->value)
- || !num_zerop (top[1].value));
- top->value.high = 0;
- top->value.unsignedp = false;
- top->value.overflow = false;
- continue;
-
- case CPP_AND_AND:
- top--;
- if (num_zerop (top->value))
- pfile->state.skip_eval--;
- top->value.low = (!num_zerop (top->value)
- && !num_zerop (top[1].value));
- top->value.high = 0;
- top->value.unsignedp = false;
- top->value.overflow = false;
- continue;
-
- case CPP_OPEN_PAREN:
- if (op != CPP_CLOSE_PAREN)
- {
- cpp_error (pfile, CPP_DL_ERROR, "missing ')' in expression");
- return 0;
- }
- top--;
- top->value = top[1].value;
- return top;
-
- case CPP_COLON:
- top -= 2;
- if (!num_zerop (top->value))
- {
- pfile->state.skip_eval--;
- top->value = top[1].value;
- }
- else
- top->value = top[2].value;
- top->value.unsignedp = (top[1].value.unsignedp
- || top[2].value.unsignedp);
- continue;
-
- case CPP_QUERY:
- cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'");
- return 0;
-
- default:
- goto bad_op;
- }
-
- top--;
- if (top->value.overflow && !pfile->state.skip_eval)
- cpp_error (pfile, CPP_DL_PEDWARN,
- "integer overflow in preprocessor expression");
- }
-
- if (op == CPP_CLOSE_PAREN)
- {
- cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression");
- return 0;
- }
-
- return top;
-}
-
-/* Returns the position of the old top of stack after expansion. */
-struct op *
-_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 = xrealloc (pfile->op_stack, new_size * sizeof (struct op));
- pfile->op_limit = pfile->op_stack + new_size;
-
- return pfile->op_stack + old_size;
-}
-
-/* Emits a warning if the effective sign of either operand of OP
- changes because of integer promotions. */
-static void
-check_promotion (cpp_reader *pfile, const struct op *op)
-{
- if (op->value.unsignedp == op[-1].value.unsignedp)
- return;
-
- if (op->value.unsignedp)
- {
- if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision)))
- 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, 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 (cpp_num num, size_t precision)
-{
- if (precision > PART_PRECISION)
- {
- precision -= PART_PRECISION;
- if (precision < PART_PRECISION)
- num.high &= ((cpp_num_part) 1 << precision) - 1;
- }
- else
- {
- if (precision < PART_PRECISION)
- num.low &= ((cpp_num_part) 1 << precision) - 1;
- num.high = 0;
- }
-
- return num;
-}
-
-/* True iff A (presumed signed) >= 0. */
-static bool
-num_positive (cpp_num num, size_t precision)
-{
- if (precision > PART_PRECISION)
- {
- precision -= PART_PRECISION;
- return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
- }
-
- return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
-}
-
-/* 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 (cpp_num num, size_t precision)
-{
- if (!num.unsignedp)
- {
- if (precision > PART_PRECISION)
- {
- precision -= PART_PRECISION;
- if (precision < PART_PRECISION
- && (num.high & (cpp_num_part) 1 << (precision - 1)))
- num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
- }
- else if (num.low & (cpp_num_part) 1 << (precision - 1))
- {
- if (precision < PART_PRECISION)
- num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
- num.high = ~(cpp_num_part) 0;
- }
- }
-
- return num;
-}
-
-/* Returns the negative of NUM. */
-static cpp_num
-num_negate (cpp_num num, size_t precision)
-{
- cpp_num copy;
-
- copy = num;
- num.high = ~num.high;
- num.low = ~num.low;
- if (++num.low == 0)
- num.high++;
- num = num_trim (num, precision);
- num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num));
-
- return num;
-}
-
-/* Returns true if A >= B. */
-static bool
-num_greater_eq (cpp_num pa, cpp_num pb, size_t precision)
-{
- bool unsignedp;
-
- unsignedp = pa.unsignedp || pb.unsignedp;
-
- if (!unsignedp)
- {
- /* Both numbers have signed type. If they are of different
- sign, the answer is the sign of A. */
- unsignedp = num_positive (pa, precision);
-
- if (unsignedp != num_positive (pb, precision))
- return unsignedp;
-
- /* Otherwise we can do an unsigned comparison. */
- }
-
- return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low);
-}
-
-/* Returns LHS OP RHS, where OP is a bit-wise operation. */
-static cpp_num
-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;
-
- /* As excess precision is zeroed, there is no need to num_trim () as
- these operations cannot introduce a set bit there. */
- if (op == CPP_AND)
- {
- lhs.low &= rhs.low;
- lhs.high &= rhs.high;
- }
- else if (op == CPP_OR)
- {
- lhs.low |= rhs.low;
- lhs.high |= rhs.high;
- }
- else
- {
- lhs.low ^= rhs.low;
- lhs.high ^= rhs.high;
- }
-
- return lhs;
-}
-
-/* Returns LHS OP RHS, where OP is an inequality. */
-static cpp_num
-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));
-
- if (op == CPP_GREATER_EQ)
- lhs.low = gte;
- else if (op == CPP_LESS)
- lhs.low = !gte;
- else if (op == CPP_GREATER)
- lhs.low = gte && !num_eq (lhs, rhs);
- else /* CPP_LESS_EQ. */
- lhs.low = !gte || num_eq (lhs, rhs);
-
- lhs.high = 0;
- lhs.overflow = false;
- lhs.unsignedp = false;
- return lhs;
-}
-
-/* Returns LHS OP RHS, where OP is == or !=. */
-static cpp_num
-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);
- if (op == CPP_NOT_EQ)
- eq = !eq;
- lhs.low = eq;
- lhs.high = 0;
- lhs.overflow = false;
- lhs.unsignedp = false;
- return lhs;
-}
-
-/* Shift NUM, of width PRECISION, right by N bits. */
-static cpp_num
-num_rshift (cpp_num num, size_t precision, size_t n)
-{
- cpp_num_part sign_mask;
-
- if (num.unsignedp || num_positive (num, precision))
- sign_mask = 0;
- else
- sign_mask = ~(cpp_num_part) 0;
-
- if (n >= precision)
- num.high = num.low = sign_mask;
- else
- {
- /* Sign-extend. */
- if (precision < PART_PRECISION)
- num.high = sign_mask, num.low |= sign_mask << precision;
- else if (precision < 2 * PART_PRECISION)
- num.high |= sign_mask << (precision - PART_PRECISION);
-
- if (n >= PART_PRECISION)
- {
- n -= PART_PRECISION;
- num.low = num.high;
- num.high = sign_mask;
- }
-
- if (n)
- {
- num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
- num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
- }
- }
-
- num = num_trim (num, precision);
- num.overflow = false;
- return num;
-}
-
-/* Shift NUM, of width PRECISION, left by N bits. */
-static cpp_num
-num_lshift (cpp_num num, size_t precision, size_t n)
-{
- if (n >= precision)
- {
- num.overflow = !num.unsignedp && !num_zerop (num);
- num.high = num.low = 0;
- }
- else
- {
- cpp_num orig, maybe_orig;
- size_t m = n;
-
- orig = num;
- if (m >= PART_PRECISION)
- {
- m -= PART_PRECISION;
- num.high = num.low;
- num.low = 0;
- }
- if (m)
- {
- num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
- num.low <<= m;
- }
- num = num_trim (num, precision);
-
- if (num.unsignedp)
- num.overflow = false;
- else
- {
- maybe_orig = num_rshift (num, precision, n);
- num.overflow = !num_eq (orig, maybe_orig);
- }
- }
-
- return num;
-}
-
-/* The four unary operators: +, -, ! and ~. */
-static cpp_num
-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, CPP_DL_WARNING,
- "traditional C rejects the unary plus operator");
- num.overflow = false;
- break;
-
- case CPP_UMINUS:
- num = num_negate (num, CPP_OPTION (pfile, precision));
- break;
-
- case CPP_COMPL:
- num.high = ~num.high;
- num.low = ~num.low;
- num = num_trim (num, CPP_OPTION (pfile, precision));
- num.overflow = false;
- break;
-
- default: /* case CPP_NOT: */
- num.low = num_zerop (num);
- num.high = 0;
- num.overflow = false;
- num.unsignedp = false;
- break;
- }
-
- return num;
-}
-
-/* The various binary operators. */
-static cpp_num
-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);
- bool gte;
- size_t n;
-
- switch (op)
- {
- /* Shifts. */
- case CPP_LSHIFT:
- case CPP_RSHIFT:
- if (!rhs.unsignedp && !num_positive (rhs, precision))
- {
- /* A negative shift is a positive shift the other way. */
- if (op == CPP_LSHIFT)
- op = CPP_RSHIFT;
- else
- op = CPP_LSHIFT;
- rhs = num_negate (rhs, precision);
- }
- if (rhs.high)
- n = ~0; /* Maximal. */
- else
- n = rhs.low;
- if (op == CPP_LSHIFT)
- lhs = num_lshift (lhs, precision, n);
- else
- lhs = num_rshift (lhs, precision, n);
- break;
-
- /* Min / Max. */
- case CPP_MIN:
- case CPP_MAX:
- {
- bool unsignedp = lhs.unsignedp || rhs.unsignedp;
-
- gte = num_greater_eq (lhs, rhs, precision);
- if (op == CPP_MIN)
- gte = !gte;
- if (!gte)
- lhs = rhs;
- lhs.unsignedp = unsignedp;
- }
- break;
-
- /* Arithmetic. */
- case CPP_MINUS:
- rhs = num_negate (rhs, precision);
- case CPP_PLUS:
- result.low = lhs.low + rhs.low;
- result.high = lhs.high + rhs.high;
- if (result.low < lhs.low)
- result.high++;
-
- result = num_trim (result, precision);
- result.unsignedp = lhs.unsignedp || rhs.unsignedp;
- if (result.unsignedp)
- result.overflow = false;
- else
- {
- bool lhsp = num_positive (lhs, precision);
- result.overflow = (lhsp == num_positive (rhs, precision)
- && lhsp != num_positive (result, precision));
- }
- return result;
-
- /* Comma. */
- default: /* case CPP_COMMA: */
- 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;
- }
-
- return lhs;
-}
-
-/* Multiplies two unsigned cpp_num_parts to give a cpp_num. This
- cannot overflow. */
-static cpp_num
-num_part_mul (cpp_num_part lhs, cpp_num_part rhs)
-{
- cpp_num result;
- cpp_num_part middle[2], temp;
-
- result.low = LOW_PART (lhs) * LOW_PART (rhs);
- result.high = HIGH_PART (lhs) * HIGH_PART (rhs);
-
- middle[0] = LOW_PART (lhs) * HIGH_PART (rhs);
- middle[1] = HIGH_PART (lhs) * LOW_PART (rhs);
-
- temp = result.low;
- result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2);
- if (result.low < temp)
- result.high++;
-
- temp = result.low;
- result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2);
- if (result.low < temp)
- result.high++;
-
- result.high += HIGH_PART (middle[0]);
- result.high += HIGH_PART (middle[1]);
- result.unsignedp = 1;
-
- return result;
-}
-
-/* Multiply two preprocessing numbers. */
-static cpp_num
-num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs)
-{
- cpp_num result, temp;
- bool unsignedp = lhs.unsignedp || rhs.unsignedp;
- bool overflow, negate = false;
- size_t precision = CPP_OPTION (pfile, precision);
-
- /* Prepare for unsigned multiplication. */
- if (!unsignedp)
- {
- if (!num_positive (lhs, precision))
- negate = !negate, lhs = num_negate (lhs, precision);
- if (!num_positive (rhs, precision))
- negate = !negate, rhs = num_negate (rhs, precision);
- }
-
- overflow = lhs.high && rhs.high;
- result = num_part_mul (lhs.low, rhs.low);
-
- temp = num_part_mul (lhs.high, rhs.low);
- result.high += temp.low;
- if (temp.high)
- overflow = true;
-
- temp = num_part_mul (lhs.low, rhs.high);
- result.high += temp.low;
- if (temp.high)
- overflow = true;
-
- temp.low = result.low, temp.high = result.high;
- result = num_trim (result, precision);
- if (!num_eq (result, temp))
- overflow = true;
-
- if (negate)
- result = num_negate (result, precision);
-
- if (unsignedp)
- result.overflow = false;
- else
- result.overflow = overflow || (num_positive (result, precision) ^ !negate
- && !num_zerop (result));
- result.unsignedp = unsignedp;
-
- return result;
-}
-
-/* Divide two preprocessing numbers, returning the answer or the
- remainder depending upon OP. */
-static cpp_num
-num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
-{
- cpp_num result, sub;
- cpp_num_part mask;
- bool unsignedp = lhs.unsignedp || rhs.unsignedp;
- bool negate = false, lhs_neg = false;
- size_t i, precision = CPP_OPTION (pfile, precision);
-
- /* Prepare for unsigned division. */
- if (!unsignedp)
- {
- if (!num_positive (lhs, precision))
- negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision);
- if (!num_positive (rhs, precision))
- negate = !negate, rhs = num_negate (rhs, precision);
- }
-
- /* Find the high bit. */
- if (rhs.high)
- {
- i = precision - 1;
- mask = (cpp_num_part) 1 << (i - PART_PRECISION);
- for (; ; i--, mask >>= 1)
- if (rhs.high & mask)
- break;
- }
- else if (rhs.low)
- {
- if (precision > PART_PRECISION)
- i = precision - PART_PRECISION - 1;
- else
- i = precision - 1;
- mask = (cpp_num_part) 1 << i;
- for (; ; i--, mask >>= 1)
- if (rhs.low & mask)
- break;
- }
- else
- {
- if (!pfile->state.skip_eval)
- cpp_error (pfile, CPP_DL_ERROR, "division by zero in #if");
- return lhs;
- }
-
- /* First nonzero bit of RHS is bit I. Do naive division by
- shifting the RHS fully left, and subtracting from LHS if LHS is
- at least as big, and then repeating but with one less shift.
- This is not very efficient, but is easy to understand. */
-
- rhs.unsignedp = true;
- lhs.unsignedp = true;
- i = precision - i - 1;
- sub = num_lshift (rhs, precision, i);
-
- result.high = result.low = 0;
- for (;;)
- {
- if (num_greater_eq (lhs, sub, precision))
- {
- lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS);
- if (i >= PART_PRECISION)
- result.high |= (cpp_num_part) 1 << (i - PART_PRECISION);
- else
- result.low |= (cpp_num_part) 1 << i;
- }
- if (i-- == 0)
- break;
- sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1));
- sub.high >>= 1;
- }
-
- /* We divide so that the remainder has the sign of the LHS. */
- if (op == CPP_DIV)
- {
- result.unsignedp = unsignedp;
- if (unsignedp)
- result.overflow = false;
- else
- {
- if (negate)
- result = num_negate (result, precision);
- result.overflow = num_positive (result, precision) ^ !negate;
- }
-
- return result;
- }
-
- /* CPP_MOD. */
- lhs.unsignedp = unsignedp;
- lhs.overflow = false;
- if (lhs_neg)
- lhs = num_negate (lhs, precision);
-
- return lhs;
-}
+++ /dev/null
-/* Part of CPP library. File handling.
- Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998,
- 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
-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 "intl.h"
-#include "mkdeps.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
-# define STAT_SIZE_RELIABLE(ST) true
-#endif
-
-#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
-
-/* 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;
-
- /* The full path used to find the file. */
- const char *path;
-
- /* The full path of the pch file. */
- const char *pchname;
-
- /* The file's path with the basename stripped. NULL if it hasn't
- been calculated yet. */
- const char *dir_name;
-
- /* Chain through all files. */
- struct _cpp_file *next_file;
-
- /* The contents of NAME after calling read_file(). */
- const uchar *buffer;
-
- /* The macro, if any, preventing re-inclusion. */
- const cpp_hashnode *cmacro;
-
- /* 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;
-
- /* As filled in by stat(2) for the file. */
- struct stat st;
-
- /* File descriptor. Invalid if -1, otherwise open. */
- int fd;
-
- /* Zero if this file was successfully opened and stat()-ed,
- otherwise errno obtained from failure. */
- int err_no;
-
- /* Number of times the file has been stacked for preprocessing. */
- unsigned short stack_count;
-
- /* If opened with #import or contains #pragma once. */
- bool once_only;
-
- /* If read() failed before. */
- bool dont_read;
-
- /* If this file is the main file. */
- bool main_file;
-
- /* If BUFFER above contains the true contents of the file. */
- bool buffer_valid;
-
- /* 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;
-};
-
-/* 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;
-};
-
-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;
- set_stdin_to_binary_mode ();
- }
- else
- file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
-
- if (file->fd != -1)
- {
- 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;
- }
-
- close (file->fd);
- file->fd = -1;
- }
- else if (errno == ENOTDIR)
- errno = ENOENT;
-
- file->err_no = errno;
-
- return false;
-}
-
-/* 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
-pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
-{
- 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;
-
- flen = strlen (path);
- len = flen + sizeof (extension);
- pchname = xmalloc (len);
- memcpy (pchname, path, flen);
- memcpy (pchname + flen, extension, sizeof (extension));
-
- if (stat (pchname, &st) == 0)
- {
- DIR *pchdir;
- struct dirent *d;
- size_t dlen, plen = len;
-
- if (!S_ISDIR (st.st_mode))
- valid = validate_pch (pfile, file, pchname);
- else if ((pchdir = opendir (pchname)) != NULL)
- {
- 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);
- }
- if (valid)
- file->pch = true;
- else
- *invalid_pch = true;
- }
-
- if (valid)
- file->pchname = pchname;
- else
- free (pchname);
-
- return valid;
-}
-
-/* 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. */
-
-static bool
-find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
-{
- char *path;
-
- 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;
-}
-
-/* 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);
-
- /* First check the cache before we resort to memory allocation. */
- entry = search_cache (*hash_slot, start_dir);
- if (entry)
- return entry->u.file;
-
- 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 bool
-read_file_guts (cpp_reader *pfile, _cpp_file *file)
-{
- ssize_t size, total, count;
- uchar *buf;
- bool regular;
-
- 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
- space. We can't handle a file that large. (Anyone with
- a single source file bigger than 2GB needs to rethink
- their coding style.) Some systems (e.g. AIX 4.1) define
- SSIZE_MAX to be much smaller than the actual range of the
- type. Use INTTYPE_MAXIMUM unconditionally to ensure this
- does not bite us. */
-#ifndef __BORLANDC__
- if (file->st.st_size > INTTYPE_MAXIMUM (ssize_t))
- {
- cpp_error (pfile, CPP_DL_ERROR, "%s is too large", file->path);
- return false;
- }
-#endif
-
- 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 (total == size)
- {
- if (regular)
- break;
- size *= 2;
- buf = xrealloc (buf, size + 1);
- }
- }
-
- if (count < 0)
- {
- cpp_errno (pfile, CPP_DL_ERROR, file->path);
- return false;
- }
-
-#ifndef __BORLANDC__
- /* 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
-
- 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))
- {
- open_file_failed (pfile, file, 0);
- return false;
- }
-
- 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)
- {
- _cpp_mark_file_once_only (pfile, file);
-
- /* Don't stack files that have been stacked before. */
- if (file->stack_count)
- return false;
- }
-
- /* 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;
-
- /* 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;
- }
-
- if (!read_file (pfile, file))
- return false;
-
- /* 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;
-
- /* 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 (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)
- {
- _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;
- }
- }
-
- return f == NULL;
-}
-
-/* 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)
-{
- cpp_buffer *buffer;
- int sysp;
-
- if (!should_stack_file (pfile, file, import))
- return false;
-
- 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)
- {
- if (!file->main_file || !CPP_OPTION (pfile, deps.ignore_main_file))
- deps_add_dep (pfile->deps, file->path);
- }
-
- /* Clear buffer_valid since _cpp_clean_line messes it up. */
- file->buffer_valid = false;
- file->stack_count++;
-
- /* 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;
-}
-
-/* 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)
-{
- cpp_dir *dir;
- _cpp_file *file;
-
- if (IS_ABSOLUTE_PATH (fname))
- return &pfile->no_search_path;
-
- /* 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 && 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
- 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;
-}
-
-/* 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)
- {
- 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;
- }
-
- 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
- {
- /* 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
- cpp_errno (pfile, CPP_DL_ERROR, file->path);
- }
-}
-
-/* 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 (cpp_reader *pfile, int syshdr, int externc)
-{
- int flags = 0;
-
- /* 1 = system header, 2 = system header to be treated as C. */
- if (syshdr)
- flags = 1 + (externc != 0);
- _cpp_do_file_change (pfile, LC_RENAME, pfile->map->to_file,
- SOURCE_LINE (pfile->map, pfile->line), flags);
-}
-
-/* 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_change_file (cpp_reader *pfile, enum lc_reason reason,
- const char *new_name)
-{
- _cpp_do_file_change (pfile, reason, new_name, 1, 0);
-}
-
-/* Callback function for htab_traverse. */
-static int
-report_missing_guard (void **slot, void *b)
-{
- struct file_hash_entry *entry = (struct file_hash_entry *) *slot;
- int *bannerp = (int *) b;
-
- /* Skip directories. */
- if (entry->start_dir != NULL)
- {
- _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)
- {
- if (*bannerp == 0)
- {
- fputs (_("Multiple include guards may be useful for:\n"),
- stderr);
- *bannerp = 1;
- }
-
- fputs (entry->u.file->path, stderr);
- putc ('\n', stderr);
- }
- }
-
- return 0;
-}
-
-/* Report on all files that might benefit from a multiple include guard.
- Triggered by -H. */
-void
-_cpp_report_missing_guards (cpp_reader *pfile)
-{
- int banner = 0;
-
- 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, return 1, otherwise 0. */
-int
-_cpp_compare_file_date (cpp_reader *pfile, const char *fname,
- int angle_brackets)
-{
- _cpp_file *file;
- struct cpp_dir *dir;
-
- dir = search_path_head (pfile, fname, angle_brackets, IT_INCLUDE);
- if (!dir)
- return -1;
-
- file = _cpp_find_file (pfile, fname, dir, false, angle_brackets);
- if (file->err_no)
- return -1;
-
- if (file->fd != -1)
- {
- close (file->fd);
- file->fd = -1;
- }
-
- return file->st.st_mtime > pfile->buffer->file->st.st_mtime;
-}
-
-/* Pushes the given file onto the buffer stack. Returns nonzero if
- successful. */
-bool
-cpp_push_include (cpp_reader *pfile, const char *fname)
-{
- /* 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 (cpp_reader *pfile, _cpp_file *file)
-{
- /* Record the inclusion-preventing macro, which could be NULL
- meaning no controlling macro. */
- if (pfile->mi_valid && file->cmacro == NULL)
- file->cmacro = pfile->mi_cmacro;
-
- /* Invalidate control macros in the #including file. */
- pfile->mi_valid = false;
-
- if (file->buffer)
- {
- free ((void *) file->buffer);
- file->buffer = NULL;
- file->buffer_valid = false;
- }
-}
-
-/* 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 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)
-{
- pfile->quote_include = quote;
- pfile->bracket_include = quote;
- pfile->quote_ignores_source_dir = quote_ignores_source_dir;
-
- for (; quote; quote = quote->next)
- {
- quote->name_map = NULL;
- quote->len = strlen (quote->name);
- if (quote == bracket)
- pfile->bracket_include = bracket;
- }
-}
-
-/* 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;
-
- 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 (int ch, FILE *f)
-{
- char *alloc, *set;
- int len;
-
- len = 20;
- set = alloc = xmalloc (len + 1);
- if (! is_space (ch))
- {
- *set++ = ch;
- while ((ch = getc (f)) != EOF && ! is_space (ch))
- {
- if (set - alloc == len)
- {
- len *= 2;
- alloc = xrealloc (alloc, len + 1);
- set = alloc + len / 2;
- }
- *set++ = ch;
- }
- }
- *set = '\0';
- ungetc (ch, f);
- return alloc;
-}
-
-/* Read the file name map file for DIR. */
-static void
-read_name_map (cpp_dir *dir)
-{
- static const char FILE_NAME_MAP_FILE[] = "header.gcc";
- char *name;
- FILE *f;
- 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)
- {
- int ch;
-
- while ((ch = getc (f)) != EOF)
- {
- char *to;
-
- if (is_space (ch))
- continue;
-
- 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);
- if (IS_ABSOLUTE_PATH (to))
- dir->name_map[count + 1] = to;
- else
- {
- dir->name_map[count + 1] = append_file_to_dir (to, dir);
- free (to);
- }
-
- count += 2;
- while ((ch = getc (f)) != '\n')
- if (ch == EOF)
- break;
- }
-
- fclose (f);
- }
-
- /* Terminate the list of maps. */
- dir->name_map[count] = NULL;
-}
-
-/* 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 (cpp_reader *pfile, _cpp_file *file)
-{
- const char *fname, *p;
- char *new_dir;
- cpp_dir *dir;
- size_t index, len;
-
- dir = file->dir;
- fname = file->name;
-
- for (;;)
- {
- if (!dir->name_map)
- read_name_map (dir);
-
- for (index = 0; dir->name_map[index]; index += 2)
- if (!strcmp (dir->name_map[index], fname))
- return xstrdup (dir->name_map[index + 1]);
-
- p = strchr (fname, '/');
- if (!p || p == fname)
- return NULL;
-
- 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';
-
- dir = make_cpp_dir (pfile, new_dir, dir->sysp);
- fname = p + 1;
- }
-}
-
-/* Return true if FILE is usable by PCH. */
-static bool
-include_pch_p (_cpp_file *file)
-{
- return file->pch & 1;
-}
-
-/* Returns true if PCHNAME is a valid PCH file for FILE. */
-static bool
-validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname)
-{
- const char *saved_path = file->path;
- bool valid = false;
-
- file->path = pchname;
- if (open_file (file))
- {
- valid = 1 & pfile->cb.valid_pch (pfile, pchname, file->fd);
-
- if (!valid)
- {
- close (file->fd);
- file->fd = -1;
- }
-
- if (CPP_OPTION (pfile, print_include_names))
- {
- unsigned int i;
- for (i = 1; i < pfile->line_maps.depth; i++)
- putc ('.', stderr);
- fprintf (stderr, "%c %s\n",
- valid ? '!' : 'x', pchname);
- }
- }
-
- file->path = saved_path;
- return valid;
-}
+++ /dev/null
-/* Hash tables for the CPP library.
- Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
- 1999, 2000, 2001, 2002 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
-
-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"
-
-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 (hash_table *table)
-{
- cpp_hashnode *node;
-
- 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 (cpp_reader *pfile, hash_table *table)
-{
- struct spec_nodes *s;
-
- if (table == NULL)
- {
- pfile->our_hashtable = 1;
- table = ht_create (13); /* 8K (=2^13) entries. */
- table->alloc_node = (hashnode (*) (hash_table *)) alloc_node;
-
- _obstack_begin (&pfile->hash_ob, 0, 0,
- (void *(*) (long)) xmalloc,
- (void (*) (void *)) free);
- }
-
- table->pfile = pfile;
- pfile->hash_table = table;
-
- /* Now we can initialize things that use the hash table. */
- _cpp_init_directives (pfile);
- _cpp_init_internal_pragmas (pfile);
-
- s = &pfile->spec_nodes;
- s->n_defined = cpp_lookup (pfile, DSC("defined"));
- s->n_true = cpp_lookup (pfile, DSC("true"));
- s->n_false = cpp_lookup (pfile, DSC("false"));
- s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__"));
- s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC;
- /* SDCC _asm specific */
- s->n__asm = cpp_lookup (pfile, DSC("_asm"));
-
-}
-
-/* Tear down the identifier hash table. */
-void
-_cpp_destroy_hashtable (cpp_reader *pfile)
-{
- if (pfile->our_hashtable)
- {
- ht_destroy (pfile->hash_table);
- obstack_free (&pfile->hash_ob, 0);
- }
-}
-
-/* Returns the hash entry for the STR of length LEN, creating one
- if necessary. */
-cpp_hashnode *
-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));
-}
-
-/* Determine whether the str STR, of length LEN, is a defined macro. */
-int
-cpp_defined (cpp_reader *pfile, const unsigned char *str, int len)
-{
- cpp_hashnode *node;
-
- node = CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_NO_INSERT));
-
- /* If it's of type NT_MACRO, it cannot be poisoned. */
- return node && node->type == NT_MACRO;
-}
-
-/* For all nodes in the hashtable, callback CB with parameters PFILE,
- the node, and V. */
-void
-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. */
- ht_forall (pfile->hash_table, (ht_cb) cb, v);
-}
+++ /dev/null
-/* Part of CPP library.
- 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
-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. */
-
-/* This header defines all the internal data structures and functions
- that need to be visible across files. It's called cpphash.h for
- historical reasons. */
-
-#ifndef GCC_CPPHASH_H
-#define GCC_CPPHASH_H
-
-#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;
-#endif
-#define U (const uchar *) /* Intended use: U"string" */
-
-#define BITS_PER_CPPCHAR_T (CHAR_BIT * sizeof (cppchar_t))
-
-/* Test if a sign is valid within a preprocessing number. */
-#define VALID_SIGN(c, prevc) \
- (((c) == '+' || (c) == '-') && \
- ((prevc) == 'e' || (prevc) == 'E' \
- || (((prevc) == 'p' || (prevc) == 'P') \
- && CPP_OPTION (pfile, extended_numbers))))
-
-#define CPP_OPTION(PFILE, OPTION) ((PFILE)->opts.OPTION)
-#define CPP_BUFFER(PFILE) ((PFILE)->buffer)
-#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
- efficiency, and partly to limit runaway recursion. */
-#define CPP_STACK_MAX 200
-
-/* Host alignment handling. */
-struct dummy
-{
- char c;
- union
- {
- double d;
- int *p;
- } u;
-};
-
-#define DEFAULT_ALIGNMENT offsetof (struct dummy, u)
-#define CPP_ALIGN2(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
-#define CPP_ALIGN(size) CPP_ALIGN2 (size, DEFAULT_ALIGNMENT)
-
-/* Each macro definition is recorded in a cpp_macro structure.
- Variadic macros cannot occur with traditional cpp. */
-struct cpp_macro
-{
- /* Parameters, if any. */
- cpp_hashnode **params;
-
- /* Replacement tokens (ISO) or replacement text (traditional). See
- comment at top of cpptrad.c for how traditional function-like
- macros are encoded. */
- union
- {
- cpp_token *tokens;
- const uchar *text;
- } exp;
-
- /* Definition line number. */
- fileline line;
-
- /* Number of tokens in expansion, or bytes for traditional macros. */
- unsigned int count;
-
- /* Number of parameters. */
- unsigned short paramc;
-
- /* If a function-like macro. */
- unsigned int fun_like : 1;
-
- /* If a variadic macro. */
- unsigned int variadic : 1;
-
- /* If macro defined in system header. */
- unsigned int syshdr : 1;
-
- /* Nonzero if it has been expanded or had its existence tested. */
- unsigned int used : 1;
-};
-
-#define _cpp_mark_macro_used(NODE) do { \
- if ((NODE)->type == NT_MACRO && !((NODE)->flags & NODE_BUILTIN)) \
- (NODE)->value.macro->used = 1; } while (0)
-
-/* A generic memory buffer, and operations on it. */
-typedef struct _cpp_buff _cpp_buff;
-struct _cpp_buff
-{
- struct _cpp_buff *next;
- unsigned char *base, *cur, *limit;
-};
-
-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)
-
-/* #include types. */
-enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE};
-
-union utoken
-{
- const cpp_token *token;
- const cpp_token **ptoken;
-};
-
-/* A "run" of tokens; part of a chain of runs. */
-typedef struct tokenrun tokenrun;
-struct tokenrun
-{
- tokenrun *next, *prev;
- cpp_token *base, *limit;
-};
-
-/* Accessor macros for struct cpp_context. */
-#define FIRST(c) ((c)->u.iso.first)
-#define LAST(c) ((c)->u.iso.last)
-#define CUR(c) ((c)->u.trad.cur)
-#define RLIMIT(c) ((c)->u.trad.rlimit)
-
-typedef struct cpp_context cpp_context;
-struct cpp_context
-{
- /* Doubly-linked list. */
- cpp_context *next, *prev;
-
- union
- {
- /* For ISO macro expansion. Contexts other than the base context
- are contiguous tokens. e.g. macro expansions, expanded
- argument tokens. */
- struct
- {
- union utoken first;
- union utoken last;
- } iso;
-
- /* For traditional macro expansion. */
- struct
- {
- const uchar *cur;
- const uchar *rlimit;
- } trad;
- } u;
-
- /* If non-NULL, a buffer used for storage related to this context.
- When the context is popped, the buffer is released. */
- _cpp_buff *buff;
-
- /* For a macro context, the macro node, otherwise NULL. */
- cpp_hashnode *macro;
-
- /* True if utoken element is token, else ptoken. */
- bool direct_p;
-};
-
-struct lexer_state
-{
- /* Nonzero if first token on line is CPP_HASH. */
- unsigned char in_directive;
-
- /* Nonzero if in a directive that will handle padding tokens itself.
- #include needs this to avoid problems with computed include and
- spacing between tokens. */
- unsigned char directive_wants_padding;
-
- /* True if we are skipping a failed conditional group. */
- unsigned char skipping;
-
- /* Nonzero if in a directive that takes angle-bracketed headers. */
- unsigned char angled_headers;
-
- /* Nonzero if in a #if or #elif directive. */
- unsigned char in_expression;
-
- /* Nonzero to save comments. Turned off if discard_comments, and in
- all directives apart from #define. */
- unsigned char save_comments;
-
- /* Nonzero if lexing __VA_ARGS__ is valid. */
- unsigned char va_args_ok;
-
- /* Nonzero if lexing poisoned identifiers is valid. */
- unsigned char poisoned_ok;
-
- /* Nonzero to prevent macro expansion. */
- unsigned char prevent_expansion;
-
- /* Nonzero when parsing arguments to a function-like macro. */
- unsigned char parsing_args;
-
- /* Nonzero to skip evaluating part of an expression. */
- unsigned int skip_eval;
-};
-
-/* Special nodes - identifiers with predefined significance. */
-struct spec_nodes
-{
- cpp_hashnode *n_defined; /* defined operator */
- cpp_hashnode *n_true; /* C++ keyword true */
- cpp_hashnode *n_false; /* C++ keyword false */
- cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */
- /* SDCC _asm specific */
- cpp_hashnode *n__asm; /* _asm ... _endasm ; */
-};
-
-typedef struct _cpp_line_note _cpp_line_note;
-struct _cpp_line_note
-{
- /* 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 uchar *cur; /* Current location. */
- const uchar *line_base; /* Start of current physical line. */
- const uchar *next_line; /* Start of to-be-cleaned logical line. */
-
- 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. */
-
- struct cpp_buffer *prev;
-
- /* 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;
-
- /* 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,
- or for -Wtraditional, and only once per file (otherwise it would
- be far too noisy). */
- unsigned char warned_cplusplus_comments;
-
- /* True if we don't process trigraphs and escaped newlines. True
- for preprocessed input, command line directives, and _Pragma
- buffers. */
- unsigned char from_stage3;
-
- /* 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. */
- 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 cpp_dir dir;
-
- /* Used for buffer overlays by cpptrad.c. */
- const uchar *saved_cur, *saved_rlimit;
-};
-
-/* A cpp_reader encapsulates the "state" of a pre-processor run.
- Applying cpp_get_token repeatedly yields a stream of pre-processor
- tokens. Usually, there is only one cpp_reader object active. */
-struct cpp_reader
-{
- /* Top of buffer stack. */
- cpp_buffer *buffer;
-
- /* Overlaid buffer (can be different after processing #include). */
- cpp_buffer *overlaid_buffer;
-
- /* Lexer state. */
- struct lexer_state state;
-
- /* Source line tracking. */
- struct line_maps line_maps;
- const struct line_map *map;
- fileline line;
-
- /* The line of the '#' of the current directive. */
- fileline directive_line;
-
- /* Memory buffers. */
- _cpp_buff *a_buff; /* Aligned permanent storage. */
- _cpp_buff *u_buff; /* Unaligned permanent storage. */
- _cpp_buff *free_buffs; /* Free buffer chain. */
-
- /* Context stack. */
- struct cpp_context base_context;
- struct cpp_context *context;
-
- /* If in_directive, the directive if known. */
- const struct directive *directive;
-
- /* 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;
-
- /* 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;
-
- /* Lexing. */
- cpp_token *cur_token;
- tokenrun base_run, *cur_run;
- unsigned int lookaheads;
-
- /* Nonzero prevents the lexer from re-using the token runs. */
- unsigned int keep_tokens;
-
- /* Error counter for exit code. */
- unsigned int errors;
-
- /* Buffer to hold macro definition string. */
- unsigned char *macro_buffer;
- unsigned int macro_buffer_len;
-
- /* Descriptor for converting from the source character set to the
- execution character set. */
- struct cset_converter narrow_cset_desc;
-
- /* 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;
- const uchar *time;
-
- /* EOF token, and a token forcing paste avoidance. */
- cpp_token avoid_paste;
- cpp_token eof;
-
- /* Opaque handle to the dependencies of mkdeps.c. */
- struct deps *deps;
-
- /* Obstack holding all macro hash nodes. This never shrinks.
- See cpphash.c */
- struct obstack hash_ob;
-
- /* Obstack holding buffer and conditional structures. This is a
- real stack. See cpplib.c. */
- struct obstack buffer_ob;
-
- /* Pragma table - dynamic, because a library user can add to the
- list of recognized pragmas. */
- struct pragma_entry *pragmas;
-
- /* Call backs to cpplib client. */
- struct cpp_callbacks cb;
-
- /* Identifier hash table. */
- struct ht *hash_table;
-
- /* Expression parser stack. */
- struct op *op_stack, *op_limit;
-
- /* User visible options. */
- struct cpp_options opts;
-
- /* Special nodes - identifiers with predefined significance to the
- preprocessor. */
- struct spec_nodes spec_nodes;
-
- /* Whether cpplib owns the hashtable. */
- bool our_hashtable;
-
- /* Traditional preprocessing output buffer (a logical line). */
- struct
- {
- uchar *base;
- uchar *limit;
- uchar *cur;
- 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.
- If the definition of `numchar' looks odd to you, please look up the
- definition of a pp-number in the C standard [section 6.4.8 of C99].
-
- In the unlikely event that characters other than \r and \n enter
- the set is_vspace, the macro handle_newline() in cpplex.c must be
- updated. */
-#define _dollar_ok(x) ((x) == '$' && CPP_OPTION (pfile, dollars_in_ident))
-
-#define is_idchar(x) (ISIDNUM(x) || _dollar_ok(x))
-#define is_numchar(x) ISIDNUM(x)
-#define is_idstart(x) (ISIDST(x) || _dollar_ok(x))
-#define is_numstart(x) ISDIGIT(x)
-#define is_hspace(x) ISBLANK(x)
-#define is_vspace(x) IS_VSPACE(x)
-#define is_nvspace(x) IS_NVSPACE(x)
-#define is_space(x) IS_SPACE_OR_NUL(x)
-
-/* This table is constant if it can be initialized at compile time,
- which is the case if cpp was compiled with GCC >=2.7, or another
- compiler that supports C99. */
-#if HAVE_DESIGNATED_INITIALIZERS
-extern const unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
-#else
-extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
-#endif
-
-/* Macros. */
-
-#define CPP_IN_SYSTEM_HEADER(PFILE) ((PFILE)->map && (PFILE)->map->sysp)
-#define CPP_PEDANTIC(PF) CPP_OPTION (PF, pedantic)
-#define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, warn_traditional)
-
-/* In cpperror.c */
-extern int _cpp_begin_message (cpp_reader *, int, fileline, unsigned int);
-
-/* In cppmacro.c */
-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 (cpp_reader *, hash_table *);
-extern void _cpp_destroy_hashtable (cpp_reader *);
-
-/* In cppfiles.c */
-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 (cpp_reader *);
-extern struct op *_cpp_expand_op_stack (cpp_reader *);
-
-/* In cpplex.c */
-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 (cpp_reader *);
-
-/* In cpplib.c */
-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_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
-#define xnew(T) (T *) xmalloc (sizeof(T))
-#define xcnew(T) (T *) xcalloc (1, sizeof(T))
-#define xnewvec(T, N) (T *) xmalloc (sizeof(T) * (N))
-#define xcnewvec(T, N) (T *) xcalloc (N, sizeof(T))
-#define xobnew(O, T) (T *) obstack_alloc (O, sizeof(T))
-
-/* These are inline functions instead of macros so we can get type
- checking. */
-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 (const uchar *s1, const uchar *s2)
-{
- return strcmp ((const char *)s1, (const char *)s2);
-}
-
-static inline int
-ustrncmp (const uchar *s1, const uchar *s2, size_t n)
-{
- return strncmp ((const char *)s1, (const char *)s2, n);
-}
-
-static inline size_t
-ustrlen (const uchar *s1)
-{
- return strlen ((const char *)s1);
-}
-
-static inline uchar *
-uxstrdup (const uchar *s1)
-{
- return (uchar *) xstrdup ((const char *)s1);
-}
-
-static inline uchar *
-ustrchr (const uchar *s1, int c)
-{
- return (uchar *) strchr ((const char *)s1, c);
-}
-
-static inline int
-ufputs (const uchar *s, FILE *f)
-{
- return fputs ((const char *)s, f);
-}
-
-#endif /* ! GCC_CPPHASH_H */
+++ /dev/null
-/* CPP Library.
- Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 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
-
-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 "mkdeps.h"
-
-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
- 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 (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
-
-/* 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 cplusplus_comments;
- char digraphs;
-};
-
-static const struct lang_flags lang_defaults[] =
-{ /* 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 (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, cplusplus_comments) = l->cplusplus_comments;
- CPP_OPTION (pfile, digraphs) = l->digraphs;
-}
-
-/* Initialize library global state. */
-static void
-init_library (void)
-{
- static int initialized = 0;
-
- if (! initialized)
- {
- initialized = 1;
-
- /* 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 (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 = xcalloc (1, sizeof (cpp_reader));
-
- cpp_set_lang (pfile, lang);
- 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, 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. */
- 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;
- 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. */
- linemap_init (&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. */
- _obstack_begin (&pfile->buffer_ob, 0, 0,
- (void *(*) (long)) xmalloc,
- (void (*) (void *)) free);
-
- _cpp_init_files (pfile);
-
- _cpp_init_hashtable (pfile, table);
-
- return pfile;
-}
-
-/* Free resources used by PFILE. Accessing PFILE after this function
- returns leads to undefined behavior. Returns the error count. */
-void
-cpp_destroy (cpp_reader *pfile)
-{
- cpp_context *context, *contextn;
- tokenrun *run, *runn;
-
- 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 (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_files (pfile);
- _cpp_destroy_iconv (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 (context = pfile->base_context.next; context; context = contextn)
- {
- contextn = context->next;
- free (context);
- }
-
- linemap_free (&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 (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->is_directive = 0;
- hp->directive_index = b->value;
- }
-}
-
-/* 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);
-
- 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 (hosted)
- _cpp_define_builtin (pfile, "__STDC_HOSTED__ 1");
- else
- _cpp_define_builtin (pfile, "__STDC_HOSTED__ 0");
-
- 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 (cpp_reader *);
-static void sanity_checks (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, CPP_DL_ICE, "cppchar_t must be an unsigned type");
-
- if (CPP_OPTION (pfile, precision) > max_precision)
- 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, 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, 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, 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, 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, CPP_DL_ICE,
- "CPP half-integer narrower than CPP character");
-
- if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T)
- 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));
-}
-#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 (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. */
-void
-cpp_post_options (cpp_reader *pfile)
-{
- sanity_checks (pfile);
-
- post_options (pfile);
-
- /* 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)
- pfile->deps = deps_init ();
-
- /* Set the default target (if there is none already). */
- deps_add_default_target (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;
-
- _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);
- if (!pfile->map)
- return NULL;
- fname = pfile->map->to_file;
- }
- return fname;
-}
-
-/* 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 (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)
- {
- 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;
- }
- }
-
- /* Backup as if nothing happened. */
- _cpp_backup_tokens (pfile, 1);
-}
-
-/* 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)
-{
- const cpp_token *hash, *token;
-
- /* 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)
- {
- _cpp_backup_tokens (pfile, 1);
- return;
- }
-
- token = _cpp_lex_direct (pfile);
-
- if (token->type != CPP_NUMBER)
- {
- _cpp_backup_tokens (pfile, 2);
- return;
- }
-
- 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)
- {
- char *debugdir = alloca (token->val.str.len - 3);
-
- memcpy (debugdir, (const char *) token->val.str.text + 1,
- token->val.str.len - 4);
- debugdir[token->val.str.len - 4] = '\0';
-
- pfile->cb.dir_change (pfile, debugdir);
- }
-}
-
-/* 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 (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;
-}
-
-static void
-post_options (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;
- }
-
- if (CPP_OPTION (pfile, warn_trigraphs) == 2)
- CPP_OPTION (pfile, warn_trigraphs) = !CPP_OPTION (pfile, trigraphs);
-
- if (CPP_OPTION (pfile, traditional))
- {
- 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;
- }
-}
+++ /dev/null
-/* CPP Library - lexical analysis.
- 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
-
-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 <assert.h>
-
-enum spell_type
-{
- SPELL_OPERATOR = 0,
- SPELL_IDENT,
- SPELL_LITERAL,
- SPELL_NONE
-};
-
-struct token_spelling
-{
- enum spell_type category;
- const unsigned char *name;
-};
-
-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 #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)
-
-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 (const cpp_token *token, const char *string)
-{
- if (token->type != CPP_NAME)
- return 0;
-
- return !ustrcmp (NODE_NAME (token->val.node), (const uchar *) string);
-}
-
-/* Record a note TYPE at byte POS into the current cleaned logical
- line. */
-static void
-add_line_note (cpp_buffer *buffer, const uchar *pos, unsigned int type)
-{
- if (buffer->notes_used == buffer->notes_cap)
- {
- buffer->notes_cap = buffer->notes_cap * 2 + 200;
- buffer->notes = xrealloc (buffer->notes,
- buffer->notes_cap * sizeof (_cpp_line_note));
- }
-
- buffer->notes[buffer->notes_used].pos = pos;
- buffer->notes[buffer->notes_used].type = type;
- buffer->notes_used++;
-}
-
-/* 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;
- 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;
-
- if (!buffer->from_stage3)
- {
- /* 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 (;;)
- {
- c = *++s;
- if (c == '\n' || c == '\r')
- {
- 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;
- }
- }
- }
-
-
- for (;;)
- {
- c = *++s;
- *++d = c;
-
- if (c == '\n' || c == '\r')
- {
- /* Handle DOS line endings. */
- if (c == '\r' && s != buffer->rlimit && s[1] == '\n')
- s++;
- if (s == buffer->rlimit)
- break;
-
- /* Escaped? */
- p = d;
- while (p != buffer->next_line && is_nvspace (p[-1]))
- p--;
- if (p == buffer->next_line || p[-1] != '\\')
- break;
-
- 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]])
- {
- /* 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
- {
- do
- s++;
- while (*s != '\n' && *s != '\r');
- d = (uchar *) s;
-
- /* 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);
-}
-
-/* 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)
-{
- cpp_buffer *buffer = pfile->buffer;
-
- 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;
- }
-
- 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 */
-/* Skip an _asm ... _endasm block. We find the end of the comment by
- seeing _endasm. Returns non-zero if _asm terminated by EOF, zero
- otherwise. */
-static int
-skip_asm_block (cpp_reader *pfile)
-{
-#define _ENDASM_STR "endasm"
-#define _ENDASM_LEN ((sizeof _ENDASM_STR) - 1)
-
- cpp_buffer *buffer = pfile->buffer;
- cppchar_t c = EOF;
- int prev_space = 0;
- int ret = 1;
-
- while (buffer->cur != buffer->rlimit)
- {
- prev_space = is_space(c);
- c = *buffer->cur++;
-
- if (prev_space && c == '_')
- {
- if (buffer->cur + _ENDASM_LEN <= buffer->rlimit &&
- strncmp(buffer->cur, _ENDASM_STR, _ENDASM_LEN) == 0)
- {
- buffer->cur += _ENDASM_LEN;
- ret = 0;
- break;
- }
- }
- else if (c == '\n')
- {
- --buffer->cur;
- _cpp_process_line_notes (pfile, true);
- if (buffer->next_line >= buffer->rlimit)
- return true;
- _cpp_clean_line (pfile);
- pfile->line++;
- }
- }
-
- _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.
-
- Buffer->cur points to the initial asterisk of the comment. */
-bool
-_cpp_skip_block_comment (cpp_reader *pfile)
-{
- cpp_buffer *buffer = pfile->buffer;
- const uchar *cur = buffer->cur;
- uchar c;
-
- cur++;
- if (*cur == '/')
- cur++;
-
- for (;;)
- {
- /* People like decorating comments with '*', so check for '/'
- instead for efficiency. */
- c = *cur++;
-
- if (c == '/')
- {
- 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)
- && 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;
- }
- }
-
- 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 (cpp_reader *pfile)
-{
- cpp_buffer *buffer = pfile->buffer;
- unsigned int orig_line = pfile->line;
-
- while (*buffer->cur != '\n')
- buffer->cur++;
-
- _cpp_process_line_notes (pfile, true);
- return orig_line != pfile->line;
-}
-
-/* Skips whitespace, saving the next non-whitespace character. */
-static void
-skip_whitespace (cpp_reader *pfile, cppchar_t c)
-{
- cpp_buffer *buffer = pfile->buffer;
- bool saw_NUL = false;
-
- do
- {
- /* Horizontal space always OK. */
- if (c == ' ' || c == '\t')
- ;
- /* Just \f \v or \0 left. */
- else if (c == '\0')
- saw_NUL = true;
- else if (pfile->state.in_directive && CPP_PEDANTIC (pfile))
- cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line,
- CPP_BUF_COL (buffer),
- "%s in preprocessing directive",
- c == '\f' ? "form feed" : "vertical tab");
-
- c = *buffer->cur++;
- }
- /* 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--;
-}
-
-/* See if the characters of a number token are valid in a name (no
- '.', '+' or '-'). */
-static int
-name_p (cpp_reader *pfile, const cpp_string *string)
-{
- unsigned int i;
-
- for (i = 0; i < string->len; i++)
- if (!is_idchar (string->text[i]))
- return 0;
-
- return 1;
-}
-
-/* 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_buffer *buffer = pfile->buffer;
-
- if (*buffer->cur == '$')
- {
- if (!CPP_OPTION (pfile, dollars_in_ident))
- return false;
-
- 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;
- }
-
- /* 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
- {
- cur = pfile->buffer->cur;
-
- /* N.B. ISIDNUM does not include $. */
- while (ISIDNUM (*cur))
- cur++;
-
- pfile->buffer->cur = cur;
- }
- 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. */
- 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, 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, CPP_DL_PEDWARN,
- "__VA_ARGS__ can only appear in the expansion"
- " of a C99 variadic macro");
- }
-
- return result;
-}
-
-/* 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_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;
-
- uchar c = *(pfile->buffer->cur - 1);
- struct obstack *stack = &pfile->hash_table->stack;
- cpp_buffer *buffer = pfile->buffer;
- int len = 0;
- int has_whole = 0;
- int has_fract = 0;
-
- if ('.' == c)
- {
- num_part = NP_FRACT;
- ++len;
- obstack_1grow (stack, '.');
- c = get_effective_char(pfile);
- }
- else
- {
- if ('0' == c)
- {
- has_whole = 1;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
-
- switch (c)
- {
- case 'X':
- case 'x':
- num_type = NT_HEX;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- break;
-
- case '.':
- num_part = NP_FRACT;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- break;
- }
- }
- }
-
- for (; ; )
- {
- switch (num_part)
- {
- case NP_WHOLE:
- if (NT_DEC == num_type)
- {
- while (ISDIGIT (c))
- {
- has_whole = 1;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
-
- if ('.' == c)
- {
- num_part = NP_FRACT;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- continue;
- }
- else if ('E' == c || 'e' == c)
- {
- if (has_whole || has_fract)
- {
- num_part = NP_EXP;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- continue;
- }
- else
- break;
- }
- }
- else
- {
- while (ISXDIGIT (c))
- {
- has_whole = 1;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
-
- if ('.' == c)
- {
- num_part = NP_FRACT;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- continue;
- }
- else if ('P' == c || 'p' == c)
- {
- if (has_whole || has_fract)
- {
- num_part = NP_EXP;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- continue;
- }
- else
- break;
- }
- }
- num_part = NP_INT_SUFFIX;
- continue;
-
- case NP_FRACT:
- if (NT_DEC == num_type)
- {
- while (ISDIGIT (c))
- {
- has_fract = 1;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
-
- if ('E' == c || 'e' == c)
- {
- if (has_whole || has_fract)
- {
- num_part = NP_EXP;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- continue;
- }
- }
- }
- else
- {
- while (ISXDIGIT (c))
- {
- has_fract = 1;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
-
- if ('P' == c || 'p' == c)
- {
- if (has_whole || has_fract)
- {
- num_part = NP_EXP;
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- continue;
- }
- }
- }
- num_part = NP_FLOAT_SUFFIX;
- continue;
-
- case NP_EXP:
- if ('+' == c || '-' == c)
- {
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
-
- while (ISDIGIT (c))
- {
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
-
- num_part = NP_FLOAT_SUFFIX;
- continue;
-
- case NP_INT_SUFFIX:
- if ('L' == c || 'l' == c)
- {
- uchar prevc = c;
-
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
-
- if (c == prevc)
- {
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
- }
- else if ('U' == c || 'u' == c)
- {
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
- break;
-
- case NP_FLOAT_SUFFIX:
- if ('F' == c || 'f' == c)
- {
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
- else if ('L' == c || 'l' == c)
- {
- ++len;
- obstack_1grow (stack, c);
- c = get_effective_char(pfile);
- }
- break;
- }
- break;
- }
-
- /* Step back over the unwanted char. */
- BACKUP ();
-
- number->text = obstack_finish (stack);
- number->len = len;
-}
-
-/* Lex a number to NUMBER starting at BUFFER->CUR - 1. */
-static void
-lex_number (cpp_reader *pfile, cpp_string *number)
-{
- const uchar *cur;
- const uchar *base;
- uchar *dest;
-
- base = pfile->buffer->cur - 1;
- do
- {
- cur = pfile->buffer->cur;
-
- /* N.B. ISIDNUM does not include $. */
- while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1]))
- cur++;
-
- 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;
-}
-
-/* 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)
-{
- uchar *dest = _cpp_unaligned_alloc (pfile, len + 1);
-
- memcpy (dest, base, len);
- dest[len] = '\0';
- token->type = type;
- token->val.str.len = len;
- token->val.str.text = dest;
-}
-
-/* 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.
-
- The spelling is NUL-terminated, but it is not guaranteed that this
- is the first NUL since embedded NULs are preserved. */
-static void
-lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
-{
- 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;
-
- for (;;)
- {
- cppchar_t c = *cur++;
-
- /* 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')
- {
- cur--;
- type = CPP_OTHER;
- break;
- }
- else if (c == '\0')
- saw_NUL = true;
- }
-
- if (saw_NUL && !pfile->state.skipping)
- cpp_error (pfile, CPP_DL_WARNING,
- "null character(s) preserved in literal");
-
- pfile->buffer->cur = cur;
- create_literal (pfile, token, base, cur - base, type);
-}
-
-/* Fixed _WIN32 problem with CR-CR-LF sequences when outputting
- comment blocks (when executed with -C option) and
- _asm (SDCPP specific) blocks */
-
-/* Count and copy characters from src to dest, excluding CRs:
- CRs are automatically generated, because the output is
- opened in TEXT mode. If dest == NULL, only count chars */
-static unsigned int
-copy_text_chars (char *dest, const char *src, unsigned int len)
-{
- unsigned int n = 0;
- const char *p;
-
- for (p = src; p != src + len; ++p)
- {
- assert(*p != '\0');
-
- if (*p != '\r')
- {
- if (dest != NULL)
- *dest++ = *p;
- ++n;
- }
- }
-
- return n;
-}
-
-/* SDCC _asm specific */
-/* The stored comment includes the comment start and any terminator. */
-static void
-save_asm (cpp_reader *pfile, cpp_token *token, const unsigned char *from)
-{
-#define _ASM_STR "_asm"
-#define _ASM_LEN ((sizeof _ASM_STR) - 1)
-
- unsigned char *buffer;
- unsigned int text_len, len;
-
- len = pfile->buffer->cur - from;
- /* + _ASM_LEN for the initial '_asm'. */
- text_len = copy_text_chars (NULL, from, len) + _ASM_LEN;
- buffer = _cpp_unaligned_alloc (pfile, text_len);
-
-
- token->type = CPP_ASM;
- token->val.str.len = text_len;
- token->val.str.text = buffer;
-
- memcpy (buffer, _ASM_STR, _ASM_LEN);
- copy_text_chars (buffer + _ASM_LEN, from, len);
-}
-
-/* The stored comment includes the comment start and any terminator. */
-static void
-save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from,
- cppchar_t type)
-{
- unsigned char *buffer;
- unsigned int len, clen;
-
- len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'. */
-
- /* C++ comments probably (not definitely) have moved past a new
- line, which we don't want to save in the comment. */
- if (is_vspace (pfile->buffer->cur[-1]))
- len--;
-
- /* If we are currently in a directive, then we need to store all
- C++ comments as C comments internally, and so we need to
- allocate a little extra space in that case.
-
- Note that the only time we encounter a directive here is
- when we are saving comments in a "#define". */
- clen = (pfile->state.in_directive && type == '/') ? len + 2 : len;
-
- buffer = _cpp_unaligned_alloc (pfile, clen);
-
- token->type = CPP_COMMENT;
- token->val.str.len = clen;
- token->val.str.text = buffer;
-
- buffer[0] = '/';
- copy_text_chars (buffer + 1, from, len);
-
- /* Finish conversion to a C comment, if necessary. */
- if (pfile->state.in_directive && type == '/')
- {
- buffer[1] = '*';
- buffer[clen - 2] = '*';
- buffer[clen - 1] = '/';
- }
-}
-
-/* Allocate COUNT tokens for RUN. */
-void
-_cpp_init_tokenrun (tokenrun *run, unsigned int count)
-{
- run->base = xnewvec (cpp_token, count);
- run->limit = run->base + count;
- run->next = NULL;
-}
-
-/* Returns the next tokenrun, or creates one if there is none. */
-static tokenrun *
-next_tokenrun (tokenrun *run)
-{
- if (run->next == NULL)
- {
- run->next = xnew (tokenrun);
- run->next->prev = run;
- _cpp_init_tokenrun (run->next, 250);
- }
-
- return run->next;
-}
-
-/* Allocate a single token that is invalidated at the same time as the
- rest of the tokens on the line. Has its line and col set to the
- same as the last lexed token, so that diagnostics appear in the
- right place. */
-cpp_token *
-_cpp_temp_token (cpp_reader *pfile)
-{
- cpp_token *old, *result;
-
- old = pfile->cur_token - 1;
- if (pfile->cur_token == pfile->cur_run->limit)
- {
- pfile->cur_run = next_tokenrun (pfile->cur_run);
- pfile->cur_token = pfile->cur_run->base;
- }
-
- result = pfile->cur_token++;
- result->line = old->line;
- result->col = old->col;
- return result;
-}
-
-/* Lex a token into RESULT (external interface). Takes care of issues
- like directive handling, token lookahead, multiple include
- optimization and skipping. */
-const cpp_token *
-_cpp_lex_token (cpp_reader *pfile)
-{
- cpp_token *result;
-
- for (;;)
- {
- if (pfile->cur_token == pfile->cur_run->limit)
- {
- pfile->cur_run = next_tokenrun (pfile->cur_run);
- pfile->cur_token = pfile->cur_run->base;
- }
-
- if (pfile->lookaheads)
- {
- pfile->lookaheads--;
- result = pfile->cur_token++;
- }
- else
- result = _cpp_lex_direct (pfile);
-
- if (result->flags & BOL)
- {
- /* Is this a directive. If _cpp_handle_directive returns
- false, it is an assembler #. */
- if (result->type == CPP_HASH
- /* 6.10.3 p 11: Directives in a list of macro arguments
- gives undefined behavior. This implementation
- handles the directive as normal. */
- && pfile->state.parsing_args != 1
- && _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);
- }
-
- /* We don't skip tokens in directives. */
- if (pfile->state.in_directive)
- break;
-
- /* 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 optimization works. */
- pfile->mi_valid = false;
-
- if (!pfile->state.skipping || result->type == CPP_EOF)
- break;
- }
-
- return result;
-}
-
-/* Returns true if a fresh line has been loaded. */
-bool
-_cpp_get_fresh_line (cpp_reader *pfile)
-{
- int return_at_eof;
-
- /* We can't get a new line until we leave the current directive. */
- if (pfile->state.in_directive)
- return false;
-
- for (;;)
- {
- cpp_buffer *buffer = pfile->buffer;
-
- if (!buffer->need_line)
- return true;
-
- if (buffer->next_line < buffer->rlimit)
- {
- _cpp_clean_line (pfile);
- return true;
- }
-
- /* 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_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 \
- { \
- 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
- 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.
-
- When meeting a newline, returns CPP_EOF if parsing a directive,
- otherwise returns to the start of the token buffer if permissible.
- Returns the location of the lexed token. */
-cpp_token *
-_cpp_lex_direct (cpp_reader *pfile)
-{
- cppchar_t c;
- cpp_buffer *buffer;
- const unsigned char *comment_start;
- 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;
- 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);
-
- switch (c)
- {
- case ' ': case '\t': case '\f': case '\v': case '\0':
- result->flags |= PREV_WHITE;
- skip_whitespace (pfile, c);
- goto skipped_white;
-
- 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_lex_number (pfile, &result->val.str);
- else
- lex_number (pfile, &result->val.str);
- break;
-
- case 'L':
- /* 'L' may introduce wide characters or strings. */
- if (*buffer->cur == '\'' || *buffer->cur == '"')
- {
- lex_string (pfile, result, buffer->cur - 1);
- break;
- }
- /* Fall through. */
-
- 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':
- case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K':
- case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- result->type = CPP_NAME;
- result->val.node = lex_identifier (pfile, buffer->cur - 1);
-
- /* SDCC _asm specific */
- /* handle _asm ... _endasm ; */
- if (CPP_OPTION(pfile, preproc_asm) == 0 && result->val.node == pfile->spec_nodes.n__asm)
- {
- comment_start = buffer->cur;
- result->type = CPP_ASM;
- skip_asm_block (pfile);
- /* Save the _asm block as a token in its own right. */
- save_asm (pfile, result, comment_start);
- }
- /* Convert named operators to their proper types. */
- else if (result->val.node->flags & NODE_OPERATOR)
- {
- result->flags |= NAMED_OP;
- result->type = result->val.node->directive_index;
- }
- break;
-
- case '\'':
- case '"':
- lex_string (pfile, result, buffer->cur - 1);
- break;
-
- case '/':
- /* A potential block or line comment. */
- comment_start = buffer->cur;
- c = *buffer->cur;
-
- if (c == '*')
- {
- 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)))
- {
- /* Warn about comments only if pedantically GNUC89, and not
- in system headers. */
- if (CPP_OPTION (pfile, lang) == CLK_GNUC89 && CPP_PEDANTIC (pfile)
- && ! buffer->warned_cplusplus_comments)
- {
- cpp_error (pfile, CPP_DL_PEDWARN,
- "C++ style comments are not allowed in ISO C90");
- 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, CPP_DL_WARNING, "multi-line comment");
- }
- else if (c == '=')
- {
- buffer->cur++;
- result->type = CPP_DIV_EQ;
- break;
- }
- else
- {
- result->type = CPP_DIV;
- break;
- }
-
- if (!pfile->state.save_comments)
- {
- result->flags |= PREV_WHITE;
- goto update_tokens_line;
- }
-
- /* Save the comment as a token in its own right. */
- save_comment (pfile, result, comment_start, c);
- break;
-
- case '<':
- if (pfile->state.angled_headers)
- {
- lex_string (pfile, result, buffer->cur - 1);
- break;
- }
-
- result->type = CPP_LESS;
- if (*buffer->cur == '=')
- buffer->cur++, result->type = CPP_LESS_EQ;
- else if (*buffer->cur == '<')
- {
- buffer->cur++;
- IF_NEXT_IS ('=', CPP_LSHIFT_EQ, CPP_LSHIFT);
- }
- else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus))
- {
- buffer->cur++;
- IF_NEXT_IS ('=', CPP_MIN_EQ, CPP_MIN);
- }
- else if (CPP_OPTION (pfile, digraphs))
- {
- 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 '>':
- result->type = CPP_GREATER;
- if (*buffer->cur == '=')
- buffer->cur++, result->type = CPP_GREATER_EQ;
- else if (*buffer->cur == '>')
- {
- 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 '%':
- result->type = CPP_MOD;
- if (*buffer->cur == '=')
- buffer->cur++, result->type = CPP_MOD_EQ;
- else if (CPP_OPTION (pfile, digraphs))
- {
- if (*buffer->cur == ':')
- {
- 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;
- }
- }
- break;
-
- case '.':
- result->type = CPP_DOT;
- if (ISDIGIT (*buffer->cur))
- {
- result->type = CPP_NUMBER;
- if (CPP_OPTION(pfile, pedantic_parse_number))
- pedantic_lex_number (pfile, &result->val.str);
- else
- lex_number (pfile, &result->val.str);
- }
- 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 '+':
- 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 '-':
- result->type = CPP_MINUS;
- if (*buffer->cur == '>')
- {
- buffer->cur++;
- result->type = CPP_DEREF;
- 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 '&':
- 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 '|':
- 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 ':':
- 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;
- }
- break;
-
- case '*': IF_NEXT_IS ('=', CPP_MULT_EQ, CPP_MULT); break;
- case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break;
- case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break;
- 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;
- case ')': result->type = CPP_CLOSE_PAREN; break;
- case '[': result->type = CPP_OPEN_SQUARE; break;
- case ']': result->type = CPP_CLOSE_SQUARE; break;
- case '{': result->type = CPP_OPEN_BRACE; break;
- case '}': result->type = CPP_CLOSE_BRACE; break;
- case ';': result->type = CPP_SEMICOLON; break;
-
- /* @ is a punctuator in Objective-C. */
- case '@': result->type = CPP_ATSIGN; break;
-
- case '$':
- 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++;
- }
-
- default:
- 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.
- Does not include preceding whitespace. */
-unsigned int
-cpp_token_len (const cpp_token *token)
-{
- unsigned int len;
-
- switch (TOKEN_SPELL (token))
- {
- default: len = 4; break;
- case SPELL_LITERAL: len = token->val.str.len; break;
- case SPELL_IDENT: len = NODE_LEN (token->val.node); break;
- }
-
- 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.
- FIXME: Would be nice if we didn't need the PFILE argument. */
-unsigned char *
-cpp_spell_token (cpp_reader *pfile, const cpp_token *token,
- unsigned char *buffer)
-{
- switch (TOKEN_SPELL (token))
- {
- case SPELL_OPERATOR:
- {
- const unsigned char *spelling;
- unsigned char c;
-
- if (token->flags & DIGRAPH)
- spelling
- = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH];
- else if (token->flags & NAMED_OP)
- goto spell_ident;
- else
- spelling = TOKEN_NAME (token);
-
- while ((c = *spelling++) != '\0')
- *buffer++ = 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_LITERAL:
- memcpy (buffer, token->val.str.text, token->val.str.len);
- buffer += token->val.str.len;
- break;
-
- case SPELL_NONE:
- cpp_error (pfile, CPP_DL_ICE,
- "unspellable token %s", TOKEN_NAME (token));
- break;
- }
-
- return 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 (cpp_reader *pfile, const cpp_token *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);
- end[0] = '\0';
-
- return start;
-}
-
-/* Used by C front ends, which really should move to using
- cpp_token_as_text. */
-const char *
-cpp_type2name (enum cpp_ttype type)
-{
- return (const char *) token_spellings[type].name;
-}
-
-/* Writes the spelling of token to FP, without any preceding space.
- Separated from cpp_spell_token for efficiency - to avoid stdio
- double-buffering. */
-void
-cpp_output_token (const cpp_token *token, FILE *fp)
-{
- switch (TOKEN_SPELL (token))
- {
- case SPELL_OPERATOR:
- {
- const unsigned char *spelling;
- int c;
-
- if (token->flags & DIGRAPH)
- spelling
- = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH];
- else if (token->flags & NAMED_OP)
- goto spell_ident;
- else
- spelling = TOKEN_NAME (token);
-
- c = *spelling;
- do
- putc (c, fp);
- while ((c = *++spelling) != '\0');
- }
- break;
-
- spell_ident:
- case SPELL_IDENT:
- fwrite (NODE_NAME (token->val.node), 1, NODE_LEN (token->val.node), fp);
- break;
-
- case SPELL_LITERAL:
- fwrite (token->val.str.text, 1, token->val.str.len, fp);
- break;
-
- case SPELL_NONE:
- /* An error, most probably. */
- break;
- }
-}
-
-/* Compare two tokens. */
-int
-_cpp_equiv_tokens (const cpp_token *a, const cpp_token *b)
-{
- if (a->type == b->type && a->flags == b->flags)
- switch (TOKEN_SPELL (a))
- {
- default: /* Keep compiler happy. */
- case SPELL_OPERATOR:
- return 1;
- 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_LITERAL:
- return (a->val.str.len == b->val.str.len
- && !memcmp (a->val.str.text, b->val.str.text,
- a->val.str.len));
- }
-
- return 0;
-}
-
-/* Returns nonzero if a space should be inserted to avoid an
- accidental token paste for output. For simplicity, it is
- conservative, and occasionally advises a space where one is not
- needed, e.g. "." and ".2". */
-int
-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;
-
- if (token1->flags & NAMED_OP)
- a = CPP_NAME;
- if (token2->flags & NAMED_OP)
- b = CPP_NAME;
-
- c = EOF;
- if (token2->flags & DIGRAPH)
- c = digraph_spellings[(int) b - (int) CPP_FIRST_DIGRAPH][0];
- else if (token_spellings[b].category == SPELL_OPERATOR)
- c = token_spellings[b].name[0];
-
- /* Quickly get everything that can paste with an '='. */
- if ((int) a <= (int) CPP_LAST_EQ && c == '=')
- return 1;
-
- switch (a)
- {
- case CPP_GREATER: return c == '>' || c == '?';
- case CPP_LESS: return c == '<' || c == '?' || c == '%' || c == ':';
- case CPP_PLUS: return c == '+';
- case CPP_MINUS: return c == '-' || c == '>';
- case CPP_DIV: return c == '/' || c == '*'; /* Comments. */
- case CPP_MOD: return c == ':' || c == '>';
- case CPP_AND: return c == '&';
- case CPP_OR: return c == '|';
- case CPP_COLON: return c == ':' || c == '>';
- case CPP_DEREF: return c == '*';
- case CPP_DOT: return c == '.' || c == '%' || b == CPP_NUMBER;
- case CPP_HASH: return c == '#' || c == '%'; /* Digraph form. */
- case CPP_NAME: return ((b == CPP_NUMBER
- && name_p (pfile, &token2->val.str))
- || b == CPP_NAME
- || b == CPP_CHAR || b == CPP_STRING); /* L */
- case CPP_NUMBER: return (b == CPP_NUMBER || b == CPP_NAME
- || c == '.' || c == '+' || c == '-');
- /* 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;
- }
-
- return 0;
-}
-
-/* Output all the remaining tokens on the current line, and a newline
- character, to FP. Leading whitespace is removed. If there are
- macros, special token padding is not performed. */
-void
-cpp_output_line (cpp_reader *pfile, FILE *fp)
-{
- const cpp_token *token;
-
- token = cpp_get_token (pfile);
- while (token->type != CPP_EOF)
- {
- cpp_output_token (token, fp);
- token = cpp_get_token (pfile);
- if (token->flags & PREV_WHITE)
- putc (' ', fp);
- }
-
- putc ('\n', fp);
-}
-
-/* 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
- range of uses of cpplib, including heavy nested function-like macro
- expansion. Also check the change in peak memory usage (NJAMD is a
- good tool for this). */
-#define MIN_BUFF_SIZE 8000
-#define BUFF_SIZE_UPPER_BOUND(MIN_SIZE) (MIN_BUFF_SIZE + (MIN_SIZE) * 3 / 2)
-#define EXTENDED_BUFF_SIZE(BUFF, MIN_EXTRA) \
- (MIN_EXTRA + ((BUFF)->limit - (BUFF)->cur) * 2)
-
-#if MIN_BUFF_SIZE > BUFF_SIZE_UPPER_BOUND (0)
- #error BUFF_SIZE_UPPER_BOUND must be at least as large as MIN_BUFF_SIZE!
-#endif
-
-/* 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 (size_t len)
-{
- _cpp_buff *result;
- unsigned char *base;
-
- if (len < MIN_BUFF_SIZE)
- len = MIN_BUFF_SIZE;
- len = CPP_ALIGN (len);
-
- base = xmalloc (len + sizeof (_cpp_buff));
- result = (_cpp_buff *) (base + len);
- result->base = base;
- result->cur = base;
- result->limit = base + len;
- result->next = NULL;
- return result;
-}
-
-/* Place a chain of unwanted allocation buffers on the free list. */
-void
-_cpp_release_buff (cpp_reader *pfile, _cpp_buff *buff)
-{
- _cpp_buff *end = buff;
-
- while (end->next)
- end = end->next;
- end->next = pfile->free_buffs;
- pfile->free_buffs = buff;
-}
-
-/* Return a free buffer of size at least MIN_SIZE. */
-_cpp_buff *
-_cpp_get_buff (cpp_reader *pfile, size_t min_size)
-{
- _cpp_buff *result, **p;
-
- for (p = &pfile->free_buffs;; p = &(*p)->next)
- {
- size_t size;
-
- if (*p == NULL)
- return new_buff (min_size);
- result = *p;
- size = result->limit - result->base;
- /* Return a buffer that's big enough, but don't waste one that's
- way too big. */
- if (size >= min_size && size <= BUFF_SIZE_UPPER_BOUND (min_size))
- break;
- }
-
- *p = result->next;
- result->next = NULL;
- result->cur = result->base;
- return result;
-}
-
-/* Creates a new buffer with enough space to hold the uncommitted
- remaining bytes of BUFF, and at least MIN_EXTRA more bytes. Copies
- the excess bytes to the new buffer. Chains the new buffer after
- BUFF, and returns the new buffer. */
-_cpp_buff *
-_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);
-
- buff->next = new_buff;
- memcpy (new_buff->base, buff->cur, BUFF_ROOM (buff));
- return new_buff;
-}
-
-/* Creates a new buffer with enough space to hold the uncommitted
- remaining bytes of the buffer pointed to by BUFF, and at least
- MIN_EXTRA more bytes. Copies the excess bytes to the new buffer.
- 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 (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);
-
- new_buff = _cpp_get_buff (pfile, size);
- memcpy (new_buff->base, old_buff->cur, BUFF_ROOM (old_buff));
- new_buff->next = old_buff;
- *pbuff = new_buff;
-}
-
-/* Free a chain of buffers starting at BUFF. */
-void
-_cpp_free_buff (_cpp_buff *buff)
-{
- _cpp_buff *next;
-
- for (; buff; buff = next)
- {
- next = buff->next;
- free (buff->base);
- }
-}
-
-/* Allocate permanent, unaligned storage of length LEN. */
-unsigned char *
-_cpp_unaligned_alloc (cpp_reader *pfile, size_t len)
-{
- _cpp_buff *buff = pfile->u_buff;
- unsigned char *result = buff->cur;
-
- if (len > (size_t) (buff->limit - result))
- {
- buff = _cpp_get_buff (pfile, len);
- buff->next = pfile->u_buff;
- pfile->u_buff = buff;
- result = buff->cur;
- }
-
- buff->cur = result + len;
- return result;
-}
-
-/* Allocate permanent, unaligned storage of length LEN from a_buff.
- That buffer is used for growing allocations when saving macro
- replacement lists in a #define, and when parsing an answer to an
- assertion in #assert, #unassert or #if (and therefore possibly
- whilst expanding macros). It therefore must not be used by any
- code that they might call: specifically the lexer and the guts of
- the macro expander.
-
- All existing other uses clearly fit this restriction: storing
- registered pragmas during initialization. */
-unsigned char *
-_cpp_aligned_alloc (cpp_reader *pfile, size_t len)
-{
- _cpp_buff *buff = pfile->a_buff;
- unsigned char *result = buff->cur;
-
- if (len > (size_t) (buff->limit - result))
- {
- buff = _cpp_get_buff (pfile, len);
- buff->next = pfile->a_buff;
- pfile->a_buff = buff;
- result = buff->cur;
- }
-
- buff->cur = result + len;
- return result;
-}
+++ /dev/null
-/* CPP Library. (Directive handling.)
- 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 "obstack.h"
-
-/* Chained list of answers to an assertion. */
-struct answer
-{
- struct answer *next;
- unsigned int count;
- cpp_token first[1];
-};
-
-/* Stack of conditionals currently in progress
- (including both successful and failing conditionals). */
-struct if_stack
-{
- struct if_stack *next;
- unsigned int line; /* Line where condition started. */
- 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. */
-};
-
-/* Contains a registered pragma or pragma namespace. */
-typedef void (*pragma_cb) (cpp_reader *);
-struct pragma_entry
-{
- struct pragma_entry *next;
- const cpp_hashnode *pragma; /* Name and length. */
- int is_nspace;
- union {
- pragma_cb handler;
- struct pragma_entry *space;
- } u;
-};
-
-/* Values for the origin field of struct directive. KANDR directives
- come from traditional (K&R) C. STDC89 directives come from the
- 1989 C standard. EXTENSION directives are extensions. */
-#define KANDR 0
-#define STDC89 1
-#define EXTENSION 2
-
-/* Values for the flags field of struct directive. COND indicates a
- conditional; IF_COND an opening conditional. INCL means to treat
- "..." and <...> as q-char and h-char sequences respectively. IN_I
- means this directive should be handled even if -fpreprocessed is in
- effect (these are the directives with callback hooks).
-
- EXPAND is set on directives that are always macro-expanded. */
-#define COND (1 << 0)
-#define IF_COND (1 << 1)
-#define INCL (1 << 2)
-#define IN_I (1 << 3)
-#define EXPAND (1 << 4)
-
-/* Defines one #-directive, including how to handle it. */
-typedef void (*directive_handler) (cpp_reader *);
-typedef struct directive directive;
-struct directive
-{
- directive_handler handler; /* Function to handle directive. */
- const uchar *name; /* Name of directive. */
- unsigned short length; /* Length of name. */
- unsigned char origin; /* Origin of directive. */
- unsigned char flags; /* Flags describing this directive. */
-};
-
-/* Forward declarations. */
-
-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
- counts from all the source code I have lying around (egcs and libc
- CVS as of 1999-05-18, plus grub-0.5.91, linux-2.2.9, and
- pcmcia-cs-3.0.9). This is no longer important as directive lookup
- is now O(1). All extensions other than #warning and #include_next
- are deprecated. The name is where the extension appears to have
- come from. */
-
-#define DIRECTIVE_TABLE \
-D(define, T_DEFINE = 0, KANDR, IN_I) /* 270554 */ \
-D(include, T_INCLUDE, KANDR, INCL | EXPAND) /* 52262 */ \
-D(endif, T_ENDIF, KANDR, COND) /* 45855 */ \
-D(ifdef, T_IFDEF, KANDR, COND | IF_COND) /* 22000 */ \
-D(if, T_IF, KANDR, COND | IF_COND | EXPAND) /* 18162 */ \
-D(else, T_ELSE, KANDR, COND) /* 9863 */ \
-D(ifndef, T_IFNDEF, KANDR, COND | IF_COND) /* 9675 */ \
-D(undef, T_UNDEF, KANDR, IN_I) /* 4837 */ \
-D(line, T_LINE, KANDR, EXPAND) /* 2465 */ \
-D(elif, T_ELIF, STDC89, COND | EXPAND) /* 610 */ \
-D(error, T_ERROR, STDC89, 0) /* 475 */ \
-D(pragma, T_PRAGMA, STDC89, IN_I) /* 195 */ \
-D(warning, T_WARNING, EXTENSION, 0) /* 22 */ \
-D(include_next, T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND) /* 19 */ \
-D(ident, T_IDENT, EXTENSION, IN_I) /* 11 */ \
-D(import, T_IMPORT, EXTENSION, INCL | EXPAND) /* 0 ObjC */ \
-D(assert, T_ASSERT, EXTENSION, 0) /* 0 SVR4 */ \
-D(unassert, T_UNASSERT, EXTENSION, 0) /* 0 SVR4 */ \
-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. */
-
-#define D(name, t, o, f) static void do_##name (cpp_reader *);
-DIRECTIVE_TABLE
-#undef D
-
-#define D(n, tag, o, f) tag,
-enum
-{
- DIRECTIVE_TABLE
- N_DIRECTIVES
-};
-#undef D
-
-#define D(name, t, origin, flags) \
-{ do_##name, (const uchar *) #name, \
- sizeof #name - 1, origin, flags },
-static const directive dtable[] =
-{
-DIRECTIVE_TABLE
-};
-#undef D
-#undef DIRECTIVE_TABLE
-
-/* Wrapper struct directive for linemarkers.
- The origin is more or less true - the original K+R cpp
- did use this notation in its preprocessed output. */
-static const directive linemarker_dir =
-{
- do_linemarker, U"#", 1, KANDR, IN_I
-};
-
-#define SEEN_EOL() (pfile->cur_token[-1].type == CPP_EOF)
-
-/* Skip any remaining tokens in a directive. */
-static void
-skip_rest_of_line (cpp_reader *pfile)
-{
- /* Discard all stacked contexts. */
- while (pfile->context->prev)
- _cpp_pop_context (pfile);
-
- /* Sweep up all tokens remaining on the line. */
- if (! SEEN_EOL ())
- while (_cpp_lex_token (pfile)->type != CPP_EOF)
- ;
-}
-
-/* Ensure there are no stray tokens at the end of a directive. */
-static void
-check_eol (cpp_reader *pfile)
-{
- if (! SEEN_EOL () && _cpp_lex_token (pfile)->type != CPP_EOF)
- 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 (cpp_reader *pfile)
-{
- /* Setup in-directive state. */
- pfile->state.in_directive = 1;
- pfile->state.save_comments = 0;
-
- /* Some handlers need the position of the # for diagnostics. */
- pfile->directive_line = pfile->line;
-}
-
-/* Called when leaving a directive, _Pragma or command-line directive. */
-static void
-end_directive (cpp_reader *pfile, int skip_line)
-{
- if (CPP_OPTION (pfile, traditional))
- {
- /* Revert change of prepare_directive_trad. */
- pfile->state.prevent_expansion--;
-
- if (pfile->directive != &dtable[T_DEFINE])
- _cpp_remove_overlay (pfile);
- }
- /* We don't skip for an assembler #. */
- else if (skip_line)
- {
- skip_rest_of_line (pfile);
- if (!pfile->keep_tokens)
- {
- pfile->cur_run = &pfile->base_run;
- pfile->cur_token = pfile->base_run.base;
- }
- }
-
- /* Restore state. */
- pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
- pfile->state.in_directive = 0;
- pfile->state.in_expression = 0;
- pfile->state.angled_headers = 0;
- pfile->directive = 0;
-}
-
-/* Prepare to handle the directive in pfile->directive. */
-static void
-prepare_directive_trad (cpp_reader *pfile)
-{
- if (pfile->directive != &dtable[T_DEFINE])
- {
- bool no_expand = (pfile->directive
- && ! (pfile->directive->flags & EXPAND));
- bool was_skipping = pfile->state.skipping;
-
- 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_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);
- }
-
- /* Stop ISO C from expanding anything. */
- pfile->state.prevent_expansion++;
-}
-
-/* Output diagnostics for a directive DIR. INDENTED is nonzero if
- the '#' was indented. */
-static void
-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, 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
- compilers, directives added by C89 must have their #
- indented, and directives present in traditional C must not.
- This is true even of directives in skipped conditional
- blocks. #elif cannot be used at all. */
- if (CPP_WTRADITIONAL (pfile))
- {
- if (dir == &dtable[T_ELIF])
- cpp_error (pfile, CPP_DL_WARNING,
- "suggest not using #elif in traditional C");
- else if (indented && dir->origin == KANDR)
- cpp_error (pfile, CPP_DL_WARNING,
- "traditional C ignores #%s with the # indented",
- dir->name);
- else if (!indented && dir->origin != KANDR)
- cpp_error (pfile, CPP_DL_WARNING,
- "suggest hiding #%s from traditional C with an indented #",
- dir->name);
- }
-}
-
-/* Check if we have a known directive. INDENTED is nonzero if the
- '#' of the directive was indented. This function is in this file
- to save unnecessarily exporting dtable etc. to cpplex.c. Returns
- nonzero if the line of tokens has been handled, zero if we should
- continue processing the line. */
-int
-_cpp_handle_directive (cpp_reader *pfile, int indented)
-{
- const directive *dir = 0;
- const cpp_token *dname;
- bool was_parsing_args = pfile->state.parsing_args;
- int skip = 1;
-
- if (was_parsing_args)
- {
- if (CPP_OPTION (pfile, pedantic))
- 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;
- }
- start_directive (pfile);
- dname = _cpp_lex_token (pfile);
-
- if (dname->type == CPP_NAME)
- {
- 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. */
- else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM)
- {
- dir = &linemarker_dir;
- if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed)
- && ! pfile->state.skipping)
- cpp_error (pfile, CPP_DL_PEDWARN,
- "style of line directive is a GCC extension");
- }
-
- if (dir)
- {
- /* If we have a directive that is not an opening conditional,
- invalidate any control macro. */
- if (! (dir->flags & IF_COND))
- pfile->mi_valid = false;
-
- /* Kluge alert. In order to be sure that code like this
-
- #define HASH #
- HASH define foo bar
-
- does not cause '#define foo bar' to get executed when
- compiled with -save-temps, we recognize directives in
- -fpreprocessed mode only if the # is in column 1. cppmacro.c
- puts a space in front of any '#' at the start of a macro. */
- if (CPP_OPTION (pfile, preprocessed)
- && (indented || !(dir->flags & IN_I)))
- {
- skip = 0;
- dir = 0;
- }
- else
- {
- /* In failed conditional groups, all non-conditional
- directives are ignored. Before doing that, whether
- skipping or not, we should lex angle-bracketed headers
- correctly, and maybe output some diagnostics. */
- pfile->state.angled_headers = dir->flags & INCL;
- pfile->state.directive_wants_padding = dir->flags & INCL;
- if (! CPP_OPTION (pfile, preprocessed))
- directive_diagnostics (pfile, dir, indented);
- if (pfile->state.skipping && !(dir->flags & COND))
- dir = 0;
- }
- }
- else if (dname->type == CPP_EOF)
- ; /* CPP_EOF is the "null directive". */
- else
- {
- /* An unknown directive. Don't complain about it in assembly
- source: we don't know where the comments are, and # may
- introduce assembler pseudo-ops. Don't complain about invalid
- directives in skipped conditional groups (6.10 p4). */
- if (CPP_OPTION (pfile, lang) == CLK_ASM)
- skip = 0;
- else if (!pfile->state.skipping)
- cpp_error (pfile, CPP_DL_ERROR, "invalid preprocessing directive #%s",
- cpp_token_as_text (pfile, dname));
- }
-
- pfile->directive = dir;
- if (CPP_OPTION (pfile, traditional))
- prepare_directive_trad (pfile);
-
- if (dir)
- pfile->directive->handler (pfile);
- else if (skip == 0)
- _cpp_backup_tokens (pfile, 1);
-
- end_directive (pfile, skip);
- if (was_parsing_args)
- {
- /* Restore state when within macro args. */
- pfile->state.parsing_args = 2;
- pfile->state.prevent_expansion = 1;
- }
- return skip;
-}
-
-/* Directive handler wrapper used by the command line option
- processor. BUF is \n terminated. */
-static void
-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);
- /* Disgusting hack. */
- if (dir_no == T_PRAGMA)
- pfile->buffer->file = pfile->buffer->prev->file;
- start_directive (pfile);
-
- /* 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);
- pfile->directive->handler (pfile);
- end_directive (pfile, 1);
- if (dir_no == T_PRAGMA)
- 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 (cpp_reader *pfile)
-{
- const cpp_token *token = _cpp_lex_token (pfile);
-
- /* The token immediately after #define must be an identifier. That
- identifier may not be "defined", per C99 6.10.8p4.
- In C++, it may not be any of the "named operators" either,
- per C++98 [lex.digraph], [lex.key].
- Finally, the identifier may not have been poisoned. (In that case
- the lexer has issued the error message for us.) */
-
- if (token->type == CPP_NAME)
- {
- cpp_hashnode *node = token->val.node;
-
- if (node == pfile->spec_nodes.n_defined)
- 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, 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, CPP_DL_ERROR, "no macro name given in #%s directive",
- pfile->directive->name);
- else
- 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 (cpp_reader *pfile)
-{
- cpp_hashnode *node = lex_macro_node (pfile);
-
- if (node)
- {
- /* If we have been requested to expand comments into macros,
- then re-enable saving of comments. */
- pfile->state.save_comments =
- ! CPP_OPTION (pfile, discard_comments_in_macro_exp);
-
- if (_cpp_create_definition (pfile, node))
- if (pfile->cb.define)
- pfile->cb.define (pfile, pfile->directive_line, node);
- }
-}
-
-/* Handle #undef. Mark the identifier NT_VOID in the hash table. */
-static void
-do_undef (cpp_reader *pfile)
-{
- cpp_hashnode *node = lex_macro_node (pfile);
-
- if (node)
- {
- if (pfile->cb.undef)
- pfile->cb.undef (pfile, pfile->directive_line, 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);
-
- _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 a malloced filename. */
-static char *
-glue_header_name (cpp_reader *pfile)
-{
- const cpp_token *token;
- 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 = xmalloc (capacity);
- for (;;)
- {
- token = get_token_no_padding (pfile);
-
- 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) + 2; /* Leading space, terminating \0. */
- if (total_len + len > capacity)
- {
- capacity = (capacity + len) * 2;
- buffer = xrealloc (buffer, capacity);
- }
-
- if (token->flags & PREV_WHITE)
- buffer[total_len++] = ' ';
-
- total_len = (cpp_spell_token (pfile, token, (uchar *) &buffer[total_len])
- - (uchar *) buffer);
- }
-
- buffer[total_len] = '\0';
- return buffer;
-}
-
-/* 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)
-{
- char *fname;
- const cpp_token *header;
-
- /* Allow macro expansion. */
- header = get_token_no_padding (pfile);
- if (header->type == CPP_STRING || header->type == CPP_HEADER_NAME)
- {
- 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;
- }
- else if (header->type == CPP_LESS)
- {
- fname = glue_header_name (pfile);
- *pangle_brackets = 1;
- }
- else
- {
- 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;
- }
-
- check_eol (pfile);
- return fname;
-}
-
-/* Handle #include, #include_next and #import. */
-static void
-do_include_common (cpp_reader *pfile, enum include_type type)
-{
- const char *fname;
- int angle_brackets;
-
- 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;
- }
-
- /* Prevent #include recursion. */
- if (pfile->line_maps.depth >= CPP_STACK_MAX)
- cpp_error (pfile, CPP_DL_ERROR, "#include nested too deeply");
- else
- {
- /* 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 (cpp_reader *pfile)
-{
- do_include_common (pfile, IT_INCLUDE);
-}
-
-static void
-do_import (cpp_reader *pfile)
-{
- do_include_common (pfile, IT_IMPORT);
-}
-
-static void
-do_include_next (cpp_reader *pfile)
-{
- 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.
- LAST is the last flag seen; 0 if this is the first flag. Return the
- flag if it is valid, 0 at the end of the directive. Otherwise
- complain. */
-static unsigned int
-read_flag (cpp_reader *pfile, unsigned int last)
-{
- const cpp_token *token = _cpp_lex_token (pfile);
-
- if (token->type == CPP_NUMBER && token->val.str.len == 1)
- {
- unsigned int flag = token->val.str.text[0] - '0';
-
- if (flag > last && flag <= 4
- && (flag != 4 || last == 3)
- && (flag != 2 || last == 0))
- return flag;
- }
-
- if (token->type != CPP_EOF)
- 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. 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 (const uchar *str, unsigned int len, long unsigned int *nump)
-{
- unsigned long reg = 0;
- uchar c;
- while (len--)
- {
- c = *str++;
- if (!ISDIGIT (c))
- return 1;
- reg *= 10;
- reg += c - '0';
- }
- *nump = reg;
- return 0;
-}
-
-/* Interpret #line command.
- Note that the filename string (if any) is a true string constant
- (escapes are interpreted), unlike in #line. */
-static void
-do_line (cpp_reader *pfile)
-{
- const cpp_token *token;
- const char *new_file = pfile->map->to_file;
- unsigned long new_lineno;
-
- /* C99 raised the minimum limit on #line numbers. */
- unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
-
- /* #line commands expand macros. */
- token = cpp_get_token (pfile);
- if (token->type != CPP_NUMBER
- || strtoul_for_line (token->val.str.text, token->val.str.len,
- &new_lineno))
- {
- 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, CPP_DL_PEDWARN, "line number out of range");
-
- token = cpp_get_token (pfile);
- if (token->type == CPP_STRING)
- {
- 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, CPP_DL_ERROR, "\"%s\" is not a valid filename",
- cpp_token_as_text (pfile, token));
- return;
- }
-
- skip_rest_of_line (pfile);
- _cpp_do_file_change (pfile, LC_RENAME, new_file, new_lineno,
- pfile->map->sysp);
-}
-
-/* Interpret the # 44 "file" [flags] notation, which has slightly
- different syntax and semantics from #line: Flags are allowed,
- and we never complain about the line number being too big. */
-static void
-do_linemarker (cpp_reader *pfile)
-{
- const cpp_token *token;
- const char *new_file = pfile->map->to_file;
- unsigned long new_lineno;
- unsigned int new_sysp = pfile->map->sysp;
- enum lc_reason reason = LC_RENAME;
- int flag;
-
- /* Back up so we can get the number again. Putting this in
- _cpp_handle_directive risks two calls to _cpp_backup_tokens in
- some circumstances, which can segfault. */
- _cpp_backup_tokens (pfile, 1);
-
- /* #line commands expand macros. */
- token = cpp_get_token (pfile);
- if (token->type != CPP_NUMBER
- || strtoul_for_line (token->val.str.text, token->val.str.len,
- &new_lineno))
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "\"%s\" after # is not a positive integer",
- cpp_token_as_text (pfile, token));
- return;
- }
-
- token = cpp_get_token (pfile);
- if (token->type == CPP_STRING)
- {
- 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)
- {
- reason = LC_ENTER;
- /* Fake an include for cpp_included (). */
- _cpp_fake_include (pfile, new_file);
- flag = read_flag (pfile, flag);
- }
- else if (flag == 2)
- {
- reason = LC_LEAVE;
- flag = read_flag (pfile, flag);
- }
- if (flag == 3)
- {
- new_sysp = 1;
- flag = read_flag (pfile, flag);
- if (flag == 4)
- new_sysp = 2;
- }
-
- check_eol (pfile);
- }
- else if (token->type != CPP_EOF)
- {
- cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename",
- cpp_token_as_text (pfile, token));
- return;
- }
-
- skip_rest_of_line (pfile);
- _cpp_do_file_change (pfile, reason, new_file, new_lineno, new_sysp);
-}
-
-/* Arrange the file_change callback. pfile->line has changed to
- FILE_LINE of TO_FILE, for reason REASON. SYSP is 1 for a system
- header, 2 for a system header that needs to be extern "C" protected,
- and zero otherwise. */
-void
-_cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason,
- const char *to_file, unsigned int file_line,
- unsigned int sysp)
-{
- 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);
-}
-
-/* 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 (cpp_reader *pfile, int code, int print_dir)
-{
- if (_cpp_begin_message (pfile, code,
- pfile->cur_token[-1].line,
- pfile->cur_token[-1].col))
- {
- if (print_dir)
- fprintf (stderr, "#%s ", pfile->directive->name);
- pfile->state.prevent_expansion++;
- cpp_output_line (pfile, stderr);
- pfile->state.prevent_expansion--;
- }
-}
-
-static void
-do_error (cpp_reader *pfile)
-{
- do_diagnostic (pfile, CPP_DL_ERROR, 1);
-}
-
-static void
-do_warning (cpp_reader *pfile)
-{
- /* We want #warning diagnostics to be emitted in system headers too. */
- do_diagnostic (pfile, CPP_DL_WARNING_SYSHDR, 1);
-}
-
-/* Report program identification. */
-static void
-do_ident (cpp_reader *pfile)
-{
- const cpp_token *str = cpp_get_token (pfile);
-
- if (str->type != CPP_STRING)
- cpp_error (pfile, CPP_DL_ERROR, "invalid #ident directive");
- else if (pfile->cb.ident)
- pfile->cb.ident (pfile, pfile->directive_line, &str->val.str);
-
- check_eol (pfile);
-}
-
-/* Lookup a PRAGMA name in a singly-linked CHAIN. Returns the
- 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 (struct pragma_entry *chain, const cpp_hashnode *pragma)
-{
- while (chain && chain->pragma != pragma)
- chain = chain->next;
-
- return chain;
-}
-
-/* Create and insert a pragma entry for NAME at the beginning of a
- 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 (cpp_reader *pfile, struct pragma_entry **chain,
- const cpp_hashnode *pragma, pragma_cb handler)
-{
- struct pragma_entry *new;
-
- new = (struct pragma_entry *)
- _cpp_aligned_alloc (pfile, sizeof (struct pragma_entry));
- new->pragma = pragma;
- if (handler)
- {
- new->is_nspace = 0;
- new->u.handler = handler;
- }
- else
- {
- new->is_nspace = 1;
- new->u.space = NULL;
- }
-
- new->next = *chain;
- *chain = new;
- return new;
-}
-
-/* Register a pragma NAME in namespace SPACE. If SPACE is null, it
- goes in the global namespace. HANDLER is the handler it will call,
- which must be non-NULL. */
-void
-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;
- const cpp_hashnode *node;
-
- if (!handler)
- abort ();
-
- if (space)
- {
- node = cpp_lookup (pfile, U space, strlen (space));
- entry = lookup_pragma_entry (*chain, node);
- if (!entry)
- entry = insert_pragma_entry (pfile, chain, node, NULL);
- else if (!entry->is_nspace)
- goto clash;
- chain = &entry->u.space;
- }
-
- /* Check for duplicates. */
- node = cpp_lookup (pfile, U name, strlen (name));
- entry = lookup_pragma_entry (*chain, node);
- if (entry)
- {
- if (entry->is_nspace)
- clash:
- 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, CPP_DL_ICE, "#pragma %s %s is already registered",
- space, name);
- else
- cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name);
- }
- else
- insert_pragma_entry (pfile, chain, node, handler);
-}
-
-/* Register the pragmas the preprocessor itself handles. */
-void
-_cpp_init_internal_pragmas (cpp_reader *pfile)
-{
- /* Pragmas in the global namespace. */
- cpp_register_pragma (pfile, 0, "once", do_pragma_once);
-
- /* New GCC-specific pragmas should be put in the GCC namespace. */
- cpp_register_pragma (pfile, "GCC", "poison", do_pragma_poison);
- cpp_register_pragma (pfile, "GCC", "system_header", do_pragma_system_header);
- cpp_register_pragma (pfile, "GCC", "dependency", do_pragma_dependency);
-
- /* Kevin abuse for SDCC. */
- cpp_register_pragma(pfile, 0, "sdcc_hash", do_pragma_sdcc_hash);
- /* SDCC _asm specific */
- cpp_register_pragma(pfile, 0, "preproc_asm", do_pragma_preproc_asm);
- /* SDCC specific */
- 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 (cpp_reader *pfile)
-{
- const struct pragma_entry *p = NULL;
- const cpp_token *token, *pragma_token = pfile->cur_token;
- unsigned int count = 1;
-
- pfile->state.prevent_expansion++;
-
- token = cpp_get_token (pfile);
- if (token->type == CPP_NAME)
- {
- p = lookup_pragma_entry (pfile->pragmas, token->val.node);
- if (p && p->is_nspace)
- {
- count = 2;
- token = cpp_get_token (pfile);
- if (token->type == CPP_NAME)
- p = lookup_pragma_entry (p->u.space, token->val.node);
- else
- p = NULL;
- }
- }
-
- if (p)
- {
- /* Since the handler below doesn't get the line number, that it
- might need for diagnostics, make sure it has the right
- numbers in place. */
- if (pfile->cb.line_change)
- (*pfile->cb.line_change) (pfile, pragma_token, false);
- (*p->u.handler) (pfile);
- }
- else if (pfile->cb.def_pragma)
- {
- _cpp_backup_tokens (pfile, count);
- pfile->cb.def_pragma (pfile, pfile->directive_line);
- }
-
- pfile->state.prevent_expansion--;
-}
-
-/* Handle #pragma once. */
-static void
-do_pragma_once (cpp_reader *pfile)
-{
- if (pfile->buffer->prev == NULL)
- 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 (cpp_reader *pfile)
-{
- const cpp_token *tok;
- cpp_hashnode *hp;
-
- pfile->state.poisoned_ok = 1;
- for (;;)
- {
- tok = _cpp_lex_token (pfile);
- if (tok->type == CPP_EOF)
- break;
- if (tok->type != CPP_NAME)
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "invalid #pragma GCC poison directive");
- break;
- }
-
- hp = tok->val.node;
- if (hp->flags & NODE_POISONED)
- continue;
-
- if (hp->type == NT_MACRO)
- cpp_error (pfile, CPP_DL_WARNING, "poisoning existing macro \"%s\"",
- NODE_NAME (hp));
- _cpp_free_definition (hp);
- hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
- }
- pfile->state.poisoned_ok = 0;
-}
-
-/* SDCC specific
- sdcc_hash pragma */
-static void
-do_pragma_sdcc_hash (cpp_reader *pfile)
-{
- const cpp_token *tok = _cpp_lex_token (pfile);
-
- if (tok->type == CPP_PLUS)
- {
- CPP_OPTION(pfile, allow_naked_hash)++;
- }
- else if (tok->type == CPP_MINUS)
- {
- CPP_OPTION(pfile, allow_naked_hash)--;
- }
- else
- {
- 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 (cpp_reader *pfile)
-{
- const cpp_token *tok = _cpp_lex_token (pfile);
-
- if (tok->type == CPP_PLUS)
- {
- CPP_OPTION(pfile, pedantic_parse_number)++;
- }
- else if (tok->type == CPP_MINUS)
- {
- CPP_OPTION(pfile, pedantic_parse_number)--;
- }
- else
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "invalid #pragma pedantic_parse_number directive, need '+' or '-'");
- }
-}
-
-/* SDCC _asm specific
- switch _asm block preprocessing on / off */
-static void
-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)++;
- }
- else if (tok->type == CPP_MINUS)
- {
- CPP_OPTION(pfile, preproc_asm)--;
- }
- else
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "invalid #pragma preproc_asm directive, need '+' or '-'");
- }
-}
-
-/* Mark the current header as a system header. This will suppress
- some categories of warnings (notably those from -pedantic). It is
- intended for use in system libraries that cannot be implemented in
- conforming C, but cannot be certain that their headers appear in a
- system include directory. To prevent abuse, it is rejected in the
- primary source file. */
-static void
-do_pragma_system_header (cpp_reader *pfile)
-{
- cpp_buffer *buffer = pfile->buffer;
-
- if (buffer->prev == 0)
- cpp_error (pfile, CPP_DL_WARNING,
- "#pragma system_header ignored outside include file");
- else
- {
- check_eol (pfile);
- skip_rest_of_line (pfile);
- cpp_make_system_header (pfile, 1, 0);
- }
-}
-
-/* Check the modified date of the current include file against a specified
- 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 (cpp_reader *pfile)
-{
- const char *fname;
- int angle_brackets, ordering;
-
- fname = parse_include (pfile, &angle_brackets);
- if (!fname)
- return;
-
- ordering = _cpp_compare_file_date (pfile, fname, angle_brackets);
- if (ordering < 0)
- cpp_error (pfile, CPP_DL_WARNING, "cannot find source file %s", fname);
- else if (ordering > 0)
- {
- 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, CPP_DL_WARNING, 0);
- }
- }
-
- free ((void *) fname);
-}
-
-/* Get a token but skip padding. */
-static const cpp_token *
-get_token_no_padding (cpp_reader *pfile)
-{
- for (;;)
- {
- const cpp_token *result = cpp_get_token (pfile);
- if (result->type != CPP_PADDING)
- return result;
- }
-}
-
-/* Check syntax is "(string-literal)". Returns the string on success,
- or NULL on failure. */
-static const cpp_token *
-get__Pragma_string (cpp_reader *pfile)
-{
- const cpp_token *string;
-
- if (get_token_no_padding (pfile)->type != CPP_OPEN_PAREN)
- return NULL;
-
- string = get_token_no_padding (pfile);
- if (string->type != CPP_STRING && string->type != CPP_WSTRING)
- return NULL;
-
- if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN)
- return NULL;
-
- return string;
-}
-
-/* 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 (cpp_reader *pfile, const cpp_string *in)
-{
- const unsigned char *src, *limit;
- char *dest, *result;
-
- 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 = '\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
- context to force cpp_get_token to lex, and so skip_rest_of_line
- doesn't go beyond the end of the text. Also, remember the
- current lexing position so we can return to it later.
-
- Something like line-at-a-time lexing should remove the need for
- this. */
- {
- cpp_context *saved_context = pfile->context;
- cpp_token *saved_cur_token = pfile->cur_token;
- tokenrun *saved_cur_run = pfile->cur_run;
-
- pfile->context = xnew (cpp_context);
- pfile->context->macro = 0;
- pfile->context->prev = 0;
- run_directive (pfile, T_PRAGMA, result, dest - result);
- free (pfile->context);
- pfile->context = saved_context;
- pfile->cur_token = saved_cur_token;
- pfile->cur_run = saved_cur_run;
- pfile->line--;
- }
-
- /* See above comment. For the moment, we'd like
-
- token1 _Pragma ("foo") token2
-
- to be output as
-
- token1
- # 7 "file.c"
- #pragma foo
- # 7 "file.c"
- token2
-
- Getting the line markers is a little tricky. */
- if (pfile->cb.line_change)
- pfile->cb.line_change (pfile, pfile->cur_token, false);
-}
-
-/* Handle the _Pragma operator. */
-void
-_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, CPP_DL_ERROR,
- "_Pragma takes a parenthesized string literal");
-}
-
-/* Ignore #sccs on all systems. */
-static void
-do_sccs (cpp_reader *pfile ATTRIBUTE_UNUSED)
-{
-}
-
-/* Handle #ifdef. */
-static void
-do_ifdef (cpp_reader *pfile)
-{
- int skip = 1;
-
- if (! pfile->state.skipping)
- {
- const cpp_hashnode *node = lex_macro_node (pfile);
-
- if (node)
- {
- skip = node->type != NT_MACRO;
- _cpp_mark_macro_used (node);
- check_eol (pfile);
- }
- }
-
- push_conditional (pfile, skip, T_IFDEF, 0);
-}
-
-/* Handle #ifndef. */
-static void
-do_ifndef (cpp_reader *pfile)
-{
- int skip = 1;
- const cpp_hashnode *node = 0;
-
- if (! pfile->state.skipping)
- {
- node = lex_macro_node (pfile);
-
- if (node)
- {
- skip = node->type == NT_MACRO;
- _cpp_mark_macro_used (node);
- check_eol (pfile);
- }
- }
-
- push_conditional (pfile, skip, T_IFNDEF, node);
-}
-
-/* _cpp_parse_expr puts a macro in a "#if !defined ()" expression in
- pfile->mi_ind_cmacro so we can handle multiple-include
- 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 (cpp_reader *pfile)
-{
- int skip = 1;
-
- if (! pfile->state.skipping)
- skip = _cpp_parse_expr (pfile) == false;
-
- push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro);
-}
-
-/* Flip skipping state if appropriate and continue without changing
- if_stack; this is so that the error message for missing #endif's
- etc. will point to the original #if. */
-static void
-do_else (cpp_reader *pfile)
-{
- cpp_buffer *buffer = pfile->buffer;
- struct if_stack *ifs = buffer->if_stack;
-
- if (ifs == NULL)
- cpp_error (pfile, CPP_DL_ERROR, "#else without #if");
- else
- {
- if (ifs->type == T_ELSE)
- {
- 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;
-
- /* Skip any future (erroneous) #elses or #elifs. */
- pfile->state.skipping = ifs->skip_elses;
- ifs->skip_elses = true;
-
- /* Invalidate any controlling macro. */
- ifs->mi_cmacro = 0;
-
- /* Only check EOL if was not originally skipping. */
- if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels))
- check_eol (pfile);
- }
-}
-
-/* Handle a #elif directive by not changing if_stack either. See the
- comment above do_else. */
-static void
-do_elif (cpp_reader *pfile)
-{
- cpp_buffer *buffer = pfile->buffer;
- struct if_stack *ifs = buffer->if_stack;
-
- if (ifs == NULL)
- cpp_error (pfile, CPP_DL_ERROR, "#elif without #if");
- else
- {
- if (ifs->type == T_ELSE)
- {
- 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;
-
- /* Only evaluate this if we aren't skipping elses. During
- evaluation, set skipping to false to get lexer warnings. */
- if (ifs->skip_elses)
- pfile->state.skipping = 1;
- else
- {
- pfile->state.skipping = 0;
- pfile->state.skipping = ! _cpp_parse_expr (pfile);
- ifs->skip_elses = ! pfile->state.skipping;
- }
-
- /* Invalidate any controlling macro. */
- ifs->mi_cmacro = 0;
- }
-}
-
-/* #endif pops the if stack and resets pfile->state.skipping. */
-static void
-do_endif (cpp_reader *pfile)
-{
- cpp_buffer *buffer = pfile->buffer;
- struct if_stack *ifs = buffer->if_stack;
-
- if (ifs == NULL)
- cpp_error (pfile, CPP_DL_ERROR, "#endif without #if");
- else
- {
- /* Only check EOL if was not originally skipping. */
- if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels))
- check_eol (pfile);
-
- /* If potential control macro, we go back outside again. */
- if (ifs->next == 0 && ifs->mi_cmacro)
- {
- pfile->mi_valid = true;
- pfile->mi_cmacro = ifs->mi_cmacro;
- }
-
- buffer->if_stack = ifs->next;
- pfile->state.skipping = ifs->was_skipping;
- obstack_free (&pfile->buffer_ob, ifs);
- }
-}
-
-/* Push an if_stack entry for a preprocessor conditional, and set
- pfile->state.skipping to SKIP. If TYPE indicates the conditional
- 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 (cpp_reader *pfile, int skip, int type,
- const cpp_hashnode *cmacro)
-{
- struct if_stack *ifs;
- cpp_buffer *buffer = pfile->buffer;
-
- ifs = xobnew (&pfile->buffer_ob, struct if_stack);
- ifs->line = pfile->directive_line;
- ifs->next = buffer->if_stack;
- ifs->skip_elses = pfile->state.skipping || !skip;
- ifs->was_skipping = pfile->state.skipping;
- ifs->type = type;
- /* This condition is effectively a test for top-of-file. */
- if (pfile->mi_valid && pfile->mi_cmacro == 0)
- ifs->mi_cmacro = cmacro;
- else
- ifs->mi_cmacro = 0;
-
- pfile->state.skipping = skip;
- buffer->if_stack = ifs;
-}
-
-/* Read the tokens of the answer into the macro pool, in a directive
- of type TYPE. Only commit the memory if we intend it as permanent
- storage, i.e. the #assert case. Returns 0 on success, and sets
- ANSWERP to point to the answer. */
-static int
-parse_answer (cpp_reader *pfile, struct answer **answerp, int type)
-{
- const cpp_token *paren;
- struct answer *answer;
- unsigned int acount;
-
- /* In a conditional, it is legal to not have an open paren. We
- should save the following token in this case. */
- paren = cpp_get_token (pfile);
-
- /* If not a paren, see if we're OK. */
- if (paren->type != CPP_OPEN_PAREN)
- {
- /* In a conditional no answer is a test for any answer. It
- could be followed by any token. */
- if (type == T_IF)
- {
- _cpp_backup_tokens (pfile, 1);
- return 0;
- }
-
- /* #unassert with no answer is valid - it removes all answers. */
- if (type == T_UNASSERT && paren->type == CPP_EOF)
- return 0;
-
- cpp_error (pfile, CPP_DL_ERROR, "missing '(' after predicate");
- return 1;
- }
-
- for (acount = 0;; acount++)
- {
- size_t room_needed;
- const cpp_token *token = cpp_get_token (pfile);
- cpp_token *dest;
-
- if (token->type == CPP_CLOSE_PAREN)
- break;
-
- if (token->type == CPP_EOF)
- {
- cpp_error (pfile, CPP_DL_ERROR, "missing ')' to complete answer");
- return 1;
- }
-
- /* struct answer includes the space for one token. */
- room_needed = (sizeof (struct answer) + acount * sizeof (cpp_token));
-
- if (BUFF_ROOM (pfile->a_buff) < room_needed)
- _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (struct answer));
-
- dest = &((struct answer *) BUFF_FRONT (pfile->a_buff))->first[acount];
- *dest = *token;
-
- /* Drop whitespace at start, for answer equivalence purposes. */
- if (acount == 0)
- dest->flags &= ~PREV_WHITE;
- }
-
- if (acount == 0)
- {
- cpp_error (pfile, CPP_DL_ERROR, "predicate's answer is empty");
- return 1;
- }
-
- answer = (struct answer *) BUFF_FRONT (pfile->a_buff);
- answer->count = acount;
- answer->next = NULL;
- *answerp = answer;
-
- return 0;
-}
-
-/* Parses an assertion directive of type TYPE, returning a pointer to
- 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 (cpp_reader *pfile, struct answer **answerp, int type)
-{
- cpp_hashnode *result = 0;
- const cpp_token *predicate;
-
- /* We don't expand predicates or answers. */
- pfile->state.prevent_expansion++;
-
- *answerp = 0;
- predicate = cpp_get_token (pfile);
- if (predicate->type == CPP_EOF)
- cpp_error (pfile, CPP_DL_ERROR, "assertion without predicate");
- else if (predicate->type != CPP_NAME)
- 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);
- unsigned char *sym = alloca (len + 1);
-
- /* Prefix '#' to get it out of macro namespace. */
- sym[0] = '#';
- memcpy (sym + 1, NODE_NAME (predicate->val.node), len);
- result = cpp_lookup (pfile, sym, len + 1);
- }
-
- pfile->state.prevent_expansion--;
- return result;
-}
-
-/* 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 (cpp_hashnode *node, const struct answer *candidate)
-{
- unsigned int i;
- struct answer **result;
-
- for (result = &node->value.answers; *result; result = &(*result)->next)
- {
- struct answer *answer = *result;
-
- if (answer->count == candidate->count)
- {
- for (i = 0; i < answer->count; i++)
- if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i]))
- break;
-
- if (i == answer->count)
- break;
- }
- }
-
- return result;
-}
-
-/* Test an assertion within a preprocessor conditional. Returns
- 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 (cpp_reader *pfile, unsigned int *value)
-{
- struct answer *answer;
- cpp_hashnode *node;
-
- node = parse_assertion (pfile, &answer, T_IF);
-
- /* For recovery, an erroneous assertion expression is handled as a
- failing assertion. */
- *value = 0;
-
- if (node)
- *value = (node->type == NT_ASSERTION &&
- (answer == 0 || *find_answer (node, answer) != 0));
- else if (pfile->cur_token[-1].type == CPP_EOF)
- _cpp_backup_tokens (pfile, 1);
-
- /* We don't commit the memory for the answer - it's temporary only. */
- return node == 0;
-}
-
-/* Handle #assert. */
-static void
-do_assert (cpp_reader *pfile)
-{
- struct answer *new_answer;
- cpp_hashnode *node;
-
- node = parse_assertion (pfile, &new_answer, T_ASSERT);
- if (node)
- {
- /* Place the new answer in the answer list. First check there
- is not a duplicate. */
- new_answer->next = 0;
- if (node->type == NT_ASSERTION)
- {
- if (*find_answer (node, new_answer))
- {
- cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted",
- NODE_NAME (node) + 1);
- return;
- }
- new_answer->next = node->value.answers;
- }
-
- node->type = NT_ASSERTION;
- node->value.answers = new_answer;
- BUFF_FRONT (pfile->a_buff) += (sizeof (struct answer)
- + (new_answer->count - 1)
- * sizeof (cpp_token));
- check_eol (pfile);
- }
-}
-
-/* Handle #unassert. */
-static void
-do_unassert (cpp_reader *pfile)
-{
- cpp_hashnode *node;
- struct answer *answer;
-
- node = parse_assertion (pfile, &answer, T_UNASSERT);
- /* It isn't an error to #unassert something that isn't asserted. */
- if (node && node->type == NT_ASSERTION)
- {
- if (answer)
- {
- struct answer **p = find_answer (node, answer), *temp;
-
- /* Remove the answer from the list. */
- temp = *p;
- if (temp)
- *p = temp->next;
-
- /* Did we free the last answer? */
- if (node->value.answers == 0)
- node->type = NT_VOID;
-
- check_eol (pfile);
- }
- else
- _cpp_free_definition (node);
- }
-
- /* We don't commit the memory for the answer - it's temporary only. */
-}
-
-/* These are for -D, -U, -A. */
-
-/* Process the string STR as if it appeared as the body of a #define.
- If STR is just an identifier, define it with value 1.
- If STR has anything after the identifier, then it should
- be identifier=definition. */
-void
-cpp_define (cpp_reader *pfile, const char *str)
-{
- char *buf, *p;
- size_t count;
-
- /* Copy the entire option so we can modify it.
- Change the first "=" in the string to a space. If there is none,
- tack " 1" on the end. */
-
- count = strlen (str);
- buf = alloca (count + 3);
- memcpy (buf, str, count);
-
- p = strchr (str, '=');
- if (p)
- buf[p - str] = ' ';
- else
- {
- buf[count++] = ' ';
- buf[count++] = '1';
- }
- buf[count] = '\n';
-
- run_directive (pfile, T_DEFINE, buf, count);
-}
-
-/* Slight variant of the above for use by initialize_builtins. */
-void
-_cpp_define_builtin (cpp_reader *pfile, const char *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 (cpp_reader *pfile, const char *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 (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 (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 (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)
- {
- buf[p - str] = '(';
- buf[count++] = ')';
- }
- buf[count] = '\n';
- str = buf;
-
- run_directive (pfile, type, str, count);
-}
-
-/* The number of errors for a given reader. */
-unsigned int
-cpp_errors (cpp_reader *pfile)
-{
- return pfile->errors;
-}
-
-/* The options structure. */
-cpp_options *
-cpp_get_options (cpp_reader *pfile)
-{
- return &pfile->opts;
-}
-
-/* The callbacks structure. */
-cpp_callbacks *
-cpp_get_callbacks (cpp_reader *pfile)
-{
- return &pfile->cb;
-}
-
-/* The line map set. */
-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 (cpp_reader *pfile, cpp_callbacks *cb)
-{
- pfile->cb = *cb;
-}
-
-/* Push a new buffer on the buffer stack. Returns the new buffer; it
- doesn't fail. It does not generate a file change call back; that
- is the responsibility of the caller. */
-cpp_buffer *
-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->next_line = new->buf = buffer;
- new->rlimit = buffer + len;
- new->from_stage3 = from_stage3;
- new->prev = pfile->buffer;
- 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 (cpp_reader *pfile)
-{
- cpp_buffer *buffer = pfile->buffer;
- 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, CPP_DL_ERROR, ifs->line, 0,
- "unterminated #%s", dtable[ifs->type].name);
-
- /* In case of a missing #endif. */
- pfile->state.skipping = 0;
-
- /* _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);
-
- if (inc)
- {
- _cpp_pop_file_buffer (pfile, inc);
-
- _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
- }
-}
-
-/* Enter all recognized directives in the hash table. */
-void
-_cpp_init_directives (cpp_reader *pfile)
-{
- unsigned int i;
- cpp_hashnode *node;
-
- for (i = 0; i < (unsigned int) N_DIRECTIVES; i++)
- {
- node = cpp_lookup (pfile, dtable[i].name, dtable[i].length);
- node->is_directive = 1;
- node->directive_index = i;
- }
-}
+++ /dev/null
-/* Definitions for CPP library.
- Copyright (C) 1995, 1996, 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.
-
- 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! */
-#ifndef GCC_CPPLIB_H
-#define GCC_CPPLIB_H
-
-#include <sys/types.h>
-#include "hashtable.h"
-#include "line-map.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct cpp_reader cpp_reader;
-typedef struct cpp_buffer cpp_buffer;
-typedef struct cpp_options cpp_options;
-typedef struct cpp_token cpp_token;
-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;
-
-/* The first three groups, apart from '=', can appear in preprocessor
- expressions (+= and -= are used to indicate unary + and - resp.).
- This allows a lookup table to be implemented in _cpp_parse_expr.
-
- The first group, to CPP_LAST_EQ, can be immediately followed by an
- '='. The lexer needs operators ending in '=', like ">>=", to be in
- the same order as their counterparts without the '=', like ">>". */
-
-/* Positions in the table. */
-#define CPP_LAST_EQ CPP_MAX
-#define CPP_FIRST_DIGRAPH CPP_HASH
-#define CPP_LAST_PUNCTUATOR CPP_DOT_STAR
-#define CPP_LAST_CPP_OP CPP_LESS_EQ
-
-#define TTYPE_TABLE \
- OP(CPP_EQ = 0, "=") \
- OP(CPP_NOT, "!") \
- OP(CPP_GREATER, ">") /* compare */ \
- OP(CPP_LESS, "<") \
- OP(CPP_PLUS, "+") /* math */ \
- OP(CPP_MINUS, "-") \
- OP(CPP_MULT, "*") \
- OP(CPP_DIV, "/") \
- OP(CPP_MOD, "%") \
- OP(CPP_AND, "&") /* bit ops */ \
- OP(CPP_OR, "|") \
- OP(CPP_XOR, "^") \
- OP(CPP_RSHIFT, ">>") \
- OP(CPP_LSHIFT, "<<") \
- OP(CPP_MIN, "<?") /* extension */ \
- OP(CPP_MAX, ">?") \
-\
- OP(CPP_COMPL, "~") \
- OP(CPP_AND_AND, "&&") /* logical */ \
- OP(CPP_OR_OR, "||") \
- OP(CPP_QUERY, "?") \
- OP(CPP_COLON, ":") \
- OP(CPP_COMMA, ",") /* grouping */ \
- OP(CPP_OPEN_PAREN, "(") \
- OP(CPP_CLOSE_PAREN, ")") \
- TK(CPP_EOF, SPELL_NONE) \
- OP(CPP_EQ_EQ, "==") /* compare */ \
- OP(CPP_NOT_EQ, "!=") \
- OP(CPP_GREATER_EQ, ">=") \
- OP(CPP_LESS_EQ, "<=") \
-\
- /* These two are unary + / - in preprocessor expressions. */ \
- OP(CPP_PLUS_EQ, "+=") /* math */ \
- OP(CPP_MINUS_EQ, "-=") \
-\
- OP(CPP_MULT_EQ, "*=") \
- OP(CPP_DIV_EQ, "/=") \
- OP(CPP_MOD_EQ, "%=") \
- OP(CPP_AND_EQ, "&=") /* bit ops */ \
- OP(CPP_OR_EQ, "|=") \
- OP(CPP_XOR_EQ, "^=") \
- OP(CPP_RSHIFT_EQ, ">>=") \
- OP(CPP_LSHIFT_EQ, "<<=") \
- OP(CPP_MIN_EQ, "<?=") /* extension */ \
- OP(CPP_MAX_EQ, ">?=") \
- /* Digraphs together, beginning with CPP_FIRST_DIGRAPH. */ \
- OP(CPP_HASH, "#") /* digraphs */ \
- OP(CPP_PASTE, "##") \
- OP(CPP_OPEN_SQUARE, "[") \
- OP(CPP_CLOSE_SQUARE, "]") \
- OP(CPP_OPEN_BRACE, "{") \
- OP(CPP_CLOSE_BRACE, "}") \
- /* The remainder of the punctuation. Order is not significant. */ \
- OP(CPP_SEMICOLON, ";") /* structure */ \
- OP(CPP_ELLIPSIS, "...") \
- OP(CPP_PLUS_PLUS, "++") /* increment */ \
- OP(CPP_MINUS_MINUS, "--") \
- OP(CPP_DEREF, "->") /* accessors */ \
- OP(CPP_DOT, ".") \
- OP(CPP_SCOPE, "::") \
- OP(CPP_DEREF_STAR, "->*") \
- OP(CPP_DOT_STAR, ".*") \
- OP(CPP_ATSIGN, "@") /* used in Objective-C */ \
-\
- TK(CPP_NAME, SPELL_IDENT) /* word */ \
- TK(CPP_AT_NAME, SPELL_IDENT) /* @word - Objective-C */ \
- TK(CPP_NUMBER, SPELL_LITERAL) /* 34_be+ta */ \
-\
- TK(CPP_CHAR, SPELL_LITERAL) /* 'char' */ \
- TK(CPP_WCHAR, SPELL_LITERAL) /* L'char' */ \
- TK(CPP_OTHER, SPELL_LITERAL) /* stray punctuation */ \
-\
- 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_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_LITERAL) /* _asm ... _endasm ; */
-#define OP(e, s) e,
-#define TK(e, s) e,
-enum cpp_ttype
-{
- TTYPE_TABLE
- N_TTYPES
-};
-#undef OP
-#undef TK
-
-/* C language kind, used when calling cpp_reader_init. */
-enum c_lang {CLK_GNUC89 = 0, CLK_GNUC99, CLK_STDC89, CLK_STDC94, CLK_STDC99,
- CLK_GNUCXX, CLK_CXX98, CLK_ASM};
-
-/* Payload of a NUMBER, STRING, CHAR or COMMENT token. */
-struct cpp_string
-{
- unsigned int len;
- const unsigned char *text;
-};
-
-/* Flags for the cpp_token structure. */
-#define PREV_WHITE (1 << 0) /* If whitespace before this token. */
-#define DIGRAPH (1 << 1) /* If it was a digraph. */
-#define STRINGIFY_ARG (1 << 2) /* If macro argument to be stringified. */
-#define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator. */
-#define NAMED_OP (1 << 4) /* C++ named operators. */
-#define NO_EXPAND (1 << 5) /* Do not macro-expand this token. */
-#define BOL (1 << 6) /* Token at beginning of line. */
-
-/* A preprocessing token. This has been carefully packed and should
- occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */
-struct cpp_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 */
-
- union
- {
- cpp_hashnode *node; /* An identifier. */
- 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. */
- } 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.
- 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
-# 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;
-
-/* This structure is nested inside struct cpp_reader, and
- carries all the options visible to the command line. */
-struct cpp_options
-{
- /* Characters between tab stops. */
- unsigned int tabstop;
-
- /* The language we're preprocessing. */
- enum c_lang lang;
-
- /* Nonzero means use extra default include directories for C++. */
- unsigned char cplusplus;
-
- /* Nonzero means handle cplusplus style comments. */
- unsigned char cplusplus_comments;
-
- /* Nonzero means define __OBJC__, treat @ as a special token, and
- use the OBJC[PLUS]_INCLUDE_PATH environment variable. */
- unsigned char objc;
-
- /* Nonzero means don't copy comments into the output file. */
- unsigned char discard_comments;
-
- /* Nonzero means don't copy comments into the output file during
- macro expansion. */
- unsigned char discard_comments_in_macro_exp;
-
- /* Nonzero means process the ISO trigraph sequences. */
- unsigned char trigraphs;
-
- /* Nonzero means process the ISO digraph sequences. */
- unsigned char digraphs;
-
- /* Nonzero means to allow hexadecimal floats and LL suffixes. */
- unsigned char extended_numbers;
-
- /* Nonzero means print names of header files (-H). */
- unsigned char print_include_names;
-
- /* Nonzero means cpp_pedwarn causes a hard error. */
- unsigned char pedantic_errors;
-
- /* 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;
-
- /* Nonzero means don't print error messages. Has no option to
- select it, but can be set by a user of cpplib (e.g. fix-header). */
- unsigned char inhibit_errors;
-
- /* Nonzero means warn if slash-star appears in a comment. */
- unsigned char warn_comments;
-
- /* Nonzero means warn if there are any trigraphs. */
- unsigned char warn_trigraphs;
-
- /* Nonzero means warn about multicharacter charconsts. */
- unsigned char warn_multichar;
-
- /* Nonzero means warn about various incompatibilities with
- traditional C. */
- unsigned char warn_traditional;
-
- /* Nonzero means warn about long long numeric constants. */
- unsigned char warn_long_long;
-
- /* Nonzero means warn about text after an #endif (or #else). */
- unsigned char warn_endif_labels;
-
- /* Nonzero means warn about implicit sign changes owing to integer
- promotions. */
- unsigned char warn_num_sign_change;
-
- /* Nonzero means turn warnings into errors. */
- unsigned char warnings_are_errors;
-
- /* Nonzero means we should look for header.gcc files that remap file
- names. */
- unsigned char remap;
-
- /* 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;
-
- /* Nonzero means warn of unused macros from the main file. */
- unsigned char warn_unused_macros;
-
- /* Nonzero for the 1999 C Standard, including corrigenda and amendments. */
- unsigned char c99;
-
- /* Nonzero if we are conforming to a specific C or C++ standard. */
- unsigned char std;
-
- /* Nonzero means give all the error messages the ANSI standard requires. */
- unsigned char pedantic;
-
- /* Nonzero means we're looking at already preprocessed code, so don't
- bother trying to do macro expansion and whatnot. */
- unsigned char preprocessed;
-
- /* Print column number in error messages. */
- unsigned char show_column;
-
- /* Nonzero means handle C++ alternate operator names. */
- unsigned char operator_names;
-
- /* True for traditional preprocessing. */
- unsigned char traditional;
-
- /* 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)
- */
- unsigned char allow_naked_hash;
-
- /* SDCC _asm specific
- switch _asm block preprocessing on / off */
- unsigned char preproc_asm;
-
- /* SDCC specific
- object file exetnsion */
- const char *obj_ext;
-
- /* SDCC specific
- pedantic_parse_number */
- unsigned char pedantic_parse_number;
-
- /* Dependency generation. */
- struct
- {
- /* Style of header dependencies to generate. */
- enum {DEPS_NONE = 0, DEPS_USER, DEPS_SYSTEM } style;
-
- /* Assume missing files are generated files. */
- bool missing_files;
-
- /* Generate phony targets for each dependency apart from the first
- one. */
- bool phony_targets;
-
- /* If true, no dependency is generated on the main file. */
- bool ignore_main_file;
- } deps;
-
- /* Target-specific features set by the front end or client. */
-
- /* Precision for target CPP arithmetic, target characters, target
- ints and target wide characters, respectively. */
- size_t precision, char_precision, int_precision, wchar_precision;
-
- /* 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 to cpplib client. */
-struct cpp_callbacks
-{
- /* Called when a new line of preprocessed output is started. */
- 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. */
-extern const char *progname;
-
-/* The structure of a node in the hash table. The hash table has
- 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. 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
- diagnostic may be required for this node. Currently this only
- applies to __VA_ARGS__ and poisoned identifiers. */
-
-/* Hash node flags. */
-#define NODE_OPERATOR (1 << 0) /* C++ named operator. */
-#define NODE_POISONED (1 << 1) /* Poisoned identifier. */
-#define NODE_BUILTIN (1 << 2) /* Builtin macro. */
-#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
-{
- NT_VOID = 0, /* No definition yet. */
- NT_MACRO, /* A macro of some form. */
- NT_ASSERTION /* Predicate for #assert. */
-};
-
-/* Different flavors of builtin macro. _Pragma is an operator, but we
- handle it with the builtin code for efficiency reasons. */
-enum builtin_type
-{
- BT_SPECLINE = 0, /* `__LINE__' */
- BT_DATE, /* `__DATE__' */
- BT_FILE, /* `__FILE__' */
- BT_BASE_FILE, /* `__BASE_FILE__' */
- BT_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
- BT_TIME, /* `__TIME__' */
- BT_STDC, /* `__STDC__' */
- BT_PRAGMA /* `_Pragma' operator */
-};
-
-#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE))
-#define HT_NODE(NODE) ((ht_identifier *) (NODE))
-#define NODE_LEN(NODE) HT_LEN (&(NODE)->ident)
-#define NODE_NAME(NODE) HT_STR (&(NODE)->ident)
-
-/* 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 GTY(())
-{
- struct ht_identifier ident;
- 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 _cpp_hashnode_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.
-
- 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 (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 (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 (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. */
-extern const char *cpp_read_main_file (cpp_reader *, const char *);
-
-/* 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 *);
-
-/* 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 (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 (cpp_reader *);
-
-/* Error count. */
-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 (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 (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 (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. */
-typedef unsigned HOST_WIDE_INT cpp_num_part;
-typedef struct cpp_num cpp_num;
-struct cpp_num
-{
- cpp_num_part high;
- cpp_num_part low;
- bool unsignedp; /* True if value should be treated as unsigned. */
- bool overflow; /* True if the most recent calculation overflowed. */
-};
-
-/* cpplib provides two interfaces for interpretation of preprocessing
- numbers.
-
- cpp_classify_number categorizes numeric constants according to
- their field (integer, floating point, or invalid), radix (decimal,
- octal, hexadecimal), and type suffixes. */
-
-#define CPP_N_CATEGORY 0x000F
-#define CPP_N_INVALID 0x0000
-#define CPP_N_INTEGER 0x0001
-#define CPP_N_FLOATING 0x0002
-
-#define CPP_N_WIDTH 0x00F0
-#define CPP_N_SMALL 0x0010 /* int, float. */
-#define CPP_N_MEDIUM 0x0020 /* long, double. */
-#define CPP_N_LARGE 0x0040 /* long long, long double. */
-
-#define CPP_N_RADIX 0x0F00
-#define CPP_N_DECIMAL 0x0100
-#define CPP_N_HEX 0x0200
-#define CPP_N_OCTAL 0x0400
-
-#define CPP_N_UNSIGNED 0x1000 /* Properties. */
-#define CPP_N_IMAGINARY 0x2000
-
-/* Classify a CPP_NUMBER token. The return value is a combination of
- the flags from the above sets. */
-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 (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 (cpp_num, size_t);
-
-/* 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 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 CPP_DL_PEDWARN 0x02
-/* An error. */
-#define CPP_DL_ERROR 0x03
-/* An internal consistency check failed. Prints "internal error: ",
- otherwise the same as CPP_DL_ERROR. */
-#define CPP_DL_ICE 0x04
-/* Extracts a diagnostic level from an int. */
-#define CPP_DL_EXTRACT(l) (l & 0xf)
-/* Nonzero if a diagnostic level is one of the warnings. */
-#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
- as the name of the function in order to work properly. Only the
- string argument gets a name in an effort to keep the lines from
- getting ridiculously oversized. */
-
-/* Output a diagnostic of some kind. */
-extern void cpp_error (cpp_reader *, int, const char *msgid, ...)
- ATTRIBUTE_PRINTF_3;
-
-/* Output a diagnostic with "MSGID: " preceding the
- error string of errno. No location is printed. */
-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 (cpp_reader *, int, fileline, unsigned,
- const char *msgid, ...) ATTRIBUTE_PRINTF_5;
-
-/* In cpplex.c */
-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 (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 (cpp_reader *, const unsigned char *,
- unsigned int);
-
-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 (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 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
-}
-#endif
-
-#endif /* ! GCC_CPPLIB_H */
+++ /dev/null
-/* Part of CPP library. (Macro and #define handling.)
- Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
- 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
-
-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"
-
-typedef struct macro_arg macro_arg;
-struct macro_arg
-{
- const cpp_token **first; /* First token in unexpanded argument. */
- const cpp_token **expanded; /* Macro-expanded argument. */
- const cpp_token *stringified; /* Stringified argument. */
- unsigned int count; /* # of tokens in argument. */
- unsigned int expanded_count; /* # of tokens in expanded argument. */
-};
-
-/* Macro expansion. */
-
-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 (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 (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
- && 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));
- }
-
- return 1;
-}
-
-/* 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 (cpp_reader *pfile, unsigned char *text, unsigned int len)
-{
- cpp_token *token = _cpp_temp_token (pfile);
-
- text[len] = '\0';
- token->type = CPP_STRING;
- token->val.str.len = len;
- token->val.str.text = text;
- token->flags = 0;
- return token;
-}
-
-static const char * const monthnames[] =
-{
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-/* Handle builtin macros like __FILE__, and push the resulting token
- on the context stack. Also handles _Pragma, for which no new token
- 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 (cpp_reader *pfile, cpp_hashnode *node)
-{
- const uchar *result = NULL;
- unsigned int number = 1;
-
- switch (node->value.builtin)
- {
- default:
- cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"",
- NODE_NAME (node));
- break;
-
- case BT_FILE:
- case BT_BASE_FILE:
- {
- unsigned int len;
- const char *name;
- uchar *buf;
- const struct line_map *map = pfile->map;
-
- if (node->value.builtin == BT_BASE_FILE)
- while (! MAIN_FILE_P (map))
- map = INCLUDED_FROM (&pfile->line_maps, map);
-
- name = map->to_file;
- len = strlen (name);
- buf = _cpp_unaligned_alloc (pfile, len * 4 + 3);
- result = buf;
- *buf = '"';
- buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len);
- *buf++ = '"';
- *buf = '\0';
- }
- break;
-
- case BT_INCLUDE_LEVEL:
- /* The line map depth counts the primary source as level 1, but
- historically __INCLUDE_DEPTH__ has called the primary source
- level 0. */
- number = pfile->line_maps.depth - 1;
- break;
-
- case BT_SPECLINE:
- /* If __LINE__ is embedded in a macro, it must expand to the
- line of the macro's invocation, not its definition.
- Otherwise things like assert() will not work properly. */
- if (CPP_OPTION (pfile, traditional))
- number = pfile->line;
- else
- number = pfile->cur_token[-1].line;
- number = SOURCE_LINE (pfile->map, number);
- break;
-
- /* __STDC__ has the value 1 under normal circumstances.
- However, if (a) we are in a system header, (b) the option
- stdc_0_in_system_headers is true (set by target config), and
- (c) we are not in strictly conforming mode, then it has the
- value 0. */
- case BT_STDC:
- {
- if (CPP_IN_SYSTEM_HEADER (pfile)
- && CPP_OPTION (pfile, stdc_0_in_system_headers)
- && !CPP_OPTION (pfile,std))
- number = 0;
- else
- number = 1;
- }
- break;
-
- case BT_DATE:
- case BT_TIME:
- if (pfile->date == NULL)
- {
- /* Allocate __DATE__ and __TIME__ strings from permanent
- storage. We only do this once, and don't generate them
- at init time, because time() and localtime() are very
- slow on some systems. */
- time_t tt;
- struct tm *tb = NULL;
-
- /* (time_t) -1 is a legitimate value for "number of seconds
- since the Epoch", so we have to do a little dance to
- distinguish that from a genuine error. */
- errno = 0;
- tt = time(NULL);
- if (tt != (time_t)-1 || errno == 0)
- tb = localtime (&tt);
-
- if (tb)
- {
- 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);
-
- pfile->time = _cpp_unaligned_alloc (pfile,
- sizeof ("\"12:34:56\""));
- sprintf ((char *) pfile->time, "\"%02d:%02d:%02d\"",
- tb->tm_hour, tb->tm_min, tb->tm_sec);
- }
- else
- {
- cpp_errno (pfile, CPP_DL_WARNING,
- "could not determine date and time");
-
- pfile->date = U"\"??? ?? ????\"";
- pfile->time = U"\"??:??:??\"";
- }
- }
-
- if (node->value.builtin == BT_DATE)
- result = pfile->date;
- else
- result = pfile->time;
- break;
- }
-
- if (result == NULL)
- {
- /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */
- result = _cpp_unaligned_alloc (pfile, 21);
- sprintf ((char *) result, "%u", number);
- }
-
- return result;
-}
-
-/* Convert builtin macros like __FILE__ to a token and push it on the
- context stack. Also handles _Pragma, for which no new token is
- created. Returns 1 if it generates a new token context, 0 to
- return the token to the caller. */
-static int
-builtin_macro (cpp_reader *pfile, cpp_hashnode *node)
-{
- const uchar *buf;
- size_t len;
- char *nbuf;
-
- if (node->value.builtin == BT_PRAGMA)
- {
- /* Don't interpret _Pragma within directives. The standard is
- not clear on this, but to me this makes most sense. */
- if (pfile->state.in_directive)
- return 0;
-
- _cpp_do__Pragma (pfile);
- return 1;
- }
-
- 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, (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, CPP_DL_ICE, "invalid built-in macro \"%s\"",
- NODE_NAME (node));
- _cpp_pop_buffer (pfile);
-
- return 1;
-}
-
-/* Copies SRC, of length LEN, to DEST, adding backslashes before all
- backslashes and double quotes. Non-printable characters are
- converted to octal. DEST must be of sufficient size. Returns
- a pointer to the end of the string. */
-uchar *
-cpp_quote_string (uchar *dest, const uchar *src, unsigned int len)
-{
- while (len--)
- {
- uchar c = *src++;
-
- if (c == '\\' || c == '"')
- {
- *dest++ = '\\';
- *dest++ = c;
- }
- else
- {
- if (ISPRINT (c))
- *dest++ = c;
- else
- {
- sprintf ((char *) dest, "\\%03o", c);
- dest += 4;
- }
- }
- }
-
- return dest;
-}
-
-/* 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 (cpp_reader *pfile, macro_arg *arg)
-{
- 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++)
- {
- const cpp_token *token = arg->first[i];
-
- if (token->type == CPP_PADDING)
- {
- if (source == NULL)
- source = token->val.source;
- continue;
- }
-
- escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING
- || token->type == CPP_CHAR || token->type == CPP_WCHAR);
-
- /* Room for each char being written in octal, initial space and
- final quote and NUL. */
- len = cpp_token_len (token);
- if (escape_it)
- len *= 4;
- len += 3;
-
- if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len)
- {
- size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff);
- _cpp_extend_buff (pfile, &pfile->u_buff, len);
- dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
- }
-
- /* Leading white space? */
- if (dest - 1 != BUFF_FRONT (pfile->u_buff))
- {
- if (source == NULL)
- source = token;
- if (source->flags & PREV_WHITE)
- *dest++ = ' ';
- }
- source = NULL;
-
- if (escape_it)
- {
- _cpp_buff *buff = _cpp_get_buff (pfile, len);
- unsigned char *buf = BUFF_FRONT (buff);
- len = cpp_spell_token (pfile, token, buf) - buf;
- dest = cpp_quote_string (dest, buf, len);
- _cpp_release_buff (pfile, buff);
- }
- else
- dest = cpp_spell_token (pfile, token, dest);
-
- if (token->type == CPP_OTHER && token->val.str.text[0] == '\\')
- backslash_count++;
- else
- backslash_count = 0;
- }
-
- /* Ignore the final \ of invalid string literals. */
- if (backslash_count & 1)
- {
- cpp_error (pfile, CPP_DL_WARNING,
- "invalid string literal, ignoring final '\\'");
- dest--;
- }
-
- /* Commit the memory, including NUL, and return the token. */
- *dest++ = '"';
- len = dest - BUFF_FRONT (pfile->u_buff);
- BUFF_FRONT (pfile->u_buff) = dest + 1;
- return new_string_token (pfile, dest - len, len);
-}
-
-/* Try to paste two tokens. On success, return nonzero. In any
- 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 (cpp_reader *pfile, const cpp_token **plhs, const cpp_token *rhs)
-{
- unsigned char *buf, *end;
- const cpp_token *lhs;
- unsigned int len;
- bool valid;
-
- lhs = *plhs;
- len = cpp_token_len (lhs) + cpp_token_len (rhs) + 1;
- buf = alloca (len);
- end = cpp_spell_token (pfile, lhs, buf);
-
- /* Avoid comment headers, since they are still processed in stage 3.
- It is simpler to insert a space here, rather than modifying the
- lexer to ignore comments in some circumstances. Simply returning
- false doesn't work, since we want to clear the PASTE_LEFT flag. */
- if (lhs->type == CPP_DIV && rhs->type != CPP_EQ)
- *end++ = ' ';
- end = cpp_spell_token (pfile, rhs, end);
- *end = '\n';
-
- 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);
- *plhs = _cpp_lex_direct (pfile);
- valid = pfile->buffer->cur == pfile->buffer->rlimit;
- _cpp_pop_buffer (pfile);
-
- return valid;
-}
-
-/* Handles an arbitrarily long sequence of ## operators, with initial
- operand LHS. This implementation is left-associative,
- non-recursive, and finishes a paste before handling succeeding
- ones. If a paste fails, we back up to the RHS of the failing ##
- operator before pushing the context containing the result of prior
- successful pastes, with the effect that the RHS appears in the
- output stream after the pasted LHS normally. */
-static void
-paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs)
-{
- const cpp_token *rhs;
- cpp_context *context = pfile->context;
-
- do
- {
- /* Take the token directly from the current context. We can do
- this, because we are in the replacement list of either an
- object-like macro, or a function-like macro with arguments
- inserted. In either case, the constraints to #define
- guarantee we have at least one more token. */
- if (context->direct_p)
- rhs = FIRST (context).token++;
- else
- rhs = *FIRST (context).ptoken++;
-
- if (rhs->type == CPP_PADDING)
- abort ();
-
- if (!paste_tokens (pfile, &lhs, rhs))
- {
- _cpp_backup_tokens (pfile, 1);
-
- /* Mandatory error for all apart from assembler. */
- if (CPP_OPTION (pfile, lang) != CLK_ASM)
- 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));
- break;
- }
- }
- while (rhs->flags & PASTE_LEFT);
-
- /* Put the resulting token in its own context. */
- push_token_context (pfile, NULL, lhs, 1);
-}
-
-/* Returns TRUE if the number of arguments ARGC supplied in an
- invocation of the MACRO referenced by NODE is valid. An empty
- invocation to a macro with no parameters should pass ARGC as zero.
-
- Note that MACRO cannot necessarily be deduced from NODE, in case
- NODE was redefined whilst collecting arguments. */
-bool
-_cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node, unsigned int argc)
-{
- if (argc == macro->paramc)
- return true;
-
- if (argc < macro->paramc)
- {
- /* As an extension, a rest argument is allowed to not appear in
- the invocation at all.
- e.g. #define debug(format, args...) something
- debug("string");
-
- This is exactly the same as if there had been an empty rest
- argument - debug("string", ). */
-
- if (argc + 1 == macro->paramc && macro->variadic)
- {
- if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
- cpp_error (pfile, CPP_DL_PEDWARN,
- "ISO C99 requires rest arguments to be used");
- return true;
- }
-
- 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, CPP_DL_ERROR,
- "macro \"%s\" passed %u arguments, but takes just %u",
- NODE_NAME (node), argc, macro->paramc);
-
- return false;
-}
-
-/* Reads and returns the arguments to a function-like macro
- invocation. Assumes the opening parenthesis has been processed.
- If there is an error, emits an appropriate diagnostic and returns
- NULL. Each argument is terminated by a CPP_EOF token, for the
- future benefit of expand_arg(). */
-static _cpp_buff *
-collect_args (cpp_reader *pfile, const cpp_hashnode *node)
-{
- _cpp_buff *buff, *base_buff;
- cpp_macro *macro;
- macro_arg *args, *arg;
- const cpp_token *token;
- unsigned int argc;
-
- macro = node->value.macro;
- if (macro->paramc)
- argc = macro->paramc;
- else
- argc = 1;
- buff = _cpp_get_buff (pfile, argc * (50 * sizeof (cpp_token *)
- + sizeof (macro_arg)));
- base_buff = buff;
- args = (macro_arg *) buff->base;
- memset (args, 0, argc * sizeof (macro_arg));
- buff->cur = (unsigned char *) &args[argc];
- arg = args, argc = 0;
-
- /* Collect the tokens making up each argument. We don't yet know
- how many arguments have been supplied, whether too many or too
- few. Hence the slightly bizarre usage of "argc" and "arg". */
- do
- {
- unsigned int paren_depth = 0;
- unsigned int ntokens = 0;
-
- argc++;
- arg->first = (const cpp_token **) buff->cur;
-
- for (;;)
- {
- /* Require space for 2 new tokens (including a CPP_EOF). */
- if ((unsigned char *) &arg->first[ntokens + 2] > buff->limit)
- {
- buff = _cpp_append_extend_buff (pfile, buff,
- 1000 * sizeof (cpp_token *));
- arg->first = (const cpp_token **) buff->cur;
- }
-
- token = cpp_get_token (pfile);
-
- if (token->type == CPP_PADDING)
- {
- /* Drop leading padding. */
- if (ntokens == 0)
- continue;
- }
- else if (token->type == CPP_OPEN_PAREN)
- paren_depth++;
- else if (token->type == CPP_CLOSE_PAREN)
- {
- if (paren_depth-- == 0)
- break;
- }
- else if (token->type == CPP_COMMA)
- {
- /* A comma does not terminate an argument within
- parentheses or as part of a variable argument. */
- if (paren_depth == 0
- && ! (macro->variadic && argc == macro->paramc))
- break;
- }
- else if (token->type == CPP_EOF
- || (token->type == CPP_HASH && token->flags & BOL))
- break;
-
- arg->first[ntokens++] = token;
- }
-
- /* Drop trailing padding. */
- while (ntokens > 0 && arg->first[ntokens - 1]->type == CPP_PADDING)
- ntokens--;
-
- arg->count = ntokens;
- arg->first[ntokens] = &pfile->eof;
-
- /* Terminate the argument. Excess arguments loop back and
- overwrite the final legitimate argument, before failing. */
- if (argc <= macro->paramc)
- {
- buff->cur = (unsigned char *) &arg->first[ntokens + 1];
- if (argc != macro->paramc)
- arg++;
- }
- }
- while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF);
-
- if (token->type == CPP_EOF)
- {
- /* We still need the CPP_EOF to end directives, and to end
- pre-expansion of a macro argument. Step back is not
- unconditional, since we don't want to return a CPP_EOF to our
- 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, CPP_DL_ERROR,
- "unterminated argument list invoking macro \"%s\"",
- NODE_NAME (node));
- }
- else
- {
- /* A single empty argument is counted as no argument. */
- if (argc == 1 && macro->paramc == 0 && args[0].count == 0)
- argc = 0;
- if (_cpp_arguments_ok (pfile, macro, node, argc))
- {
- /* GCC has special semantics for , ## b where b is a varargs
- parameter: we remove the comma if b was omitted entirely.
- If b was merely an empty argument, the comma is retained.
- If the macro takes just one (varargs) parameter, then we
- retain the comma only if we are standards conforming.
-
- If FIRST is NULL replace_args () swallows the comma. */
- if (macro->variadic && (argc < macro->paramc
- || (argc == 1 && args[0].count == 0
- && !CPP_OPTION (pfile, std))))
- args[macro->paramc - 1].first = NULL;
- return base_buff;
- }
- }
-
- /* An error occurred. */
- _cpp_release_buff (pfile, base_buff);
- return NULL;
-}
-
-/* Search for an opening parenthesis to the macro of NODE, in such a
- way that, if none is found, we don't lose the information in any
- intervening padding tokens. If we find the parenthesis, collect
- the arguments and return the buffer containing them. */
-static _cpp_buff *
-funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node)
-{
- const cpp_token *token, *padding = NULL;
-
- for (;;)
- {
- token = cpp_get_token (pfile);
- if (token->type != CPP_PADDING)
- break;
- if (padding == NULL
- || (!(padding->flags & PREV_WHITE) && token->val.source == NULL))
- padding = token;
- }
-
- if (token->type == CPP_OPEN_PAREN)
- {
- pfile->state.parsing_args = 2;
- return collect_args (pfile, node);
- }
-
- /* CPP_EOF can be the end of macro arguments, or the end of the
- file. We mustn't back up over the latter. Ugh. */
- if (token->type != CPP_EOF || token == &pfile->eof)
- {
- /* Back up. We may have skipped padding, in which case backing
- up more than one token when expanding macros is in general
- too difficult. We re-insert it in its own context. */
- _cpp_backup_tokens (pfile, 1);
- if (padding)
- push_token_context (pfile, NULL, padding, 1);
- }
-
- return NULL;
-}
-
-/* Push the context of a macro with hash entry NODE onto the context
- stack. If we can successfully expand the macro, we push a context
- 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 (cpp_reader *pfile, cpp_hashnode *node)
-{
- /* The presence of a macro invalidates a file's controlling macro. */
- pfile->mi_valid = false;
-
- pfile->state.angled_headers = false;
-
- /* Handle standard macros. */
- if (! (node->flags & NODE_BUILTIN))
- {
- cpp_macro *macro = node->value.macro;
-
- if (macro->fun_like)
- {
- _cpp_buff *buff;
-
- pfile->state.prevent_expansion++;
- pfile->keep_tokens++;
- pfile->state.parsing_args = 1;
- buff = funlike_invocation_p (pfile, node);
- pfile->state.parsing_args = 0;
- pfile->keep_tokens--;
- pfile->state.prevent_expansion--;
-
- if (buff == NULL)
- {
- if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
- cpp_error (pfile, CPP_DL_WARNING,
- "function-like macro \"%s\" must be used with arguments in traditional C",
- NODE_NAME (node));
-
- return 0;
- }
-
- if (macro->paramc > 0)
- replace_args (pfile, node, macro, (macro_arg *) buff->base);
- _cpp_release_buff (pfile, buff);
- }
-
- /* Disable the macro within its expansion. */
- node->flags |= NODE_DISABLED;
-
- macro->used = 1;
-
- if (macro->paramc == 0)
- push_token_context (pfile, node, macro->exp.tokens, macro->count);
-
- return 1;
- }
-
- /* Handle built-in macros and the _Pragma operator. */
- return builtin_macro (pfile, node);
-}
-
-/* Replace the parameters in a function-like macro of NODE with the
- actual ARGS, and place the result in a newly pushed token context.
- Expand each argument before replacing, unless it is operated upon
- by the # or ## operators. */
-static void
-replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg *args)
-{
- unsigned int i, total;
- const cpp_token *src, *limit;
- const cpp_token **dest, **first;
- macro_arg *arg;
- _cpp_buff *buff;
-
- /* First, fully macro-expand arguments, calculating the number of
- tokens in the final expansion as we go. The ordering of the if
- statements below is subtle; we must handle stringification before
- pasting. */
- total = macro->count;
- limit = macro->exp.tokens + macro->count;
-
- for (src = macro->exp.tokens; src < limit; src++)
- if (src->type == CPP_MACRO_ARG)
- {
- /* Leading and trailing padding tokens. */
- total += 2;
-
- /* We have an argument. If it is not being stringified or
- pasted it is macro-replaced before insertion. */
- arg = &args[src->val.arg_no - 1];
-
- if (src->flags & STRINGIFY_ARG)
- {
- if (!arg->stringified)
- arg->stringified = stringify_arg (pfile, arg);
- }
- else if ((src->flags & PASTE_LEFT)
- || (src > macro->exp.tokens && (src[-1].flags & PASTE_LEFT)))
- total += arg->count - 1;
- else
- {
- if (!arg->expanded)
- expand_arg (pfile, arg);
- total += arg->expanded_count - 1;
- }
- }
-
- /* Now allocate space for the expansion, copy the tokens and replace
- the arguments. */
- buff = _cpp_get_buff (pfile, total * sizeof (cpp_token *));
- first = (const cpp_token **) buff->base;
- dest = first;
-
- for (src = macro->exp.tokens; src < limit; src++)
- {
- unsigned int count;
- const cpp_token **from, **paste_flag;
-
- if (src->type != CPP_MACRO_ARG)
- {
- *dest++ = src;
- continue;
- }
-
- paste_flag = 0;
- arg = &args[src->val.arg_no - 1];
- if (src->flags & STRINGIFY_ARG)
- count = 1, from = &arg->stringified;
- else if (src->flags & PASTE_LEFT)
- count = arg->count, from = arg->first;
- else if (src != macro->exp.tokens && (src[-1].flags & PASTE_LEFT))
- {
- count = arg->count, from = arg->first;
- if (dest != first)
- {
- if (dest[-1]->type == CPP_COMMA
- && macro->variadic
- && src->val.arg_no == macro->paramc)
- {
- /* Swallow a pasted comma if from == NULL, otherwise
- drop the paste flag. */
- if (from == NULL)
- dest--;
- else
- paste_flag = dest - 1;
- }
- /* Remove the paste flag if the RHS is a placemarker. */
- else if (count == 0)
- paste_flag = dest - 1;
- }
- }
- else
- count = arg->expanded_count, from = arg->expanded;
-
- /* Padding on the left of an argument (unless RHS of ##). */
- if ((!pfile->state.in_directive || pfile->state.directive_wants_padding)
- && src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT))
- *dest++ = padding_token (pfile, src);
-
- if (count)
- {
- memcpy (dest, from, count * sizeof (cpp_token *));
- dest += count;
-
- /* With a non-empty argument on the LHS of ##, the last
- token should be flagged PASTE_LEFT. */
- if (src->flags & PASTE_LEFT)
- paste_flag = dest - 1;
- }
-
- /* Avoid paste on RHS (even case count == 0). */
- if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT))
- *dest++ = &pfile->avoid_paste;
-
- /* Add a new paste flag, or remove an unwanted one. */
- if (paste_flag)
- {
- cpp_token *token = _cpp_temp_token (pfile);
- token->type = (*paste_flag)->type;
- token->val.str = (*paste_flag)->val.str;
- if (src->flags & PASTE_LEFT)
- token->flags = (*paste_flag)->flags | PASTE_LEFT;
- else
- token->flags = (*paste_flag)->flags & ~PASTE_LEFT;
- *paste_flag = token;
- }
- }
-
- /* Free the expanded arguments. */
- for (i = 0; i < macro->paramc; i++)
- if (args[i].expanded)
- free (args[i].expanded);
-
- push_ptoken_context (pfile, node, buff, first, dest - first);
-}
-
-/* Return a special padding token, with padding inherited from SOURCE. */
-static const cpp_token *
-padding_token (cpp_reader *pfile, const cpp_token *source)
-{
- cpp_token *result = _cpp_temp_token (pfile);
-
- result->type = CPP_PADDING;
- result->val.source = source;
- result->flags = 0;
- return result;
-}
-
-/* Get a new uninitialized context. Create a new one if we cannot
- re-use an old one. */
-static cpp_context *
-next_context (cpp_reader *pfile)
-{
- cpp_context *result = pfile->context->next;
-
- if (result == 0)
- {
- result = xnew (cpp_context);
- result->prev = pfile->context;
- result->next = 0;
- pfile->context->next = result;
- }
-
- pfile->context = result;
- return result;
-}
-
-/* Push a list of pointers to tokens. */
-static void
-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);
-
- context->direct_p = false;
- context->macro = macro;
- context->buff = buff;
- FIRST (context).ptoken = first;
- LAST (context).ptoken = first + count;
-}
-
-/* Push a list of tokens. */
-static void
-push_token_context (cpp_reader *pfile, cpp_hashnode *macro,
- const cpp_token *first, unsigned int count)
-{
- cpp_context *context = next_context (pfile);
-
- context->direct_p = true;
- context->macro = macro;
- context->buff = NULL;
- FIRST (context).token = first;
- LAST (context).token = first + count;
-}
-
-/* Push a traditional macro's replacement text. */
-void
-_cpp_push_text_context (cpp_reader *pfile, cpp_hashnode *macro,
- const uchar *start, size_t len)
-{
- cpp_context *context = next_context (pfile);
-
- context->direct_p = true;
- context->macro = macro;
- context->buff = NULL;
- CUR (context) = start;
- RLIMIT (context) = start + len;
- macro->flags |= NODE_DISABLED;
-}
-
-/* Expand an argument ARG before replacing parameters in a
- function-like macro. This works by pushing a context with the
- argument's tokens, and then expanding that into a temporary buffer
- as if it were a normal part of the token stream. collect_args()
- 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 (cpp_reader *pfile, macro_arg *arg)
-{
- unsigned int capacity;
- bool saved_warn_trad;
-
- if (arg->count == 0)
- return;
-
- /* Don't warn about funlike macros when pre-expanding. */
- saved_warn_trad = CPP_WTRADITIONAL (pfile);
- CPP_WTRADITIONAL (pfile) = 0;
-
- /* Loop, reading in the arguments. */
- capacity = 256;
- arg->expanded = xmalloc (capacity * sizeof (cpp_token *));
-
- push_ptoken_context (pfile, NULL, NULL, arg->first, arg->count + 1);
- for (;;)
- {
- const cpp_token *token;
-
- if (arg->expanded_count + 1 >= capacity)
- {
- capacity *= 2;
- arg->expanded = xrealloc (arg->expanded,
- capacity * sizeof (cpp_token *));
- }
-
- token = cpp_get_token (pfile);
-
- if (token->type == CPP_EOF)
- break;
-
- arg->expanded[arg->expanded_count++] = token;
- }
-
- _cpp_pop_context (pfile);
-
- CPP_WTRADITIONAL (pfile) = saved_warn_trad;
-}
-
-/* Pop the current context off the stack, re-enabling the macro if the
- 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 (cpp_reader *pfile)
-{
- cpp_context *context = pfile->context;
-
- if (context->macro)
- context->macro->flags &= ~NODE_DISABLED;
-
- if (context->buff)
- _cpp_release_buff (pfile, context->buff);
-
- pfile->context = context->prev;
-}
-
-/* External routine to get a token. Also used nearly everywhere
- internally, except for places where we know we can safely call
- _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
- expansion, and after any intervening directives. External callers
- see CPP_EOF only at EOF. Internal callers also see it when meeting
- a directive inside a macro call, when at the end of a directive and
- state.in_directive is still 1, and at the end of argument
- pre-expansion. */
-const cpp_token *
-cpp_get_token (cpp_reader *pfile)
-{
- const cpp_token *result;
-
- for (;;)
- {
- cpp_hashnode *node;
- cpp_context *context = pfile->context;
-
- /* Context->prev == 0 <=> base context. */
- if (!context->prev)
- result = _cpp_lex_token (pfile);
- else if (FIRST (context).token != LAST (context).token)
- {
- if (context->direct_p)
- result = FIRST (context).token++;
- else
- result = *FIRST (context).ptoken++;
-
- if (result->flags & PASTE_LEFT)
- {
- paste_all_tokens (pfile, result);
- if (pfile->state.in_directive)
- continue;
- return padding_token (pfile, result);
- }
- }
- else
- {
- _cpp_pop_context (pfile);
- if (pfile->state.in_directive)
- continue;
- return &pfile->avoid_paste;
- }
-
- if (pfile->state.in_directive && result->type == CPP_COMMENT)
- continue;
-
- if (result->type != CPP_NAME)
- break;
-
- node = result->val.node;
-
- if (node->type != NT_MACRO || (result->flags & NO_EXPAND))
- break;
-
- if (!(node->flags & NODE_DISABLED))
- {
- if (!pfile->state.prevent_expansion
- && enter_macro_context (pfile, node))
- {
- if (pfile->state.in_directive)
- continue;
- return padding_token (pfile, result);
- }
- }
- else
- {
- /* Flag this token as always unexpandable. FIXME: move this
- to collect_args()?. */
- cpp_token *t = _cpp_temp_token (pfile);
- t->type = result->type;
- t->flags = result->flags | NO_EXPAND;
- t->val.str = result->val.str;
- result = t;
- }
-
- break;
- }
-
- return result;
-}
-
-/* Returns true if we're expanding an object-like macro that was
- defined in a system header. Just checks the macro at the top of
- the stack. Used for diagnostic suppression. */
-int
-cpp_sys_macro_p (cpp_reader *pfile)
-{
- cpp_hashnode *node = pfile->context->macro;
-
- return node && node->value.macro && node->value.macro->syshdr;
-}
-
-/* Read each token in, until end of the current file. Directives are
- transparently processed. */
-void
-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. */
- pfile->buffer->return_at_eof = true;
-
- if (CPP_OPTION (pfile, traditional))
- while (_cpp_read_logical_line_trad (pfile))
- ;
- else
- while (cpp_get_token (pfile)->type != CPP_EOF)
- ;
-}
-
-/* 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 (cpp_reader *pfile, unsigned int count)
-{
- if (pfile->context->prev == NULL)
- {
- pfile->lookaheads += count;
- while (count--)
- {
- pfile->cur_token--;
- if (pfile->cur_token == pfile->cur_run->base
- /* Possible with -fpreprocessed and no leading #line. */
- && pfile->cur_run->prev != NULL)
- {
- pfile->cur_run = pfile->cur_run->prev;
- pfile->cur_token = pfile->cur_run->limit;
- }
- }
- }
- else
- {
- if (count != 1)
- abort ();
- if (pfile->context->direct_p)
- FIRST (pfile->context).token--;
- else
- FIRST (pfile->context).ptoken--;
- }
-}
-
-/* #define directive parsing and handling. */
-
-/* Returns nonzero if a macro redefinition warning is required. */
-static bool
-warn_of_redefinition (cpp_reader *pfile, const cpp_hashnode *node,
- const cpp_macro *macro2)
-{
- const cpp_macro *macro1;
- unsigned int i;
-
- /* Some redefinitions need to be warned about regardless. */
- if (node->flags & NODE_WARN)
- return true;
-
- /* Redefinition of a macro is allowed if and only if the old and new
- definitions are the same. (6.10.3 paragraph 2). */
- macro1 = node->value.macro;
-
- /* Don't check count here as it can be different in valid
- traditional redefinitions with just whitespace differences. */
- if (macro1->paramc != macro2->paramc
- || macro1->fun_like != macro2->fun_like
- || macro1->variadic != macro2->variadic)
- return true;
-
- /* Check parameter spellings. */
- for (i = 0; i < macro1->paramc; i++)
- if (macro1->params[i] != macro2->params[i])
- return true;
-
- /* Check the replacement text or tokens. */
- if (CPP_OPTION (pfile, traditional))
- return _cpp_expansions_different_trad (macro1, macro2);
-
- if (macro1->count != macro2->count)
- return true;
-
- for (i = 0; i < macro1->count; i++)
- if (!_cpp_equiv_tokens (¯o1->exp.tokens[i], ¯o2->exp.tokens[i]))
- return true;
-
- return false;
-}
-
-/* Free the definition of hashnode H. */
-void
-_cpp_free_definition (cpp_hashnode *h)
-{
- /* Macros and assertions no longer have anything to free. */
- h->type = NT_VOID;
- /* Clear builtin flag in case of redefinition. */
- h->flags &= ~(NODE_BUILTIN | NODE_DISABLED);
-}
-
-/* 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 (cpp_reader *pfile, cpp_macro *macro, cpp_hashnode *node)
-{
- unsigned int len;
- /* Constraint 6.10.3.6 - duplicate parameter names. */
- if (node->flags & NODE_MACRO_ARG)
- {
- cpp_error (pfile, CPP_DL_ERROR, "duplicate macro parameter \"%s\"",
- NODE_NAME (node));
- return true;
- }
-
- if (BUFF_ROOM (pfile->a_buff)
- < (macro->paramc + 1) * sizeof (cpp_hashnode *))
- _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *));
-
- ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node;
- 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 (cpp_reader *pfile, cpp_macro *macro)
-{
- unsigned int prev_ident = 0;
-
- for (;;)
- {
- const cpp_token *token = _cpp_lex_token (pfile);
-
- switch (token->type)
- {
- default:
- /* Allow/ignore comments in parameter lists if we are
- preserving comments in macro expansions. */
- if (token->type == CPP_COMMENT
- && ! CPP_OPTION (pfile, discard_comments_in_macro_exp))
- continue;
-
- cpp_error (pfile, CPP_DL_ERROR,
- "\"%s\" may not appear in macro parameter list",
- cpp_token_as_text (pfile, token));
- return false;
-
- case CPP_NAME:
- if (prev_ident)
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "macro parameters must be comma-separated");
- return false;
- }
- prev_ident = 1;
-
- if (_cpp_save_parameter (pfile, macro, token->val.node))
- return false;
- continue;
-
- case CPP_CLOSE_PAREN:
- if (prev_ident || macro->paramc == 0)
- return true;
-
- /* Fall through to pick up the error. */
- case CPP_COMMA:
- if (!prev_ident)
- {
- cpp_error (pfile, CPP_DL_ERROR, "parameter name missing");
- return false;
- }
- prev_ident = 0;
- continue;
-
- case CPP_ELLIPSIS:
- macro->variadic = 1;
- if (!prev_ident)
- {
- _cpp_save_parameter (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, CPP_DL_PEDWARN,
- "anonymous variadic macros were introduced in C99");
- }
- else if (CPP_OPTION (pfile, pedantic))
- 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. */
- token = _cpp_lex_token (pfile);
- if (token->type == CPP_CLOSE_PAREN)
- return true;
- /* Fall through. */
-
- case CPP_EOF:
- cpp_error (pfile, CPP_DL_ERROR, "missing ')' in macro parameter list");
- return false;
- }
- }
-}
-
-/* Allocate room for a token from a macro's replacement list. */
-static cpp_token *
-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));
-
- return &((cpp_token *) BUFF_FRONT (pfile->a_buff))[macro->count++];
-}
-
-/* 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 (cpp_reader *pfile, cpp_macro *macro)
-{
- cpp_token *token;
-
- pfile->cur_token = alloc_expansion_token (pfile, macro);
- token = _cpp_lex_direct (pfile);
-
- /* Is this a parameter? */
- 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->value.arg_index;
- }
- else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0
- && (token->type == CPP_STRING || token->type == CPP_CHAR))
- check_trad_stringification (pfile, macro, &token->val.str);
-
- return token;
-}
-
-static bool
-create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
-{
- cpp_token *token;
- const cpp_token *ctoken;
-
- /* Get the first token of the expansion (or the '(' of a
- function-like macro). */
- ctoken = _cpp_lex_token (pfile);
-
- if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE))
- {
- bool ok = parse_params (pfile, macro);
- macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
- if (!ok)
- return false;
-
- /* Success. Commit the parameter array. */
- BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc];
- macro->fun_like = 1;
- }
- else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE))
- cpp_error (pfile, CPP_DL_PEDWARN,
- "ISO C requires whitespace after the macro name");
-
- if (macro->fun_like)
- token = lex_expansion_token (pfile, macro);
- else
- {
- token = alloc_expansion_token (pfile, macro);
- *token = *ctoken;
- }
-
- for (;;)
- {
- /* Check the stringifying # constraint 6.10.3.2.1 of
- function-like macros when lexing the subsequent token. */
- if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like)
- {
- if (token->type == CPP_MACRO_ARG)
- {
- token->flags &= ~PREV_WHITE;
- token->flags |= STRINGIFY_ARG;
- token->flags |= token[-1].flags & PREV_WHITE;
- token[-1] = token[0];
- macro->count--;
- }
- /* Let assembler get away with murder. */
- else if ((CPP_OPTION (pfile, lang) != CLK_ASM)
- && (!CPP_OPTION(pfile, allow_naked_hash)))
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "'#' is not followed by a macro parameter");
- return false;
- }
- }
-
- if (token->type == CPP_EOF)
- break;
-
- /* Paste operator constraint 6.10.3.3.1. */
- if (token->type == CPP_PASTE)
- {
- /* Token-paste ##, can appear in both object-like and
- function-like macros, but not at the ends. */
- if (--macro->count > 0)
- token = lex_expansion_token (pfile, macro);
-
- if (macro->count == 0 || token->type == CPP_EOF)
- {
- cpp_error (pfile, CPP_DL_ERROR,
- "'##' cannot appear at either end of a macro expansion");
- return false;
- }
-
- token[-1].flags |= PASTE_LEFT;
- }
-
- token = lex_expansion_token (pfile, macro);
- }
-
- macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
-
- /* Don't count the CPP_EOF. */
- macro->count--;
-
- /* Clear whitespace on first token for warn_of_redefinition(). */
- if (macro->count)
- macro->exp.tokens[0].flags &= ~PREV_WHITE;
-
- /* Commit the memory. */
- BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->exp.tokens[macro->count];
-
- return true;
-}
-
-/* Parse a macro and save its expansion. Returns nonzero on success. */
-bool
-_cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node)
-{
- cpp_macro *macro;
- unsigned int i;
- bool ok;
-
- macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
- macro->line = pfile->directive_line;
- macro->params = 0;
- macro->paramc = 0;
- macro->variadic = 0;
- macro->used = !CPP_OPTION (pfile, warn_unused_macros);
- macro->count = 0;
- macro->fun_like = 0;
- /* To suppress some diagnostics. */
- macro->syshdr = pfile->map->sysp != 0;
-
- if (CPP_OPTION (pfile, traditional))
- ok = _cpp_create_trad_definition (pfile, macro);
- else
- {
- cpp_token *saved_cur_token = pfile->cur_token;
-
- ok = create_iso_definition (pfile, macro);
-
- /* Restore lexer position because of games lex_expansion_token()
- plays lexing the macro. We set the type for SEEN_EOL() in
- cpplib.c.
-
- Longer term we should lex the whole line before coming here,
- and just copy the expansion. */
- saved_cur_token[-1].type = pfile->cur_token[-1].type;
- pfile->cur_token = saved_cur_token;
-
- /* Stop the lexer accepting __VA_ARGS__. */
- pfile->state.va_args_ok = 0;
- }
-
- /* Clear the fast argument lookup indices. */
- for (i = macro->paramc; i-- > 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;
-
- if (node->type == NT_MACRO)
- {
- if (CPP_OPTION (pfile, warn_unused_macros))
- _cpp_warn_if_unused_macro (pfile, node, NULL);
-
- if (warn_of_redefinition (pfile, node, macro))
- {
- 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, CPP_DL_PEDWARN,
- node->value.macro->line, 0,
- "this is the location of the previous definition");
- }
- }
-
- if (node->type != NT_VOID)
- _cpp_free_definition (node);
-
- /* Enter definition in hash table. */
- node->type = NT_MACRO;
- node->value.macro = macro;
- if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_")))
- node->flags |= NODE_WARN;
-
- return ok;
-}
-
-/* Warn if a token in STRING matches one of a function-like MACRO's
- parameters. */
-static void
-check_trad_stringification (cpp_reader *pfile, const cpp_macro *macro,
- const cpp_string *string)
-{
- unsigned int i, len;
- const uchar *p, *q, *limit;
-
- /* Loop over the string. */
- 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))
- p++;
-
- /* Find the end of the identifier. */
- q = p;
- while (q < limit && is_idchar (*q))
- q++;
-
- len = q - p;
-
- /* Loop over the function macro arguments to see if the
- identifier inside the string matches one of them. */
- for (i = 0; i < macro->paramc; i++)
- {
- const cpp_hashnode *node = macro->params[i];
-
- if (NODE_LEN (node) == len
- && !memcmp (p, NODE_NAME (node), len))
- {
- cpp_error (pfile, CPP_DL_WARNING,
- "macro argument \"%s\" would be stringified in traditional C",
- NODE_NAME (node));
- break;
- }
- }
- }
-}
-
-/* Returns the name, arguments and expansion of a macro, in a format
- suitable to be read back in again, and therefore also for DWARF 2
- debugging info. e.g. "PASTE(X, Y) X ## Y", or "MACNAME EXPANSION".
- 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 (cpp_reader *pfile, const cpp_hashnode *node)
-{
- unsigned int i, len;
- const cpp_macro *macro = node->value.macro;
- unsigned char *buffer;
-
- if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
- {
- cpp_error (pfile, CPP_DL_ICE,
- "invalid hash type %d in cpp_macro_definition", node->type);
- return 0;
- }
-
- /* Calculate length. */
- len = NODE_LEN (node) + 2; /* ' ' and NUL. */
- if (macro->fun_like)
- {
- len += 4; /* "()" plus possible final ".." of named
- varargs (we have + 1 below). */
- for (i = 0; i < macro->paramc; i++)
- 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
- {
- for (i = 0; i < macro->count; i++)
- {
- cpp_token *token = ¯o->exp.tokens[i];
-
- if (token->type == CPP_MACRO_ARG)
- len += NODE_LEN (macro->params[token->val.arg_no - 1]);
- else
- 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 = xrealloc (pfile->macro_buffer, len);
- pfile->macro_buffer_len = len;
- }
-
- /* Fill in the buffer. Start with the macro name. */
- buffer = pfile->macro_buffer;
- memcpy (buffer, NODE_NAME (node), NODE_LEN (node));
- buffer += NODE_LEN (node);
-
- /* Parameter names. */
- if (macro->fun_like)
- {
- *buffer++ = '(';
- for (i = 0; i < macro->paramc; i++)
- {
- cpp_hashnode *param = macro->params[i];
-
- if (param != pfile->spec_nodes.n__VA_ARGS__)
- {
- memcpy (buffer, NODE_NAME (param), NODE_LEN (param));
- buffer += NODE_LEN (param);
- }
-
- if (i + 1 < macro->paramc)
- /* Don't emit a space after the comma here; we're trying
- to emit a Dwarf-friendly definition, and the Dwarf spec
- forbids spaces in the argument list. */
- *buffer++ = ',';
- else if (macro->variadic)
- *buffer++ = '.', *buffer++ = '.', *buffer++ = '.';
- }
- *buffer++ = ')';
- }
-
- /* The Dwarf spec requires a space after the macro name, even if the
- definition is the empty string. */
- *buffer++ = ' ';
-
- if (CPP_OPTION (pfile, traditional))
- buffer = _cpp_copy_replacement_text (macro, buffer);
- else if (macro->count)
- /* Expansion tokens. */
- {
- for (i = 0; i < macro->count; i++)
- {
- cpp_token *token = ¯o->exp.tokens[i];
-
- if (token->flags & PREV_WHITE)
- *buffer++ = ' ';
- if (token->flags & STRINGIFY_ARG)
- *buffer++ = '#';
-
- if (token->type == CPP_MACRO_ARG)
- {
- memcpy (buffer,
- 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);
-
- if (token->flags & PASTE_LEFT)
- {
- *buffer++ = ' ';
- *buffer++ = '#';
- *buffer++ = '#';
- /* Next has PREV_WHITE; see _cpp_create_definition. */
- }
- }
- }
-
- *buffer = '\0';
- return pfile->macro_buffer;
-}
+++ /dev/null
-/* CPP Library - traditional lexical analysis and macro expansion.
- 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
-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"
-
-/* The replacement text of a function-like macro is stored as a
- contiguous sequence of aligned blocks, each representing the text
- between subsequent parameters.
-
- Each block comprises the text between its surrounding parameters,
- the length of that text, and the one-based index of the following
- parameter. The final block in the replacement text is easily
- recognizable as it has an argument index of zero. */
-
-struct block
-{
- unsigned int text_len;
- unsigned short arg_index;
- uchar text[1];
-};
-
-#define BLOCK_HEADER_LEN offsetof (struct block, text)
-#define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + (TEXT_LEN))
-
-/* Structure holding information about a function-like macro
- invocation. */
-struct fun_macro
-{
- /* Memory buffer holding the trad_arg array. */
- _cpp_buff *buff;
-
- /* An array of size the number of macro parameters + 1, containing
- the offsets of the start of each macro argument in the output
- buffer. The argument continues until the character before the
- start of the next one. */
- size_t *args;
-
- /* The hashnode of the macro. */
- cpp_hashnode *node;
-
- /* The offset of the macro name in the output buffer. */
- size_t offset;
-
- /* The line the macro name appeared on. */
- unsigned int line;
-
- /* Zero-based index of argument being currently lexed. */
- unsigned int argc;
-};
-
-/* Lexing state. It is mostly used to prevent macro expansion. */
-enum ls {ls_none = 0, /* Normal state. */
- ls_fun_open, /* When looking for '('. */
- ls_fun_close, /* When looking for ')'. */
- ls_defined, /* After defined. */
- ls_defined_close, /* Looking for ')' of defined(). */
- ls_hash, /* After # in preprocessor conditional. */
- ls_predicate, /* After the predicate, maybe paren? */
- ls_answer}; /* In answer to predicate. */
-
-/* Lexing TODO: Maybe handle space in escaped newlines. Stop cpplex.c
- from recognizing comments and directives during its lexing pass. */
-
-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 (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. */
- n += 2 + 1;
-
- if (n > (size_t) (pfile->out.limit - pfile->out.cur))
- {
- size_t size = pfile->out.cur - pfile->out.base;
- size_t new_size = (size + n) * 3 / 2;
-
- pfile->out.base = xrealloc (pfile->out.base, new_size);
- pfile->out.limit = pfile->out.base + new_size;
- pfile->out.cur = pfile->out.base + size;
- }
-}
-
-/* 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 *cur = pfile->buffer->cur;
-
- cur++;
- if (*cur == '/')
- cur++;
-
- /* People like decorating comments with '*', so check for '/'
- instead for efficiency. */
- while(! (*cur++ == '/' && cur[-2] == '*') )
- ;
-
- pfile->buffer->cur = cur;
-}
-
-/* CUR points to the asterisk introducing a comment in the current
- context. IN_DEFINE is true if we are in the replacement text of a
- macro.
-
- The asterisk and following comment is copied to the buffer pointed
- to by pfile->out.cur, which must be of sufficient size.
- Unterminated comments are diagnosed, and correctly terminated in
- the output. pfile->out.cur is updated depending upon IN_DEFINE,
- -C, -CC and pfile->state.in_directive.
-
- Returns a pointer to the first character after the comment in the
- input buffer. */
-static const uchar *
-copy_comment (cpp_reader *pfile, const uchar *cur, int in_define)
-{
- bool unterminated, copy = false;
- unsigned int from_line = pfile->line;
- cpp_buffer *buffer = pfile->buffer;
-
- 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");
-
- /* Comments in directives become spaces so that tokens are properly
- separated when the ISO preprocessor re-lexes the line. The
- exception is #define. */
- if (pfile->state.in_directive)
- {
- if (in_define)
- {
- if (CPP_OPTION (pfile, discard_comments_in_macro_exp))
- pfile->out.cur--;
- else
- copy = true;
- }
- else
- pfile->out.cur[-1] = ' ';
- }
- else if (CPP_OPTION (pfile, discard_comments))
- pfile->out.cur--;
- else
- 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 buffer->cur;
-}
-
-/* CUR points to any character in the input buffer. Skips over all
- contiguous horizontal white space and NULs, including comments if
- SKIP_COMMENTS, until reaching the first non-horizontal-whitespace
- character or the end of the current context. Escaped newlines are
- removed.
-
- The whitespace is copied verbatim to the output buffer, except that
- comments are handled as described in copy_comment().
- pfile->out.cur is updated.
-
- Returns a pointer to the first character after the whitespace in
- the input buffer. */
-static const uchar *
-skip_whitespace (cpp_reader *pfile, const uchar *cur, int skip_comments)
-{
- uchar *out = pfile->out.cur;
-
- for (;;)
- {
- unsigned int c = *cur++;
- *out++ = c;
-
- if (is_nvspace (c))
- continue;
-
- if (c == '/' && *cur == '*' && skip_comments)
- {
- pfile->out.cur = out;
- cur = copy_comment (pfile, cur, false /* in_define */);
- out = pfile->out.cur;
- continue;
- }
-
- out--;
- break;
- }
-
- pfile->out.cur = out;
- return cur - 1;
-}
-
-/* Lexes and outputs an identifier starting at CUR, which is assumed
- to point to a valid first character of an identifier. Returns
- the hashnode, and updates out.cur. */
-static cpp_hashnode *
-lex_identifier (cpp_reader *pfile, const uchar *cur)
-{
- size_t len;
- uchar *out = pfile->out.cur;
- cpp_hashnode *result;
-
- do
- *out++ = *cur++;
- while (is_numchar (*cur));
-
- CUR (pfile->context) = cur;
- len = out - pfile->out.cur;
- result = (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->out.cur,
- len, HT_ALLOC);
- pfile->out.cur = out;
- return result;
-}
-
-/* Overlays the true file buffer temporarily with text of length LEN
- starting at START. The true buffer is restored upon calling
- restore_buff(). */
-void
-_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;
-}
-
-/* Restores a buffer overlaid by _cpp_overlay_buffer(). */
-void
-_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 (cpp_reader *pfile)
-{
- do
- {
- if (pfile->buffer->need_line && !_cpp_get_fresh_line (pfile))
- return false;
- }
- while (!_cpp_scan_out_logical_line (pfile, NULL) || pfile->state.skipping);
-
- return pfile->buffer != NULL;
-}
-
-/* Set up state for finding the opening '(' of a function-like
- macro. */
-static void
-maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start, struct fun_macro *macro)
-{
- unsigned int n = node->value.macro->paramc + 1;
-
- if (macro->buff)
- _cpp_release_buff (pfile, macro->buff);
- macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t));
- macro->args = (size_t *) BUFF_FRONT (macro->buff);
- macro->node = node;
- macro->offset = start - pfile->out.base;
- macro->argc = 0;
-}
-
-/* Save the OFFSET of the start of the next argument to MACRO. */
-static void
-save_argument (struct fun_macro *macro, size_t offset)
-{
- macro->argc++;
- if (macro->argc <= macro->node->value.macro->paramc)
- macro->args[macro->argc] = offset;
-}
-
-/* Copies the next logical line in the current buffer (starting at
- buffer->cur) to the output buffer. The output is guaranteed to
- terminate with a NUL character. buffer->cur is updated.
-
- 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. */
-bool
-_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
-{
- bool result = true;
- cpp_context *context;
- const uchar *cur;
- uchar *out;
- struct fun_macro fmacro;
- unsigned int c, paren_depth = 0, quote;
- enum ls lex_state = ls_none;
- bool header_ok;
- const uchar *start_of_input_line;
-
- fmacro.buff = NULL;
-
- quote = 0;
- header_ok = pfile->state.angled_headers;
- CUR (pfile->context) = pfile->buffer->cur;
- RLIMIT (pfile->context) = pfile->buffer->rlimit;
- 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. */
- start_of_input_line = pfile->buffer->cur;
- new_context:
- context = pfile->context;
- cur = CUR (context);
- check_output_buffer (pfile, RLIMIT (context) - cur);
- out = pfile->out.cur;
-
- 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;
-
- /* Whitespace should "continue" out of the switch,
- non-whitespace should "break" out of it. */
- switch (c)
- {
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- case '\0':
- continue;
-
- case '\n':
- /* If this is a macro's expansion, pop it. */
- if (context->prev)
- {
- pfile->out.cur = out - 1;
- _cpp_pop_context (pfile);
- goto new_context;
- }
-
- /* Omit the newline from the output buffer. */
- pfile->out.cur = out - 1;
- pfile->buffer->cur = cur;
- pfile->buffer->need_line = true;
- pfile->line++;
-
- if ((lex_state == ls_fun_open || lex_state == ls_fun_close)
- && !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;
-
- case '<':
- if (header_ok)
- quote = '>';
- break;
- case '>':
- if (c == quote)
- quote = 0;
- break;
-
- case '"':
- case '\'':
- if (c == quote)
- quote = 0;
- else if (!quote)
- quote = c;
- break;
-
- case '\\':
- /* 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 && *cur == '*')
- {
- pfile->out.cur = out;
- cur = copy_comment (pfile, cur, macro != 0);
- out = pfile->out.cur;
- continue;
- }
- break;
-
- 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':
- case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- if (!pfile->state.skipping && (quote == 0 || macro))
- {
- cpp_hashnode *node;
- uchar *out_start = out - 1;
-
- pfile->out.cur = out_start;
- node = lex_identifier (pfile, cur - 1);
- out = pfile->out.cur;
- cur = CUR (context);
-
- if (node->type == NT_MACRO
- /* Should we expand for ls_answer? */
- && (lex_state == ls_none || lex_state == ls_fun_open)
- && !pfile->state.prevent_expansion)
- {
- /* Macros invalidate MI optimization. */
- pfile->mi_valid = false;
- if (! (node->flags & NODE_BUILTIN)
- && node->value.macro->fun_like)
- {
- maybe_start_funlike (pfile, node, out_start, &fmacro);
- lex_state = ls_fun_open;
- fmacro.line = pfile->line;
- continue;
- }
- else if (!recursive_macro (pfile, node))
- {
- /* Remove the object-like macro's name from the
- output, and push its replacement text. */
- pfile->out.cur = out_start;
- push_replacement_text (pfile, node);
- lex_state = ls_none;
- goto new_context;
- }
- }
- 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->value.arg_index);
- out = pfile->out.base;
- }
- else if (lex_state == ls_hash)
- {
- lex_state = ls_predicate;
- continue;
- }
- else if (pfile->state.in_expression
- && node == pfile->spec_nodes.n_defined)
- {
- lex_state = ls_defined;
- continue;
- }
- }
- break;
-
- case '(':
- if (quote == 0)
- {
- paren_depth++;
- if (lex_state == ls_fun_open)
- {
- if (recursive_macro (pfile, fmacro.node))
- lex_state = ls_none;
- else
- {
- lex_state = ls_fun_close;
- paren_depth = 1;
- out = pfile->out.base + fmacro.offset;
- fmacro.args[0] = fmacro.offset;
- }
- }
- else if (lex_state == ls_predicate)
- lex_state = ls_answer;
- else if (lex_state == ls_defined)
- lex_state = ls_defined_close;
- }
- break;
-
- case ',':
- if (quote == 0 && lex_state == ls_fun_close && paren_depth == 1)
- save_argument (&fmacro, out - pfile->out.base);
- break;
-
- case ')':
- if (quote == 0)
- {
- paren_depth--;
- if (lex_state == ls_fun_close && paren_depth == 0)
- {
- cpp_macro *m = fmacro.node->value.macro;
-
- m->used = 1;
- lex_state = ls_none;
- save_argument (&fmacro, out - pfile->out.base);
-
- /* A single zero-length argument is no argument. */
- if (fmacro.argc == 1
- && m->paramc == 0
- && out == pfile->out.base + fmacro.offset + 1)
- fmacro.argc = 0;
-
- if (_cpp_arguments_ok (pfile, m, fmacro.node, fmacro.argc))
- {
- /* Remove the macro's invocation from the
- output, and push its replacement text. */
- pfile->out.cur = (pfile->out.base
- + fmacro.offset);
- CUR (context) = cur;
- replace_args_and_push (pfile, &fmacro);
- goto new_context;
- }
- }
- else if (lex_state == ls_answer || lex_state == ls_defined_close)
- lex_state = ls_none;
- }
- break;
-
- case '#':
- if (cur - 1 == start_of_input_line
- /* A '#' from a macro doesn't start a directive. */
- && !pfile->context->prev
- && !pfile->state.in_directive)
- {
- /* A directive. With the way _cpp_handle_directive
- currently works, we only want to call it if either we
- know the directive is OK, or we want it to fail and
- be removed from the output. If we want it to be
- passed through (the assembler case) then we must not
- call _cpp_handle_directive. */
- pfile->out.cur = out;
- cur = skip_whitespace (pfile, cur, true /* skip_comments */);
- out = pfile->out.cur;
-
- if (*cur == '\n')
- {
- /* Null directive. Ignore it and don't invalidate
- the MI optimization. */
- pfile->buffer->need_line = true;
- pfile->line++;
- result = false;
- goto done;
- }
- else
- {
- bool do_it = false;
-
- if (is_numstart (*cur)
- && CPP_OPTION (pfile, lang) != CLK_ASM)
- do_it = true;
- else if (is_idstart (*cur))
- /* Check whether we know this directive, but don't
- advance. */
- do_it = lex_identifier (pfile, cur)->is_directive;
-
- if (do_it || CPP_OPTION (pfile, lang) != CLK_ASM)
- {
- /* This is a kludge. We want to have the ISO
- preprocessor lex the next token. */
- pfile->buffer->cur = cur;
- _cpp_handle_directive (pfile, false /* indented */);
- result = false;
- goto done;
- }
- }
- }
-
- if (pfile->state.in_expression)
- {
- lex_state = ls_hash;
- continue;
- }
- break;
-
- default:
- break;
- }
-
- /* Non-whitespace disables MI optimization and stops treating
- '<' as a quote in #include. */
- header_ok = false;
- if (!pfile->state.in_directive)
- pfile->mi_valid = false;
-
- if (lex_state == ls_none)
- continue;
-
- /* Some of these transitions of state are syntax errors. The
- ISO preprocessor will issue errors later. */
- if (lex_state == ls_fun_open)
- /* Missing '('. */
- lex_state = ls_none;
- else if (lex_state == ls_hash
- || lex_state == ls_predicate
- || lex_state == ls_defined)
- lex_state = ls_none;
-
- /* ls_answer and ls_defined_close keep going until ')'. */
- }
-
- done:
- if (fmacro.buff)
- _cpp_release_buff (pfile, fmacro.buff);
-
- if (lex_state == ls_fun_close)
- 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 (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
- {
- cpp_macro *macro = node->value.macro;
- macro->used = 1;
- text = macro->exp.text;
- len = macro->count;
- }
-
- _cpp_push_text_context (pfile, node, text, len);
-}
-
-/* Returns TRUE if traditional macro recursion is detected. */
-static bool
-recursive_macro (cpp_reader *pfile, cpp_hashnode *node)
-{
- bool recursing = !!(node->flags & NODE_DISABLED);
-
- /* Object-like macros that are already expanding are necessarily
- recursive.
-
- However, it is possible to have traditional function-like macros
- that are not infinitely recursive but recurse to any given depth.
- Further, it is easy to construct examples that get ever longer
- until the point they stop recursing. So there is no easy way to
- detect true recursion; instead we assume any expansion more than
- 20 deep since the first invocation of this macro must be
- recursing. */
- if (recursing && node->value.macro->fun_like)
- {
- size_t depth = 0;
- cpp_context *context = pfile->context;
-
- do
- {
- depth++;
- if (context->macro == node && depth > 20)
- break;
- context = context->prev;
- }
- while (context);
- recursing = context != NULL;
- }
-
- if (recursing)
- cpp_error (pfile, CPP_DL_ERROR,
- "detected recursion whilst expanding macro \"%s\"",
- NODE_NAME (node));
-
- return recursing;
-}
-
-/* Return the length of the replacement text of a function-like or
- object-like non-builtin macro. */
-size_t
-_cpp_replacement_text_len (const cpp_macro *macro)
-{
- size_t len;
-
- if (macro->fun_like && (macro->paramc != 0))
- {
- const uchar *exp;
-
- len = 0;
- for (exp = macro->exp.text;;)
- {
- struct block *b = (struct block *) exp;
-
- len += b->text_len;
- if (b->arg_index == 0)
- break;
- len += NODE_LEN (macro->params[b->arg_index - 1]);
- exp += BLOCK_LEN (b->text_len);
- }
- }
- else
- len = macro->count;
-
- return len;
-}
-
-/* Copy the replacement text of MACRO to DEST, which must be of
- sufficient size. It is not NUL-terminated. The next character is
- returned. */
-uchar *
-_cpp_copy_replacement_text (const cpp_macro *macro, uchar *dest)
-{
- if (macro->fun_like && (macro->paramc != 0))
- {
- const uchar *exp;
-
- for (exp = macro->exp.text;;)
- {
- struct block *b = (struct block *) exp;
- cpp_hashnode *param;
-
- memcpy (dest, b->text, b->text_len);
- dest += b->text_len;
- if (b->arg_index == 0)
- break;
- param = macro->params[b->arg_index - 1];
- memcpy (dest, NODE_NAME (param), NODE_LEN (param));
- dest += NODE_LEN (param);
- exp += BLOCK_LEN (b->text_len);
- }
- }
- else
- {
- memcpy (dest, macro->exp.text, macro->count);
- dest += macro->count;
- }
-
- return dest;
-}
-
-/* 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
-replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
-{
- cpp_macro *macro = fmacro->node->value.macro;
-
- if (macro->paramc == 0)
- push_replacement_text (pfile, fmacro->node);
- else
- {
- const uchar *exp;
- uchar *p;
- _cpp_buff *buff;
- size_t len = 0;
-
- /* Calculate the length of the argument-replaced text. */
- for (exp = macro->exp.text;;)
- {
- struct block *b = (struct block *) exp;
-
- len += b->text_len;
- if (b->arg_index == 0)
- break;
- len += (fmacro->args[b->arg_index]
- - fmacro->args[b->arg_index - 1] - 1);
- exp += BLOCK_LEN (b->text_len);
- }
-
- /* Allocate room for the expansion plus \n. */
- buff = _cpp_get_buff (pfile, len + 1);
-
- /* Copy the expansion and replace arguments. */
- p = BUFF_FRONT (buff);
- for (exp = macro->exp.text;;)
- {
- struct block *b = (struct block *) exp;
- size_t arglen;
-
- memcpy (p, b->text, b->text_len);
- p += b->text_len;
- if (b->arg_index == 0)
- break;
- arglen = (fmacro->args[b->arg_index]
- - fmacro->args[b->arg_index - 1] - 1);
- memcpy (p, pfile->out.base + fmacro->args[b->arg_index - 1],
- arglen);
- p += arglen;
- exp += BLOCK_LEN (b->text_len);
- }
-
- /* \n-terminate. */
- *p = '\n';
- _cpp_push_text_context (pfile, fmacro->node, BUFF_FRONT (buff), len);
-
- /* So we free buffer allocation when macro is left. */
- pfile->context->buff = buff;
- }
-}
-
-/* Read and record the parameters, if any, of a function-like macro
- definition. Destroys pfile->out.cur.
-
- Returns true on success, false on failure (syntax error or a
- duplicate parameter). On success, CUR (pfile->context) is just
- past the closing parenthesis. */
-static bool
-scan_parameters (cpp_reader *pfile, cpp_macro *macro)
-{
- const uchar *cur = CUR (pfile->context) + 1;
- bool ok;
-
- for (;;)
- {
- cur = skip_whitespace (pfile, cur, true /* skip_comments */);
-
- if (is_idstart (*cur))
- {
- ok = false;
- if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur)))
- break;
- cur = skip_whitespace (pfile, CUR (pfile->context),
- true /* skip_comments */);
- if (*cur == ',')
- {
- cur++;
- continue;
- }
- ok = (*cur == ')');
- break;
- }
-
- ok = (*cur == ')' && macro->paramc == 0);
- break;
- }
-
- if (!ok)
- cpp_error (pfile, CPP_DL_ERROR, "syntax error in macro parameter list");
-
- CUR (pfile->context) = cur + (*cur == ')');
-
- return ok;
-}
-
-/* Save the text from pfile->out.base to pfile->out.cur as
- the replacement text for the current macro, followed by argument
- ARG_INDEX, with zero indicating the end of the replacement
- text. */
-static void
-save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
- unsigned int arg_index)
-{
- size_t len = pfile->out.cur - pfile->out.base;
- uchar *exp;
-
- if (macro->paramc == 0)
- {
- /* Object-like and function-like macros without parameters
- simply store their \n-terminated replacement text. */
- exp = _cpp_unaligned_alloc (pfile, len + 1);
- memcpy (exp, pfile->out.base, len);
- exp[len] = '\n';
- macro->exp.text = exp;
- macro->count = len;
- }
- else
- {
- /* Store the text's length (unsigned int), the argument index
- (unsigned short, base 1) and then the text. */
- size_t blen = BLOCK_LEN (len);
- struct block *block;
-
- if (macro->count + blen > BUFF_ROOM (pfile->a_buff))
- _cpp_extend_buff (pfile, &pfile->a_buff, macro->count + blen);
-
- exp = BUFF_FRONT (pfile->a_buff);
- block = (struct block *) (exp + macro->count);
- macro->exp.text = exp;
-
- /* Write out the block information. */
- block->text_len = len;
- block->arg_index = arg_index;
- memcpy (block->text, pfile->out.base, len);
-
- /* Lex the rest into the start of the output buffer. */
- pfile->out.cur = pfile->out.base;
-
- macro->count += blen;
-
- /* If we've finished, commit the memory. */
- if (arg_index == 0)
- BUFF_FRONT (pfile->a_buff) += macro->count;
- }
-}
-
-/* Analyze and save the replacement text of a macro. Returns true on
- success. */
-bool
-_cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro)
-{
- const uchar *cur;
- uchar *limit;
- cpp_context *context = pfile->context;
-
- /* The context has not been set up for command line defines, and CUR
- has not been updated for the macro name for in-file defines. */
- pfile->out.cur = pfile->out.base;
- CUR (context) = pfile->buffer->cur;
- RLIMIT (context) = pfile->buffer->rlimit;
- check_output_buffer (pfile, RLIMIT (context) - CUR (context));
-
- /* 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 _cpp_scan_out_logical_line. */
- if (!ok)
- macro = NULL;
- else
- {
- BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc];
- macro->fun_like = 1;
- }
- }
-
- /* Skip leading whitespace in the replacement text. */
- pfile->buffer->cur
- = skip_whitespace (pfile, CUR (context),
- CPP_OPTION (pfile, discard_comments_in_macro_exp));
-
- pfile->state.prevent_expansion++;
- _cpp_scan_out_logical_line (pfile, macro);
- pfile->state.prevent_expansion--;
-
- if (!macro)
- return false;
-
- /* Skip trailing white space. */
- cur = pfile->out.base;
- limit = pfile->out.cur;
- while (limit > cur && is_space (limit[-1]))
- limit--;
- pfile->out.cur = limit;
- save_replacement_text (pfile, macro, 0);
-
- return true;
-}
-
-/* Copy SRC of length LEN to DEST, but convert all contiguous
- whitespace to a single space, provided it is not in quotes. The
- 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 (uchar *dest, const uchar *src, size_t len, uchar *pquote)
-{
- uchar *orig_dest = dest;
- uchar quote = *pquote;
-
- while (len)
- {
- if (is_space (*src) && !quote)
- {
- do
- src++, len--;
- while (len && is_space (*src));
- *dest++ = ' ';
- }
- else
- {
- if (*src == '\'' || *src == '"')
- {
- if (!quote)
- quote = *src;
- else if (quote == *src)
- quote = 0;
- }
- *dest++ = *src++, len--;
- }
- }
-
- *pquote = quote;
- return dest - orig_dest;
-}
-
-/* Returns true if MACRO1 and MACRO2 have expansions different other
- than in the form of their whitespace. */
-bool
-_cpp_expansions_different_trad (const cpp_macro *macro1,
- const cpp_macro *macro2)
-{
- uchar *p1 = xmalloc (macro1->count + macro2->count);
- uchar *p2 = p1 + macro1->count;
- uchar quote1 = 0, quote2 = 0;
- bool mismatch;
- size_t len1, len2;
-
- if (macro1->paramc > 0)
- {
- const uchar *exp1 = macro1->exp.text, *exp2 = macro2->exp.text;
-
- mismatch = true;
- for (;;)
- {
- struct block *b1 = (struct block *) exp1;
- struct block *b2 = (struct block *) exp2;
-
- if (b1->arg_index != b2->arg_index)
- break;
-
- len1 = canonicalize_text (p1, b1->text, b1->text_len, "e1);
- len2 = canonicalize_text (p2, b2->text, b2->text_len, "e2);
- if (len1 != len2 || memcmp (p1, p2, len1))
- break;
- if (b1->arg_index == 0)
- {
- mismatch = false;
- break;
- }
- exp1 += BLOCK_LEN (b1->text_len);
- exp2 += BLOCK_LEN (b2->text_len);
- }
- }
- else
- {
- len1 = canonicalize_text (p1, macro1->exp.text, macro1->count, "e1);
- len2 = canonicalize_text (p2, macro2->exp.text, macro2->count, "e2);
- mismatch = (len1 != len2 || memcmp (p1, p2, len1));
- }
-
- free (p1);
- return mismatch;
-}
+++ /dev/null
-/* 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 */
/* Language-independent diagnostic subroutines for the GNU Compiler Collection
- Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This file implements the language independent aspect of diagnostic
#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 "options.h"
#include "version.h"
#include "input.h"
#include "intl.h"
#include "diagnostic.h"
+#include "opts.h"
/* Prototypes. */
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. */
/* 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;
+ context->printer->wrapping.rule = DIAGNOSTICS_SHOW_PREFIX_ONCE;
memset (context->diagnostic_count, 0, sizeof context->diagnostic_count);
- context->warnings_are_errors_message = warnings_are_errors;
+ context->issue_warnings_are_errors_message = true;
+ context->warning_as_error_requested = false;
+ context->show_option_requested = false;
context->abort_on_error = false;
context->internal_error = NULL;
diagnostic_starter (context) = default_diagnostic_starter;
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)
+/* Initialize DIAGNOSTIC, where the message MSG has already been
+ translated. */
+void
+diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
+ va_list *args, location_t location,
+ diagnostic_t kind)
{
- 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;
+ diagnostic->message.err_no = errno;
+ diagnostic->message.args_ptr = args;
+ diagnostic->message.format_spec = msg;
+ diagnostic->location = location;
+ diagnostic->kind = kind;
+ diagnostic->option_index = 0;
}
+/* Initialize DIAGNOSTIC, where the message GMSGID has not yet been
+ translated. */
void
-diagnostic_set_info (diagnostic_info *diagnostic, const char *msgid,
+diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
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;
+ diagnostic_set_info_translated (diagnostic, _(gmsgid), args, location, kind);
}
/* Return a malloc'd string describing a location. The caller is
#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]));
+ const char *text = _(diagnostic_kind_text[diagnostic->kind]);
+ expanded_location s = expand_location (diagnostic->location);
+ gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND);
+
+ return
+ (s.file == NULL
+ ? build_message_string ("%s: %s", progname, text)
+#ifdef USE_MAPPED_LOCATION
+ : flag_show_column && s.column != 0
+ ? build_message_string ("%s:%d:%d: %s", s.file, s.line, s.column, text)
+#endif
+ : build_message_string ("%s:%d: %s", s.file, s.line, text));
}
/* Count a diagnostic. Return true if the message should be printed. */
switch (kind)
{
default:
- abort();
- break;
+ gcc_unreachable ();
case DK_ICE:
#ifndef ENABLE_CHECKING
|| diagnostic_kind_count (context, DK_SORRY) > 0)
&& !context->abort_on_error)
{
+ expanded_location s = expand_location (diagnostic->location);
fnotice (stderr, "%s:%d: confused by earlier errors, bailing out\n",
- diagnostic->location.file, diagnostic->location.line);
+ s.file, s.line);
exit (FATAL_EXIT_CODE);
}
#endif
if (!diagnostic_report_warnings_p ())
return false;
- if (!warnings_are_errors)
+ if (!context->warning_as_error_requested)
{
++diagnostic_kind_count (context, DK_WARNING);
break;
}
-
- if (context->warnings_are_errors_message)
+ else if (context->issue_warnings_are_errors_message)
{
pp_verbatim (context->printer,
"%s: warnings being treated as errors\n", progname);
- context->warnings_are_errors_message = false;
+ context->issue_warnings_are_errors_message = false;
}
/* And fall through. */
case DK_SORRY:
if (context->abort_on_error)
real_abort ();
+ if (flag_fatal_errors)
+ {
+ fnotice (stderr, "compilation terminated due to -Wfatal-errors.\n");
+ exit (FATAL_EXIT_CODE);
+ }
break;
case DK_ICE:
if (context->abort_on_error)
real_abort ();
- fnotice (stderr, bug_report_request, bug_report_url);
+ fnotice (stderr, "Please submit a full bug report,\n"
+ "with preprocessed source if appropriate.\n"
+ "See %s for instructions.\n", bug_report_url);
exit (FATAL_EXIT_CODE);
case DK_FATAL:
exit (FATAL_EXIT_CODE);
default:
- real_abort ();
+ gcc_unreachable ();
}
}
/* 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. */
-
+ that caused an error. Called from all error and warning functions. */
void
diagnostic_report_current_function (diagnostic_context *context)
{
diagnostic_report_current_module (context);
- (*lang_hooks.print_error_function) (context, input_filename);
+ lang_hooks.print_error_function (context, input_filename);
}
void
pp_needs_newline (context->printer) = false;
}
- if (input_file_stack && diagnostic_last_module_changed (context))
+ p = input_file_stack;
+ if (p && diagnostic_last_module_changed (context))
{
- p = input_file_stack;
+ expanded_location xloc = expand_location (p->location);
pp_verbatim (context->printer,
"In file included from %s:%d",
- p->location.file, p->location.line);
+ xloc.file, xloc.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");
+ {
+ xloc = expand_location (p->location);
+ pp_verbatim (context->printer,
+ ",\n from %s:%d",
+ xloc.file, xloc.line);
+ }
+ pp_verbatim (context->printer, ":");
diagnostic_set_last_module (context);
+ pp_newline (context->printer);
}
}
static void
default_diagnostic_finalizer (diagnostic_context *context,
- diagnostic_info *diagnostic __attribute__((unused)))
+ diagnostic_info *diagnostic ATTRIBUTE_UNUSED)
{
pp_destroy_prefix (context->printer);
}
diagnostic_report_diagnostic (diagnostic_context *context,
diagnostic_info *diagnostic)
{
- if (context->lock++ && diagnostic->kind < DK_SORRY)
- error_recursion (context);
+ if (context->lock > 0)
+ {
+ /* If we're reporting an ICE in the middle of some other error,
+ try to flush out the previous error, then let this one
+ through. Don't do this more than once. */
+ if (diagnostic->kind == DK_ICE && context->lock == 1)
+ pp_flush (context->printer);
+ else
+ error_recursion (context);
+ }
+
+ if (diagnostic->option_index
+ && ! option_enabled (diagnostic->option_index))
+ return;
+
+ context->lock++;
if (diagnostic_count_diagnostic (context, diagnostic))
{
+ const char *saved_format_spec = diagnostic->message.format_spec;
+
+ if (context->show_option_requested && diagnostic->option_index)
+ diagnostic->message.format_spec
+ = ACONCAT ((diagnostic->message.format_spec,
+ " [", cl_options[diagnostic->option_index].opt_text, "]", NULL));
+
+ diagnostic->message.locus = &diagnostic->location;
+ pp_format (context->printer, &diagnostic->message);
(*diagnostic_starter (context)) (context, diagnostic);
- pp_format_text (context->printer, &diagnostic->message);
+ pp_output_formatted_text (context->printer);
(*diagnostic_finalizer (context)) (context, diagnostic);
pp_flush (context->printer);
diagnostic_action_after_output (context, diagnostic);
+ diagnostic->message.format_spec = saved_format_spec;
}
context->lock--;
/* 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
- ))
+ while (p[0] == '.' && p[1] == '.' && IS_DIR_SEPARATOR (p[2]))
p += 3;
- while (q[0] == '.' && q[1] == '.'
- && (q[2] == DIR_SEPARATOR
-#ifdef DIR_SEPARATOR_2
- || p[2] == DIR_SEPARATOR_2
-#endif
- ))
+ while (q[0] == '.' && q[1] == '.' && IS_DIR_SEPARATOR (q[2]))
q += 3;
/* Now skip any parts the two filenames have in common. */
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
- )
+ while (p > name && !IS_DIR_SEPARATOR (p[-1]))
p--;
return p;
/* 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, ...)
+verbatim (const char *gmsgid, ...)
{
text_info text;
va_list ap;
- va_start (ap, msgid);
+ va_start (ap, gmsgid);
text.err_no = errno;
text.args_ptr = ≈
- text.format_spec = _(msgid);
+ text.format_spec = _(gmsgid);
+ text.locus = NULL;
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, ...)
+inform (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
- va_start (ap, msgid);
- diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_NOTE);
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &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, ...)
+warning (int opt, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
- va_start (ap, msgid);
- diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_WARNING);
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING);
+ diagnostic.option_index = opt;
+
+ report_diagnostic (&diagnostic);
+ va_end (ap);
+}
+
+void
+warning0 (const char *gmsgid, ...)
+{
+ diagnostic_info diagnostic;
+ va_list ap;
+
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING);
report_diagnostic (&diagnostic);
va_end (ap);
}
of the -pedantic command-line switch. To get a warning enabled
only with that switch, write "if (pedantic) pedwarn (...);" */
void
-pedwarn (const char *msgid, ...)
+pedwarn (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
- va_start (ap, msgid);
- diagnostic_set_info (&diagnostic, msgid, &ap, input_location,
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &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, ...)
+error (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
- va_start (ap, msgid);
- diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_ERROR);
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ERROR);
report_diagnostic (&diagnostic);
va_end (ap);
}
required by the relevant specification but not implemented by GCC.
An object file will not be produced. */
void
-sorry (const char *msgid, ...)
+sorry (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
- va_start (ap, msgid);
- diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_SORRY);
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_SORRY);
report_diagnostic (&diagnostic);
va_end (ap);
}
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, ...)
+fatal_error (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
- va_start (ap, msgid);
- diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_FATAL);
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_FATAL);
report_diagnostic (&diagnostic);
va_end (ap);
- /* NOTREACHED */
- real_abort ();
+ gcc_unreachable ();
}
/* An internal consistency check has failed. We make no attempt to
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, ...)
+internal_error (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
- va_start (ap, msgid);
- diagnostic_set_info (&diagnostic, msgid, &ap, input_location, DK_ICE);
+ va_start (ap, gmsgid);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ICE);
report_diagnostic (&diagnostic);
va_end (ap);
- /* NOTREACHED */
- real_abort ();
+ gcc_unreachable ();
}
\f
/* Special case error functions. Most are implemented in terms of the
/* 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, ...)
+fnotice (FILE *file, const char *cmsgid, ...)
{
va_list ap;
- va_start (ap, msgid);
- vfprintf (file, _(msgid), ap);
+ va_start (ap, cmsgid);
+ vfprintf (file, _(cmsgid), ap);
va_end (ap);
}
static void
error_recursion (diagnostic_context *context)
{
+ diagnostic_info diagnostic;
+
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);
+
+ /* Call diagnostic_action_after_output to get the "please submit a bug
+ report" message. It only looks at the kind field of diagnostic_info. */
+ diagnostic.kind = DK_ICE;
+ diagnostic_action_after_output (context, &diagnostic);
+
+ /* Do not use gcc_unreachable here; that goes through internal_error
+ and therefore would cause infinite recursion. */
+ real_abort ();
}
/* Report an internal compiler error in a friendly manner. This is
/* Various declarations for language-independent diagnostics subroutines.
- Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#ifndef GCC_DIAGNOSTIC_H
#define GCC_DIAGNOSTIC_H
location_t location;
/* The kind of diagnostic it is about. */
diagnostic_t kind;
+ /* Which OPT_* directly controls this diagnostic. */
+ int option_index;
} diagnostic_info;
#define pedantic_error_kind() (flag_pedantic_errors ? DK_ERROR : DK_WARNING)
/* True if we should display the "warnings are being tread as error"
message, usually displayed once per compiler run. */
- bool warnings_are_errors_message;
+ bool issue_warnings_are_errors_message;
+
+ /* True if it has been requested that warnings be treated as errors. */
+ bool warning_as_error_requested;
+
+ /* True if we should print the command line option which controls
+ each diagnostic, if known. */
+ bool show_option_requested;
/* True if we should raise a SIGABRT on errors. */
bool abort_on_error;
int last_module;
int lock;
-
- /* Hook for front-end extensions. */
- void *x_data;
};
/* Client supplied function to announce a diagnostic. */
#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)
+#define diagnostic_prefixing_rule(DC) ((DC)->printer->wrapping.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_line_cutoff(DC) ((DC)->printer->wrapping.line_cutoff)
#define diagnostic_flush_buffer(DC) pp_base_flush ((DC)->printer)
extern void diagnostic_report_current_function (diagnostic_context *);
extern void diagnostic_report_diagnostic (diagnostic_context *,
diagnostic_info *);
+#ifdef ATTRIBUTE_GCC_DIAG
extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *,
- location_t, diagnostic_t);
+ location_t, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0);
+extern void diagnostic_set_info_translated (diagnostic_info *, const char *,
+ va_list *, location_t,
+ diagnostic_t)
+ ATTRIBUTE_GCC_DIAG(2,0);
+#endif
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 *);
+/* In tree-pretty-print.c */
+extern int dump_generic_node (pretty_printer *, tree, int, int, bool);
+extern void print_generic_stmt (FILE *, tree, int);
+extern void print_generic_stmt_indented (FILE *, tree, int, int);
+extern void print_generic_expr (FILE *, tree, int);
+extern void print_generic_decl (FILE *, tree, int);
+
+extern void debug_generic_expr (tree);
+extern void debug_generic_stmt (tree);
+extern void debug_c_tree (tree);
#endif /* ! GCC_DIAGNOSTIC_H */
/* Exception Handling interface routines.
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Contributed by Mike Stump <mrs@cygnus.com>.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
struct function;
-struct inline_remap;
-
/* Per-function EH data. Used only in except.c, but GC and others
manipulate pointers to the opaque type. */
struct eh_status;
/* Test: is exception handling turned on? */
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 (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 (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 (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 (tree);
-
-/* End a catch clause. Control will resume after the try/catch block. */
-extern void expand_end_catch (void);
-
-/* End a sequence of catch handlers for a try block. */
-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 (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 (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 (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 (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 (void);
+extern void note_eh_region_may_contain_throw (struct eh_region *);
+extern void note_current_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 (void (*) (rtx));
+/* Invokes CALLBACK for every exception region in the current function. */
+extern void for_each_eh_region (void (*) (struct eh_region *));
+
/* Determine if the given INSN can throw an exception. */
+extern bool can_throw_internal_1 (int, bool);
extern bool can_throw_internal (rtx);
+extern bool can_throw_external_1 (int, bool);
extern bool can_throw_external (rtx);
-/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls. */
+/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls. */
extern void set_nothrow_function_flags (void);
/* After initial rtl generation, call back to finish generating
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 rtx get_exception_filter (struct function *);
+typedef tree (*duplicate_eh_regions_map) (tree, void *);
+extern int duplicate_eh_regions (struct function *, duplicate_eh_regions_map, void *, int);
extern void sjlj_emit_function_exit_after (rtx);
-
+extern void default_init_unwind_resume_libfunc (void);
+
+extern struct eh_region *gen_eh_region_cleanup (struct eh_region *,
+ struct eh_region *);
+extern struct eh_region *gen_eh_region_try (struct eh_region *);
+extern struct eh_region *gen_eh_region_catch (struct eh_region *, tree);
+extern struct eh_region *gen_eh_region_allowed (struct eh_region *, tree);
+extern struct eh_region *gen_eh_region_must_not_throw (struct eh_region *);
+extern int get_eh_region_number (struct eh_region *);
+extern bool get_eh_region_may_contain_throw (struct eh_region *);
+extern tree get_eh_region_tree_label (struct eh_region *);
+extern void set_eh_region_tree_label (struct eh_region *, tree);
+
+extern void foreach_reachable_handler (int, bool,
+ void (*) (struct eh_region *, void *),
+ void *);
+
+extern void collect_eh_region_array (void);
+extern void expand_resx_expr (tree);
+extern void verify_eh_tree (struct function *);
+extern void dump_eh_tree (FILE *, struct function *);
+
+/* tree-eh.c */
+extern void add_stmt_to_eh_region_fn (struct function *, tree, int);
+extern bool remove_stmt_from_eh_region_fn (struct function *, tree);
+extern int lookup_stmt_eh_region_fn (struct function *, tree);
+extern int lookup_stmt_eh_region (tree);
+extern bool verify_eh_edges (tree);
/* If non-NULL, this is a function that returns an expression to be
executed if an unhandled exception is propagated out of a cleanup
#ifndef MUST_USE_SJLJ_EXCEPTIONS
# if !(defined (EH_RETURN_DATA_REGNO) \
- && (defined (IA64_UNWIND_INFO) \
+ && (defined (TARGET_UNWIND_INFO) \
|| (DWARF2_UNWIND_INFO \
&& (defined (EH_RETURN_HANDLER_RTX) \
|| defined (HAVE_eh_return)))))
# if !defined(EH_RETURN_HANDLER_RTX) && !defined(HAVE_eh_return)
#error "EH_RETURN_HANDLER_RTX or eh_return required"
# endif
-# if !defined(DWARF2_UNWIND_INFO) && !defined(IA64_UNWIND_INFO)
- #error "{DWARF2,IA64}_UNWIND_INFO required"
+# if !defined(DWARF2_UNWIND_INFO) && !defined(TARGET_UNWIND_INFO)
+ #error "{DWARF2,TARGET}_UNWIND_INFO required"
# endif
# endif
#else
# define USING_SJLJ_EXCEPTIONS MUST_USE_SJLJ_EXCEPTIONS
#endif
+
+struct throw_stmt_node GTY(())
+{
+ tree stmt;
+ int region_nr;
+};
+
+extern struct htab *get_eh_throw_stmt_table (struct function *);
+extern void set_eh_throw_stmt_table (struct function *, struct htab *);
+++ /dev/null
-/* 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;
-}
+++ /dev/null
-/* 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 */
+++ /dev/null
-/* Hash tables.
- 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
-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 "hashtable.h"
-
-/* The code below is a specialization of Vladimir Makarov's expandable
- hash tables (see libiberty/hashtab.c). The abstraction penalty was
- too high to continue using the generic form. This code knows
- intrinsically how to calculate a hash value, and how to compare an
- existing entry with a potential new one. Also, the ability to
- delete members from the table has been removed. */
-
-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 (const unsigned char *str, size_t len)
-{
- size_t n = len;
- unsigned int r = 0;
-#define HASHSTEP(r, c) ((r) * 67 + ((c) - 113));
-
- while (n--)
- r = HASHSTEP (r, *str++);
-
- return r + len;
-#undef HASHSTEP
-}
-
-/* Initialize an identifier hashtable. */
-
-hash_table *
-ht_create (unsigned int order)
-{
- unsigned int nslots = 1 << order;
- hash_table *table;
-
- table = xcalloc (1, sizeof (hash_table));
-
- /* Strings need no alignment. */
- _obstack_begin (&table->stack, 0, 0,
- (void *(*) (long)) xmalloc,
- (void (*) (void *)) free);
-
- obstack_alignment_mask (&table->stack) = 0;
-
- table->entries = xcalloc (nslots, sizeof (hashnode));
- table->nslots = nslots;
- return table;
-}
-
-/* Frees all memory associated with a hash table. */
-
-void
-ht_destroy (hash_table *table)
-{
- obstack_free (&table->stack, NULL);
- free (table->entries);
- free (table);
-}
-
-/* Returns the hash entry for the a STR of length LEN. If that string
- already exists in the table, returns the existing entry, and, if
- INSERT is CPP_ALLOCED, frees the last obstack object. If the
- identifier hasn't been seen before, and INSERT is CPP_NO_INSERT,
- returns NULL. Otherwise insert and returns a new entry. A new
- string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is
- CPP_ALLOCED and the item is assumed to be at the top of the
- obstack. */
-hashnode
-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;
- unsigned int index;
- size_t sizemask;
- hashnode node;
-
- sizemask = table->nslots - 1;
- index = hash & sizemask;
- table->searches++;
-
- node = table->entries[index];
-
- if (node != NULL)
- {
- 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;
- }
-
- /* 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)
- return NULL;
-
- node = (*table->alloc_node) (table);
- table->entries[index] = node;
-
- HT_LEN (node) = (unsigned int) len;
- node->hash_value = hash;
- if (insert == HT_ALLOC)
- HT_STR (node) = obstack_copy0 (&table->stack, str, len);
- else
- HT_STR (node) = str;
-
- if (++table->nelements * 4 >= table->nslots * 3)
- /* Must expand the string table. */
- ht_expand (table);
-
- return node;
-}
-
-/* Double the size of a hash table, re-hashing existing entries. */
-
-static void
-ht_expand (hash_table *table)
-{
- hashnode *nentries, *p, *limit;
- unsigned int size, sizemask;
-
- size = table->nslots * 2;
- nentries = xcalloc (size, sizeof (hashnode));
- sizemask = size - 1;
-
- p = table->entries;
- limit = p + table->nslots;
- do
- if (*p)
- {
- unsigned int index, hash, hash2;
-
- hash = (*p)->hash_value;
- index = hash & sizemask;
-
- if (nentries[index])
- {
- hash2 = ((hash * 17) & sizemask) | 1;
- do
- {
- index = (index + hash2) & sizemask;
- }
- while (nentries[index]);
- }
- nentries[index] = *p;
- }
- while (++p < limit);
-
- free (table->entries);
- table->entries = nentries;
- table->nslots = size;
-}
-
-/* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
- the node, and V. */
-void
-ht_forall (hash_table *table, ht_cb cb, const void *v)
-{
- hashnode *p, *limit;
-
- p = table->entries;
- limit = p + table->nslots;
- do
- if (*p)
- {
- if ((*cb) (table->pfile, *p, v) == 0)
- break;
- }
- while (++p < limit);
-}
-
-/* Dump allocation statistics to stderr. */
-
-void
-ht_dump_statistics (hash_table *table)
-{
- size_t nelts, nids, overhead, headers;
- size_t total_bytes, longest, sum_of_squares;
- double exp_len, exp_len2, exp2_len;
- hashnode *p, *limit;
-
-#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
- ? (x) \
- : ((x) < 1024*1024*10 \
- ? (x) / 1024 \
- : (x) / (1024*1024))))
-#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
-
- total_bytes = longest = sum_of_squares = nids = 0;
- p = table->entries;
- limit = p + table->nslots;
- do
- if (*p)
- {
- size_t n = HT_LEN (*p);
-
- total_bytes += n;
- sum_of_squares += n * n;
- if (n > longest)
- longest = n;
- nids++;
- }
- while (++p < limit);
-
- nelts = table->nelements;
- overhead = obstack_memory_used (&table->stack) - total_bytes;
- headers = table->nslots * sizeof (hashnode);
-
- fprintf (stderr, "\nString pool\nentries\t\t%lu\n",
- (unsigned long) nelts);
- fprintf (stderr, "identifiers\t%lu (%.2f%%)\n",
- (unsigned long) nids, nids * 100.0 / nelts);
- fprintf (stderr, "slots\t\t%lu\n",
- (unsigned long) table->nslots);
- fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
- SCALE (total_bytes), LABEL (total_bytes),
- SCALE (overhead), LABEL (overhead));
- fprintf (stderr, "table size\t%lu%c\n",
- SCALE (headers), LABEL (headers));
-
- exp_len = (double)total_bytes / (double)nelts;
- exp2_len = exp_len * exp_len;
- exp_len2 = (double) sum_of_squares / (double) nelts;
-
- fprintf (stderr, "coll/search\t%.4f\n",
- (double) table->collisions / (double) table->searches);
- fprintf (stderr, "ins/search\t%.4f\n",
- (double) nelts / (double) table->searches);
- fprintf (stderr, "avg. entry\t%.2f bytes (+/- %.2f)\n",
- exp_len, approx_sqrt (exp_len2 - exp2_len));
- fprintf (stderr, "longest entry\t%lu\n",
- (unsigned long) longest);
-#undef SCALE
-#undef LABEL
-}
-
-/* Return the approximate positive square root of a number N. This is for
- statistical reports, not code generation. */
-static double
-approx_sqrt (double x)
-{
- double s, d;
-
- if (x < 0)
- abort ();
- if (x == 0)
- return 0;
-
- s = x;
- do
- {
- d = (s * s - x) / (2 * s);
- s -= d;
- }
- while (d > .0001);
- return s;
-}
+++ /dev/null
-/* Hash tables.
- 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
-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. */
-
-#ifndef GCC_HASHTABLE_H
-#define GCC_HASHTABLE_H
-
-#if defined(__APPLE__) && defined(__MACH__)
-#include "libiberty/obstack.h"
-#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. */
-typedef struct ht_identifier ht_identifier;
-struct ht_identifier GTY(())
-{
- const unsigned char *str;
- unsigned int len;
- unsigned int hash_value;
-};
-
-#define HT_LEN(NODE) ((NODE)->len)
-#define HT_STR(NODE) ((NODE)->str)
-
-typedef struct ht hash_table;
-typedef struct ht_identifier *hashnode;
-
-enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC, HT_ALLOCED};
-
-/* An identifier hash table for cpplib and the front ends. */
-struct ht
-{
- /* Identifiers are allocated from here. */
- struct obstack stack;
-
- hashnode *entries;
- /* Call back. */
- hashnode (*alloc_node) (hash_table *);
-
- unsigned int nslots; /* Total slots in the entries array. */
- unsigned int nelements; /* Number of live elements. */
-
- /* Link to reader, if any. For the benefit of cpplib. */
- struct cpp_reader *pfile;
-
- /* Table usage statistics. */
- unsigned int searches;
- unsigned int collisions;
-};
-
-/* Initialize the hashtable with 2 ^ order entries. */
-extern hash_table *ht_create (unsigned int order);
-
-/* Frees all memory associated with a hash table. */
-extern void ht_destroy (hash_table *);
-
-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) (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 (hash_table *);
-
-#endif /* GCC_HASHTABLE_H */
/* HOST_WIDE_INT definitions for the GNU compiler.
- Copyright (C) 1998, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1998, 2002, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#define HOST_BITS_PER_INT (CHAR_BIT * SIZEOF_INT)
#define HOST_BITS_PER_LONG (CHAR_BIT * SIZEOF_LONG)
+/* The string that should be inserted into a printf style format to
+ indicate a "long long" operand. */
+#ifndef HOST_LONG_LONG_FORMAT
+#define HOST_LONG_LONG_FORMAT "ll"
+#endif
+
/* 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
# define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%lx%08lx"
# endif
#else
-# define HOST_WIDE_INT_PRINT "ll"
+# define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
# 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"
+# define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
+ "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
#endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
#define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
#error "This line should be impossible to reach"
# endif
# endif
-# 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"
+# define HOST_WIDEST_INT_PRINT_DEC "%" HOST_LONG_LONG_FORMAT "d"
+# define HOST_WIDEST_INT_PRINT_DEC_C "%" HOST_LONG_LONG_FORMAT "dLL"
+# define HOST_WIDEST_INT_PRINT_UNSIGNED "%" HOST_LONG_LONG_FORMAT "u"
+# define HOST_WIDEST_INT_PRINT_HEX "0x%" HOST_LONG_LONG_FORMAT "x"
+# define HOST_WIDEST_INT_PRINT_DOUBLE_HEX \
+ "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
+#endif
+
+/* Define HOST_WIDEST_FAST_INT to the widest integer type supported
+ efficiently in hardware. (That is, the widest integer type that fits
+ in a hardware register.) Normally this is "long" but on some hosts it
+ should be "long long" or "__int64". This is no convenient way to
+ autodect this, so such systems must set a flag in config.host; see there
+ for details. */
+
+#ifdef USE_LONG_LONG_FOR_WIDEST_FAST_INT
+# ifdef HAVE_LONG_LONG
+# define HOST_WIDEST_FAST_INT long long
+# define HOST_BITS_PER_WIDEST_FAST_INT HOST_BITS_PER_LONGLONG
+# elif defined (HAVE___INT64)
+# define HOST_WIDEST_FAST_INT __int64
+# define HOST_BITS_PER_WIDEST_FAST_INT HOST_BITS_PER___INT64
+# else
+# error "Your host said it wantted to use long long or __int64 but neither"
+# error "exist"
+# endif
+#else
+# define HOST_WIDEST_FAST_INT long
+# define HOST_BITS_PER_WIDEST_FAST_INT HOST_BITS_PER_LONG
#endif
#endif /* ! GCC_HWINT_H */
/* 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.
+ Copyright (C) 1993, 1997, 1998, 2000, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, 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 (())
+#include "line-map.h"
+extern struct line_maps line_table;
+
+/* The location for declarations in "<built-in>" */
+#define BUILTINS_LOCATION ((source_location) 2)
+
+#ifdef USE_MAPPED_LOCATION
+
+typedef struct
+{
+ /* The name of the source file involved. */
+ const char *file;
+
+ /* The line-location in the source file. */
+ int line;
+
+ int column;
+} expanded_location;
+
+extern expanded_location expand_location (source_location);
+
+#define UNKNOWN_LOCATION ((source_location) 0)
+typedef source_location location_t; /* deprecated typedef */
+typedef source_location source_locus; /* to be removed */
+
+#else /* ! USE_MAPPED_LOCATION */
+
+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 expanded_location;
typedef struct location_s location_t;
+typedef location_t *source_locus;
+
+#define expand_location(FILELINE) (FILELINE)
+extern location_t unknown_location;
+#define UNKNOWN_LOCATION unknown_location
+
+#endif /* ! USE_MAPPED_LOCATION */
struct file_stack
{
extern const char *main_input_filename;
extern location_t input_location;
-#define input_line (input_location.line)
-#define input_filename (input_location.file)
+#ifdef USE_MAPPED_LOCATION
+extern void push_srcloc (location_t);
+#else /* ! USE_MAPPED_LOCATION */
+extern void push_srcloc (const char *name, int line);
+#endif /* ! USE_MAPPED_LOCATION */
+extern void pop_srcloc (void);
+
+#define LOCATION_FILE(LOC) ((expand_location (LOC)).file)
+#define LOCATION_LINE(LOC) ((expand_location (LOC)).line)
+
+#define input_line LOCATION_LINE(input_location)
+#define input_filename LOCATION_FILE(input_location)
/* 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
/* intl.h - internationalization
- Copyright 1998, 2001, 2003 Free Software Foundation, Inc.
+ Copyright 1998, 2001, 2003, 2004 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
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. */
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#ifndef GCC_INTL_H
#define GCC_INTL_H
# define N_(msgid) msgid
#endif
+#ifndef G_
+# define G_(gmsgid) gmsgid
+#endif
+
+extern const char *open_quote;
+extern const char *close_quote;
+
#endif /* intl.h */
--- /dev/null
+/* 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "internal.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"
+#define LAST_POSSIBLY_BASIC_SOURCE_CHAR 0x7e
+#elif HOST_CHARSET == HOST_CHARSET_EBCDIC
+#define SOURCE_CHARSET "UTF-EBCDIC"
+#define LAST_POSSIBLY_BASIC_SOURCE_CHAR 0xFF
+#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 = XRESIZEVEC (uchar, 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 = XRESIZEVEC (uchar, 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 = XRESIZEVEC (uchar, 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 = (char *) 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, /* FIXME 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, /* FIXME: 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);
+}
+
+/* Destroy iconv(3) descriptors set up by cpp_init_iconv, if necessary. */
+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 for use by a full compiler. C is a character taken
+ from the *basic* source character set, encoded in the host's
+ execution encoding. Convert it to (the target's) execution
+ encoding, and return that value.
+
+ Issues an internal error if C's representation in the narrow
+ execution character set fails to be a single-byte value (C99
+ 5.2.1p3: "The representation of each member of the source and
+ execution character sets shall fit in a byte.") May also issue an
+ internal error if C fails to be a member of the basic source
+ character set (testing this exactly is too hard, especially when
+ the host character set is EBCDIC). */
+cppchar_t
+cpp_host_to_exec_charset (cpp_reader *pfile, cppchar_t c)
+{
+ uchar sbuf[1];
+ struct _cpp_strbuf tbuf;
+
+ /* This test is merely an approximation, but it suffices to catch
+ the most important thing, which is that we don't get handed a
+ character outside the unibyte range of the host character set. */
+ if (c > LAST_POSSIBLY_BASIC_SOURCE_CHAR)
+ {
+ cpp_error (pfile, CPP_DL_ICE,
+ "character 0x%lx is not in the basic source character set\n",
+ (unsigned long)c);
+ return 0;
+ }
+
+ /* Being a character in the unibyte range of the host character set,
+ we can safely splat it into a one-byte buffer and trust that that
+ is a well-formed string. */
+ sbuf[0] = c;
+
+ /* This should never need to reallocate, but just in case... */
+ tbuf.asize = 1;
+ tbuf.text = XNEWVEC (uchar, tbuf.asize);
+ tbuf.len = 0;
+
+ if (!APPLY_CONVERSION (pfile->narrow_cset_desc, sbuf, 1, &tbuf))
+ {
+ cpp_errno (pfile, CPP_DL_ICE, "converting to execution character set");
+ return 0;
+ }
+ if (tbuf.len != 1)
+ {
+ cpp_error (pfile, CPP_DL_ICE,
+ "character 0x%lx is not unibyte in execution character set",
+ (unsigned long)c);
+ return 0;
+ }
+ c = tbuf.text[0];
+ free(tbuf.text);
+ return c;
+}
+
+\f
+
+/* 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;
+}
+
+/* A large table of unicode character information. */
+enum {
+ /* Valid in a C99 identifier? */
+ C99 = 1,
+ /* Valid in a C99 identifier, but not as the first character? */
+ DIG = 2,
+ /* Valid in a C++ identifier? */
+ CXX = 4,
+ /* NFC representation is not valid in an identifier? */
+ CID = 8,
+ /* Might be valid NFC form? */
+ NFC = 16,
+ /* Might be valid NFKC form? */
+ NKC = 32,
+ /* Certain preceding characters might make it not valid NFC/NKFC form? */
+ CTX = 64
+};
+
+static const struct {
+ /* Bitmap of flags above. */
+ unsigned char flags;
+ /* Combining class of the character. */
+ unsigned char combine;
+ /* Last character in the range described by this entry. */
+ unsigned short end;
+} ucnranges[] = {
+#include "ucnid.h"
+};
+
+/* 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. Also update NST for C if returning nonzero. The
+ algorithm is a simple binary search on the table defined in
+ ucnid.h. */
+
+static int
+ucn_valid_in_identifier (cpp_reader *pfile, cppchar_t c,
+ struct normalize_state *nst)
+{
+ int mn, mx, md;
+
+ if (c > 0xFFFF)
+ return 0;
+
+ mn = 0;
+ mx = ARRAY_SIZE (ucnranges) - 1;
+ while (mx != mn)
+ {
+ md = (mn + mx) / 2;
+ if (c <= ucnranges[md].end)
+ mx = md;
+ else
+ mn = md + 1;
+ }
+
+ /* 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 (! (ucnranges[mn].flags & (C99 | CXX)))
+ return 0;
+
+ if (CPP_PEDANTIC (pfile)
+ && ((CPP_OPTION (pfile, c99) && !(ucnranges[mn].flags & C99))
+ || (CPP_OPTION (pfile, cplusplus)
+ && !(ucnranges[mn].flags & CXX))))
+ return 0;
+
+ /* Update NST. */
+ if (ucnranges[mn].combine != 0 && ucnranges[mn].combine < nst->prev_class)
+ nst->level = normalized_none;
+ else if (ucnranges[mn].flags & CTX)
+ {
+ bool safe;
+ cppchar_t p = nst->previous;
+
+ /* Easy cases from Bengali, Oriya, Tamil, Jannada, and Malayalam. */
+ if (c == 0x09BE)
+ safe = p != 0x09C7; /* Use 09CB instead of 09C7 09BE. */
+ else if (c == 0x0B3E)
+ safe = p != 0x0B47; /* Use 0B4B instead of 0B47 0B3E. */
+ else if (c == 0x0BBE)
+ safe = p != 0x0BC6 && p != 0x0BC7; /* Use 0BCA/0BCB instead. */
+ else if (c == 0x0CC2)
+ safe = p != 0x0CC6; /* Use 0CCA instead of 0CC6 0CC2. */
+ else if (c == 0x0D3E)
+ safe = p != 0x0D46 && p != 0x0D47; /* Use 0D4A/0D4B instead. */
+ /* For Hangul, characters in the range AC00-D7A3 are NFC/NFKC,
+ and are combined algorithmically from a sequence of the form
+ 1100-1112 1161-1175 11A8-11C2
+ (if the third is not present, it is treated as 11A7, which is not
+ really a valid character).
+ Unfortunately, C99 allows (only) the NFC form, but C++ allows
+ only the combining characters. */
+ else if (c >= 0x1161 && c <= 0x1175)
+ safe = p < 0x1100 || p > 0x1112;
+ else if (c >= 0x11A8 && c <= 0x11C2)
+ safe = (p < 0xAC00 || p > 0xD7A3 || (p - 0xAC00) % 28 != 0);
+ else
+ {
+ /* Uh-oh, someone updated ucnid.h without updating this code. */
+ cpp_error (pfile, CPP_DL_ICE, "Character %x might not be NFKC", c);
+ safe = true;
+ }
+ if (!safe && c < 0x1161)
+ nst->level = normalized_none;
+ else if (!safe)
+ nst->level = MAX (nst->level, normalized_identifier_C);
+ }
+ else if (ucnranges[mn].flags & NKC)
+ ;
+ else if (ucnranges[mn].flags & NFC)
+ nst->level = MAX (nst->level, normalized_C);
+ else if (ucnranges[mn].flags & CID)
+ nst->level = MAX (nst->level, normalized_identifier_C);
+ else
+ nst->level = normalized_none;
+ nst->previous = c;
+ nst->prev_class = ucnranges[mn].combine;
+
+ /* In C99, UCN digits may not begin identifiers. */
+ if (CPP_OPTION (pfile, c99) && (ucnranges[mn].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 the
+ UCN has not been consumed.
+
+ 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,
+ struct normalize_state *nst)
+{
+ 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
+ {
+ cpp_error (pfile, CPP_DL_ICE, "In _cpp_valid_ucn but not a UCN");
+ length = 4;
+ }
+
+ result = 0;
+ do
+ {
+ c = *str;
+ if (!ISXDIGIT (c))
+ break;
+ str++;
+ result = (result << 4) + hex_value (c);
+ }
+ while (--length && str < limit);
+
+ /* Partial UCNs are not valid in strings, but decompose into
+ multiple tokens in identifiers, so we can't give a helpful
+ error message in that case. */
+ if (length && identifier_pos)
+ return 0;
+
+ *pstr = str;
+ if (length)
+ {
+ 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 && result == 0x24
+ && CPP_OPTION (pfile, dollars_in_ident))
+ {
+ 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");
+ }
+ NORMALIZE_STATE_UPDATE_IDNUM (nst);
+ }
+ else if (identifier_pos)
+ {
+ int validity = ucn_valid_in_identifier (pfile, result, nst);
+
+ 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;
+ struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+
+ from++; /* Skip u/U. */
+ ucn = _cpp_valid_ucn (pfile, &from, limit, 0, &nst);
+
+ 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;
+}
+
+/* Subroutine of convert_hex and convert_oct. N is the representation
+ in the execution character set of a numeric escape; write it into the
+ string buffer TBUF and update the end-of-string pointer therein. WIDE
+ is true if it's a wide string that's being assembled in TBUF. This
+ function issues no diagnostics and never fails. */
+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 = XRESIZEVEC (uchar, 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
+ {
+ /* Note: this code does not handle the case where the target
+ and host have a different number of bits in a byte. */
+ if (tbuf->len + 1 > tbuf->asize)
+ {
+ tbuf->asize += OUTBUF_BLOCK_SIZE;
+ tbuf->text = XRESIZEVEC (uchar, 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
+ {
+ /* diagnostic.c does not support "%03o". When it does, this
+ code can use %03o directly in the diagnostic again. */
+ char buf[32];
+ sprintf(buf, "%03o", (int) c);
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "unknown escape sequence: '\\%s'", buf);
+ }
+ }
+
+ /* 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 = XNEWVEC (uchar, 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 = XRESIZEVEC (uchar, 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 *from,
+ size_t count, cpp_string *to, bool wide)
+{
+ 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, from, count, to, wide);
+
+ 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;
+}
+\f
+/* Convert an identifier denoted by ID and LEN, which might contain
+ UCN escapes, to the source character set, either UTF-8 or
+ UTF-EBCDIC. Assumes that the identifier is actually a valid identifier. */
+cpp_hashnode *
+_cpp_interpret_identifier (cpp_reader *pfile, const uchar *id, size_t len)
+{
+ /* It turns out that a UCN escape always turns into fewer characters
+ than the escape itself, so we can allocate a temporary in advance. */
+ uchar * buf = (uchar *) alloca (len + 1);
+ uchar * bufp = buf;
+ size_t idp;
+
+ for (idp = 0; idp < len; idp++)
+ if (id[idp] != '\\')
+ *bufp++ = id[idp];
+ else
+ {
+ unsigned length = id[idp+1] == 'u' ? 4 : 8;
+ cppchar_t value = 0;
+ size_t bufleft = len - (bufp - buf);
+ int rval;
+
+ idp += 2;
+ while (length && idp < len && ISXDIGIT (id[idp]))
+ {
+ value = (value << 4) + hex_value (id[idp]);
+ idp++;
+ length--;
+ }
+ idp--;
+
+ /* Special case for EBCDIC: if the identifier contains
+ a '$' specified using a UCN, translate it to EBCDIC. */
+ if (value == 0x24)
+ {
+ *bufp++ = '$';
+ continue;
+ }
+
+ rval = one_cppchar_to_utf8 (value, &bufp, &bufleft);
+ if (rval)
+ {
+ errno = rval;
+ cpp_errno (pfile, CPP_DL_ERROR,
+ "converting UCN to source character set");
+ break;
+ }
+ }
+
+ return CPP_HASHNODE (ht_lookup (pfile->hash_table,
+ buf, bufp - buf, HT_ALLOC));
+}
+\f
+/* Convert an input buffer (containing the complete contents of one
+ source file) from INPUT_CHARSET to the source character set. INPUT
+ points to the input buffer, SIZE is its allocated size, and LEN is
+ the length of the meaningful data within the buffer. The
+ translated buffer is returned, and *ST_SIZE is set to the length of
+ the meaningful data within the translated buffer.
+
+ INPUT is expected to have been allocated with xmalloc. This function
+ will either return INPUT, or free it and return a pointer to another
+ xmalloc-allocated block of memory. */
+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 = XNEWVEC (uchar, 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 = XRESIZEVEC (uchar, to.text, to.len + 1);
+
+ /* If the file is using old-school Mac line endings (\r only),
+ terminate with another \r, not an \n, so that we do not mistake
+ the \r\n sequence for a single DOS line ending and erroneously
+ issue the "No newline at end of file" diagnostic. */
+ if (to.text[to.len - 1] == '\r')
+ to.text[to.len] = '\r';
+ else
+ to.text[to.len] = '\n';
+
+ *st_size = to.len;
+ return to.text;
+}
+
+/* Decide on the default encoding to assume for input files. */
+const char *
+_cpp_default_encoding (void)
+{
+ const char *current_encoding = NULL;
+
+ /* We disable this because the default codeset is 7-bit ASCII on
+ most platforms, and this causes conversion failures on every
+ file in GCC that happens to have one of the upper 128 characters
+ in it -- most likely, as part of the name of a contributor.
+ We should definitely recognize in-band markers of file encoding,
+ like:
+ - the appropriate Unicode byte-order mark (FE FF) to recognize
+ UTF16 and UCS4 (in both big-endian and little-endian flavors)
+ and UTF8
+ - a "#i", "#d", "/ *", "//", " #p" or "#p" (for #pragma) to
+ distinguish ASCII and EBCDIC.
+ - now we can parse something like "#pragma GCC encoding <xyz>
+ on the first line, or even Emacs/VIM's mode line tags (there's
+ a problem here in that VIM uses the last line, and Emacs has
+ its more elaborate "local variables" convention).
+ - investigate whether Java has another common convention, which
+ would be friendly to support.
+ (Zack Weinberg and Paolo Bonzini, May 20th 2004) */
+#if defined (HAVE_LOCALE_H) && defined (HAVE_LANGINFO_CODESET) && 0
+ setlocale (LC_CTYPE, "");
+ current_encoding = nl_langinfo (CODESET);
+#endif
+ if (current_encoding == NULL || *current_encoding == '\0')
+ current_encoding = SOURCE_CHARSET;
+
+ return current_encoding;
+}
--- /dev/null
+/* CPP Library. (Directive handling.)
+ Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "internal.h"
+#include "mkdeps.h"
+#include "obstack.h"
+
+/* Stack of conditionals currently in progress
+ (including both successful and failing conditionals). */
+struct if_stack
+{
+ struct if_stack *next;
+ unsigned int line; /* Line where condition started. */
+ 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. */
+};
+
+/* Contains a registered pragma or pragma namespace. */
+typedef void (*pragma_cb) (cpp_reader *);
+struct pragma_entry
+{
+ struct pragma_entry *next;
+ const cpp_hashnode *pragma; /* Name and length. */
+ bool is_nspace;
+ bool allow_expansion;
+ bool is_internal;
+ union {
+ pragma_cb handler;
+ struct pragma_entry *space;
+ } u;
+};
+
+/* Values for the origin field of struct directive. KANDR directives
+ come from traditional (K&R) C. STDC89 directives come from the
+ 1989 C standard. EXTENSION directives are extensions. */
+#define KANDR 0
+#define STDC89 1
+#define EXTENSION 2
+
+/* Values for the flags field of struct directive. COND indicates a
+ conditional; IF_COND an opening conditional. INCL means to treat
+ "..." and <...> as q-char and h-char sequences respectively. IN_I
+ means this directive should be handled even if -fpreprocessed is in
+ effect (these are the directives with callback hooks).
+
+ EXPAND is set on directives that are always macro-expanded. */
+#define COND (1 << 0)
+#define IF_COND (1 << 1)
+#define INCL (1 << 2)
+#define IN_I (1 << 3)
+#define EXPAND (1 << 4)
+
+/* Defines one #-directive, including how to handle it. */
+typedef void (*directive_handler) (cpp_reader *);
+typedef struct directive directive;
+struct directive
+{
+ directive_handler handler; /* Function to handle directive. */
+ const uchar *name; /* Name of directive. */
+ unsigned short length; /* Length of name. */
+ unsigned char origin; /* Origin of directive. */
+ unsigned char flags; /* Flags describing this directive. */
+};
+
+/* Forward declarations. */
+
+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 *, const cpp_token ***);
+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,
+ bool, bool);
+static void register_pragma (cpp_reader *, const char *, const char *,
+ pragma_cb, bool, bool);
+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
+ counts from all the source code I have lying around (egcs and libc
+ CVS as of 1999-05-18, plus grub-0.5.91, linux-2.2.9, and
+ pcmcia-cs-3.0.9). This is no longer important as directive lookup
+ is now O(1). All extensions other than #warning and #include_next
+ are deprecated. The name is where the extension appears to have
+ come from. */
+
+#define DIRECTIVE_TABLE \
+D(define, T_DEFINE = 0, KANDR, IN_I) /* 270554 */ \
+D(include, T_INCLUDE, KANDR, INCL | EXPAND) /* 52262 */ \
+D(endif, T_ENDIF, KANDR, COND) /* 45855 */ \
+D(ifdef, T_IFDEF, KANDR, COND | IF_COND) /* 22000 */ \
+D(if, T_IF, KANDR, COND | IF_COND | EXPAND) /* 18162 */ \
+D(else, T_ELSE, KANDR, COND) /* 9863 */ \
+D(ifndef, T_IFNDEF, KANDR, COND | IF_COND) /* 9675 */ \
+D(undef, T_UNDEF, KANDR, IN_I) /* 4837 */ \
+D(line, T_LINE, KANDR, EXPAND) /* 2465 */ \
+D(elif, T_ELIF, STDC89, COND | EXPAND) /* 610 */ \
+D(error, T_ERROR, STDC89, 0) /* 475 */ \
+D(pragma, T_PRAGMA, STDC89, IN_I) /* 195 */ \
+D(warning, T_WARNING, EXTENSION, 0) /* 22 */ \
+D(include_next, T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND) /* 19 */ \
+D(ident, T_IDENT, EXTENSION, IN_I) /* 11 */ \
+D(import, T_IMPORT, EXTENSION, INCL | EXPAND) /* 0 ObjC */ \
+D(assert, T_ASSERT, EXTENSION, 0) /* 0 SVR4 */ \
+D(unassert, T_UNASSERT, EXTENSION, 0) /* 0 SVR4 */ \
+D(sccs, T_SCCS, EXTENSION, IN_I) /* 0 SVR4? */
+
+/* #sccs is synonymous with #ident. */
+#define do_sccs do_ident
+
+/* Use the table to generate a series of prototypes, an enum for the
+ directive names, and an array of directive handlers. */
+
+#define D(name, t, o, f) static void do_##name (cpp_reader *);
+DIRECTIVE_TABLE
+#undef D
+
+#define D(n, tag, o, f) tag,
+enum
+{
+ DIRECTIVE_TABLE
+ N_DIRECTIVES
+};
+#undef D
+
+#define D(name, t, origin, flags) \
+{ do_##name, (const uchar *) #name, \
+ sizeof #name - 1, origin, flags },
+static const directive dtable[] =
+{
+DIRECTIVE_TABLE
+};
+#undef D
+#undef DIRECTIVE_TABLE
+
+/* Wrapper struct directive for linemarkers.
+ The origin is more or less true - the original K+R cpp
+ did use this notation in its preprocessed output. */
+static const directive linemarker_dir =
+{
+ do_linemarker, U"#", 1, KANDR, IN_I
+};
+
+#define SEEN_EOL() (pfile->cur_token[-1].type == CPP_EOF)
+
+/* Skip any remaining tokens in a directive. */
+static void
+skip_rest_of_line (cpp_reader *pfile)
+{
+ /* Discard all stacked contexts. */
+ while (pfile->context->prev)
+ _cpp_pop_context (pfile);
+
+ /* Sweep up all tokens remaining on the line. */
+ if (! SEEN_EOL ())
+ while (_cpp_lex_token (pfile)->type != CPP_EOF)
+ ;
+}
+
+/* Ensure there are no stray tokens at the end of a directive. */
+static void
+check_eol (cpp_reader *pfile)
+{
+ if (! SEEN_EOL () && _cpp_lex_token (pfile)->type != CPP_EOF)
+ cpp_error (pfile, CPP_DL_PEDWARN, "extra tokens at end of #%s directive",
+ pfile->directive->name);
+}
+
+/* Ensure there are no stray tokens other than comments at the end of
+ a directive, and gather the comments. */
+static const cpp_token **
+check_eol_return_comments (cpp_reader *pfile)
+{
+ size_t c;
+ size_t capacity = 8;
+ const cpp_token **buf;
+
+ buf = XNEWVEC (const cpp_token *, capacity);
+ c = 0;
+ if (! SEEN_EOL ())
+ {
+ while (1)
+ {
+ const cpp_token *tok;
+
+ tok = _cpp_lex_token (pfile);
+ if (tok->type == CPP_EOF)
+ break;
+ if (tok->type != CPP_COMMENT)
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "extra tokens at end of #%s directive",
+ pfile->directive->name);
+ else
+ {
+ if (c + 1 >= capacity)
+ {
+ capacity *= 2;
+ buf = XRESIZEVEC (const cpp_token *, buf, capacity);
+ }
+ buf[c] = tok;
+ ++c;
+ }
+ }
+ }
+ buf[c] = NULL;
+ return buf;
+}
+
+/* Called when entering a directive, _Pragma or command-line directive. */
+static void
+start_directive (cpp_reader *pfile)
+{
+ /* Setup in-directive state. */
+ pfile->state.in_directive = 1;
+ pfile->state.save_comments = 0;
+ pfile->directive_result.type = CPP_PADDING;
+
+ /* Some handlers need the position of the # for diagnostics. */
+ pfile->directive_line = pfile->line_table->highest_line;
+}
+
+/* Called when leaving a directive, _Pragma or command-line directive. */
+static void
+end_directive (cpp_reader *pfile, int skip_line)
+{
+ if (CPP_OPTION (pfile, traditional))
+ {
+ /* Revert change of prepare_directive_trad. */
+ pfile->state.prevent_expansion--;
+
+ if (pfile->directive != &dtable[T_DEFINE])
+ _cpp_remove_overlay (pfile);
+ }
+ /* We don't skip for an assembler #. */
+ else if (skip_line)
+ {
+ skip_rest_of_line (pfile);
+ if (!pfile->keep_tokens)
+ {
+ pfile->cur_run = &pfile->base_run;
+ pfile->cur_token = pfile->base_run.base;
+ }
+ }
+
+ /* Restore state. */
+ pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
+ pfile->state.in_directive = 0;
+ pfile->state.in_expression = 0;
+ pfile->state.angled_headers = 0;
+ pfile->directive = 0;
+}
+
+/* Prepare to handle the directive in pfile->directive. */
+static void
+prepare_directive_trad (cpp_reader *pfile)
+{
+ if (pfile->directive != &dtable[T_DEFINE])
+ {
+ bool no_expand = (pfile->directive
+ && ! (pfile->directive->flags & EXPAND));
+ bool was_skipping = pfile->state.skipping;
+
+ 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_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);
+ }
+
+ /* Stop ISO C from expanding anything. */
+ pfile->state.prevent_expansion++;
+}
+
+/* Output diagnostics for a directive DIR. INDENTED is nonzero if
+ the '#' was indented. */
+static void
+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, 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
+ compilers, directives added by C89 must have their #
+ indented, and directives present in traditional C must not.
+ This is true even of directives in skipped conditional
+ blocks. #elif cannot be used at all. */
+ if (CPP_WTRADITIONAL (pfile))
+ {
+ if (dir == &dtable[T_ELIF])
+ cpp_error (pfile, CPP_DL_WARNING,
+ "suggest not using #elif in traditional C");
+ else if (indented && dir->origin == KANDR)
+ cpp_error (pfile, CPP_DL_WARNING,
+ "traditional C ignores #%s with the # indented",
+ dir->name);
+ else if (!indented && dir->origin != KANDR)
+ cpp_error (pfile, CPP_DL_WARNING,
+ "suggest hiding #%s from traditional C with an indented #",
+ dir->name);
+ }
+}
+
+/* Check if we have a known directive. INDENTED is nonzero if the
+ '#' of the directive was indented. This function is in this file
+ to save unnecessarily exporting dtable etc. to lex.c. Returns
+ nonzero if the line of tokens has been handled, zero if we should
+ continue processing the line. */
+int
+_cpp_handle_directive (cpp_reader *pfile, int indented)
+{
+ const directive *dir = 0;
+ const cpp_token *dname;
+ bool was_parsing_args = pfile->state.parsing_args;
+ bool was_discarding_output = pfile->state.discarding_output;
+ int skip = 1;
+
+ if (was_discarding_output)
+ pfile->state.prevent_expansion = 0;
+
+ if (was_parsing_args)
+ {
+ if (CPP_OPTION (pfile, pedantic))
+ 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;
+ }
+ start_directive (pfile);
+ dname = _cpp_lex_token (pfile);
+
+ if (dname->type == CPP_NAME)
+ {
+ 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. */
+ else if (dname->type == CPP_NUMBER && CPP_OPTION (pfile, lang) != CLK_ASM)
+ {
+ dir = &linemarker_dir;
+ if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, preprocessed)
+ && ! pfile->state.skipping)
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "style of line directive is a GCC extension");
+ }
+
+ if (dir)
+ {
+ /* If we have a directive that is not an opening conditional,
+ invalidate any control macro. */
+ if (! (dir->flags & IF_COND))
+ pfile->mi_valid = false;
+
+ /* Kluge alert. In order to be sure that code like this
+
+ #define HASH #
+ HASH define foo bar
+
+ does not cause '#define foo bar' to get executed when
+ compiled with -save-temps, we recognize directives in
+ -fpreprocessed mode only if the # is in column 1. macro.c
+ puts a space in front of any '#' at the start of a macro. */
+ if (CPP_OPTION (pfile, preprocessed)
+ && (indented || !(dir->flags & IN_I)))
+ {
+ skip = 0;
+ dir = 0;
+ }
+ else
+ {
+ /* In failed conditional groups, all non-conditional
+ directives are ignored. Before doing that, whether
+ skipping or not, we should lex angle-bracketed headers
+ correctly, and maybe output some diagnostics. */
+ pfile->state.angled_headers = dir->flags & INCL;
+ pfile->state.directive_wants_padding = dir->flags & INCL;
+ if (! CPP_OPTION (pfile, preprocessed))
+ directive_diagnostics (pfile, dir, indented);
+ if (pfile->state.skipping && !(dir->flags & COND))
+ dir = 0;
+ }
+ }
+ else if (dname->type == CPP_EOF)
+ ; /* CPP_EOF is the "null directive". */
+ else
+ {
+ /* An unknown directive. Don't complain about it in assembly
+ source: we don't know where the comments are, and # may
+ introduce assembler pseudo-ops. Don't complain about invalid
+ directives in skipped conditional groups (6.10 p4). */
+ if (CPP_OPTION (pfile, lang) == CLK_ASM)
+ skip = 0;
+ else if (!pfile->state.skipping)
+ cpp_error (pfile, CPP_DL_ERROR, "invalid preprocessing directive #%s",
+ cpp_token_as_text (pfile, dname));
+ }
+
+ pfile->directive = dir;
+ if (CPP_OPTION (pfile, traditional))
+ prepare_directive_trad (pfile);
+
+ if (dir)
+ pfile->directive->handler (pfile);
+ else if (skip == 0)
+ _cpp_backup_tokens (pfile, 1);
+
+ end_directive (pfile, skip);
+ if (was_parsing_args)
+ {
+ /* Restore state when within macro args. */
+ pfile->state.parsing_args = 2;
+ pfile->state.prevent_expansion = 1;
+ }
+ if (was_discarding_output)
+ pfile->state.prevent_expansion = 1;
+ return skip;
+}
+
+/* Directive handler wrapper used by the command line option
+ processor. BUF is \n terminated. */
+static void
+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);
+ /* Disgusting hack. */
+ if (dir_no == T_PRAGMA && pfile->buffer->prev)
+ pfile->buffer->file = pfile->buffer->prev->file;
+ start_directive (pfile);
+
+ /* 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);
+ pfile->directive->handler (pfile);
+ end_directive (pfile, 1);
+ if (dir_no == T_PRAGMA)
+ 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 (cpp_reader *pfile)
+{
+ const cpp_token *token = _cpp_lex_token (pfile);
+
+ /* The token immediately after #define must be an identifier. That
+ identifier may not be "defined", per C99 6.10.8p4.
+ In C++, it may not be any of the "named operators" either,
+ per C++98 [lex.digraph], [lex.key].
+ Finally, the identifier may not have been poisoned. (In that case
+ the lexer has issued the error message for us.) */
+
+ if (token->type == CPP_NAME)
+ {
+ cpp_hashnode *node = token->val.node;
+
+ if (node == pfile->spec_nodes.n_defined)
+ 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, 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, CPP_DL_ERROR, "no macro name given in #%s directive",
+ pfile->directive->name);
+ else
+ cpp_error (pfile, CPP_DL_ERROR, "macro names must be identifiers");
+
+ return NULL;
+}
+
+/* Process a #define directive. Most work is done in macro.c. */
+static void
+do_define (cpp_reader *pfile)
+{
+ cpp_hashnode *node = lex_macro_node (pfile);
+
+ if (node)
+ {
+ /* If we have been requested to expand comments into macros,
+ then re-enable saving of comments. */
+ pfile->state.save_comments =
+ ! CPP_OPTION (pfile, discard_comments_in_macro_exp);
+
+ if (_cpp_create_definition (pfile, node))
+ if (pfile->cb.define)
+ pfile->cb.define (pfile, pfile->directive_line, node);
+ }
+}
+
+/* Handle #undef. Mark the identifier NT_VOID in the hash table. */
+static void
+do_undef (cpp_reader *pfile)
+{
+ cpp_hashnode *node = lex_macro_node (pfile);
+
+ if (node)
+ {
+ if (pfile->cb.undef)
+ pfile->cb.undef (pfile, pfile->directive_line, 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);
+
+ _cpp_free_definition (node);
+ }
+ }
+
+ check_eol (pfile);
+}
+
+/* Undefine a single macro/assertion/whatever. */
+
+static int
+undefine_macros (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *h,
+ void *data_p ATTRIBUTE_UNUSED)
+{
+ /* Body of _cpp_free_definition inlined here for speed.
+ Macros and assertions no longer have anything to free. */
+ h->type = NT_VOID;
+ h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED);
+ 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 a malloced filename. */
+static char *
+glue_header_name (cpp_reader *pfile)
+{
+ const cpp_token *token;
+ 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 = XNEWVEC (char, capacity);
+ for (;;)
+ {
+ token = get_token_no_padding (pfile);
+
+ 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) + 2; /* Leading space, terminating \0. */
+ if (total_len + len > capacity)
+ {
+ capacity = (capacity + len) * 2;
+ buffer = XRESIZEVEC (char, buffer, capacity);
+ }
+
+ if (token->flags & PREV_WHITE)
+ buffer[total_len++] = ' ';
+
+ total_len = (cpp_spell_token (pfile, token, (uchar *) &buffer[total_len],
+ true)
+ - (uchar *) buffer);
+ }
+
+ buffer[total_len] = '\0';
+ return buffer;
+}
+
+/* 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 cpp_token ***buf)
+{
+ char *fname;
+ const cpp_token *header;
+
+ /* Allow macro expansion. */
+ header = get_token_no_padding (pfile);
+ if (header->type == CPP_STRING || header->type == CPP_HEADER_NAME)
+ {
+ fname = XNEWVEC (char, 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;
+ }
+ else if (header->type == CPP_LESS)
+ {
+ fname = glue_header_name (pfile);
+ *pangle_brackets = 1;
+ }
+ else
+ {
+ 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;
+ }
+
+ if (buf == NULL || CPP_OPTION (pfile, discard_comments))
+ check_eol (pfile);
+ else
+ {
+ /* If we are not discarding comments, then gather them while
+ doing the eol check. */
+ *buf = check_eol_return_comments (pfile);
+ }
+
+ return fname;
+}
+
+/* Handle #include, #include_next and #import. */
+static void
+do_include_common (cpp_reader *pfile, enum include_type type)
+{
+ const char *fname;
+ int angle_brackets;
+ const cpp_token **buf = NULL;
+
+ /* Re-enable saving of comments if requested, so that the include
+ callback can dump comments which follow #include. */
+ pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
+
+ fname = parse_include (pfile, &angle_brackets, &buf);
+ if (!fname)
+ {
+ if (buf)
+ XDELETEVEC (buf);
+ return;
+ }
+
+ if (!*fname)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "empty filename in #%s",
+ pfile->directive->name);
+ XDELETEVEC (fname);
+ if (buf)
+ XDELETEVEC (buf);
+ return;
+ }
+
+ /* Prevent #include recursion. */
+ if (pfile->line_table->depth >= CPP_STACK_MAX)
+ cpp_error (pfile, CPP_DL_ERROR, "#include nested too deeply");
+ else
+ {
+ /* 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,
+ buf);
+
+ _cpp_stack_include (pfile, fname, angle_brackets, type);
+ }
+
+ XDELETEVEC (fname);
+ if (buf)
+ XDELETEVEC (buf);
+}
+
+static void
+do_include (cpp_reader *pfile)
+{
+ do_include_common (pfile, IT_INCLUDE);
+}
+
+static void
+do_import (cpp_reader *pfile)
+{
+ do_include_common (pfile, IT_IMPORT);
+}
+
+static void
+do_include_next (cpp_reader *pfile)
+{
+ 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.
+ LAST is the last flag seen; 0 if this is the first flag. Return the
+ flag if it is valid, 0 at the end of the directive. Otherwise
+ complain. */
+static unsigned int
+read_flag (cpp_reader *pfile, unsigned int last)
+{
+ const cpp_token *token = _cpp_lex_token (pfile);
+
+ if (token->type == CPP_NUMBER && token->val.str.len == 1)
+ {
+ unsigned int flag = token->val.str.text[0] - '0';
+
+ if (flag > last && flag <= 4
+ && (flag != 4 || last == 3)
+ && (flag != 2 || last == 0))
+ return flag;
+ }
+
+ if (token->type != CPP_EOF)
+ 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. 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 (const uchar *str, unsigned int len, long unsigned int *nump)
+{
+ unsigned long reg = 0;
+ uchar c;
+ while (len--)
+ {
+ c = *str++;
+ if (!ISDIGIT (c))
+ return 1;
+ reg *= 10;
+ reg += c - '0';
+ }
+ *nump = reg;
+ return 0;
+}
+
+/* Interpret #line command.
+ Note that the filename string (if any) is a true string constant
+ (escapes are interpreted), unlike in #line. */
+static void
+do_line (cpp_reader *pfile)
+{
+ const struct line_maps *line_table = pfile->line_table;
+ const struct line_map *map = &line_table->maps[line_table->used - 1];
+
+ /* skip_rest_of_line() may cause line table to be realloc()ed so note down
+ sysp right now. */
+
+ unsigned char map_sysp = map->sysp;
+ const cpp_token *token;
+ const char *new_file = map->to_file;
+ unsigned long new_lineno;
+
+ /* C99 raised the minimum limit on #line numbers. */
+ unsigned int cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
+
+ /* #line commands expand macros. */
+ token = cpp_get_token (pfile);
+ if (token->type != CPP_NUMBER
+ || strtoul_for_line (token->val.str.text, token->val.str.len,
+ &new_lineno))
+ {
+ 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, CPP_DL_PEDWARN, "line number out of range");
+
+ token = cpp_get_token (pfile);
+ if (token->type == CPP_STRING)
+ {
+ cpp_string s = { 0, 0 };
+ if (cpp_interpret_string_notranslate (pfile, &token->val.str, 1,
+ &s, false))
+ new_file = (const char *)s.text;
+ check_eol (pfile);
+ }
+ else if (token->type != CPP_EOF)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename",
+ cpp_token_as_text (pfile, token));
+ return;
+ }
+
+ skip_rest_of_line (pfile);
+ _cpp_do_file_change (pfile, LC_RENAME, new_file, new_lineno,
+ map_sysp);
+}
+
+/* Interpret the # 44 "file" [flags] notation, which has slightly
+ different syntax and semantics from #line: Flags are allowed,
+ and we never complain about the line number being too big. */
+static void
+do_linemarker (cpp_reader *pfile)
+{
+ const struct line_maps *line_table = pfile->line_table;
+ const struct line_map *map = &line_table->maps[line_table->used - 1];
+ const cpp_token *token;
+ const char *new_file = map->to_file;
+ unsigned long new_lineno;
+ unsigned int new_sysp = map->sysp;
+ enum lc_reason reason = LC_RENAME;
+ int flag;
+
+ /* Back up so we can get the number again. Putting this in
+ _cpp_handle_directive risks two calls to _cpp_backup_tokens in
+ some circumstances, which can segfault. */
+ _cpp_backup_tokens (pfile, 1);
+
+ /* #line commands expand macros. */
+ token = cpp_get_token (pfile);
+ if (token->type != CPP_NUMBER
+ || strtoul_for_line (token->val.str.text, token->val.str.len,
+ &new_lineno))
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "\"%s\" after # is not a positive integer",
+ cpp_token_as_text (pfile, token));
+ return;
+ }
+
+ token = cpp_get_token (pfile);
+ if (token->type == CPP_STRING)
+ {
+ cpp_string s = { 0, 0 };
+ if (cpp_interpret_string_notranslate (pfile, &token->val.str,
+ 1, &s, false))
+ new_file = (const char *)s.text;
+
+ new_sysp = 0;
+ flag = read_flag (pfile, 0);
+ if (flag == 1)
+ {
+ reason = LC_ENTER;
+ /* Fake an include for cpp_included (). */
+ _cpp_fake_include (pfile, new_file);
+ flag = read_flag (pfile, flag);
+ }
+ else if (flag == 2)
+ {
+ reason = LC_LEAVE;
+ flag = read_flag (pfile, flag);
+ }
+ if (flag == 3)
+ {
+ new_sysp = 1;
+ flag = read_flag (pfile, flag);
+ if (flag == 4)
+ new_sysp = 2;
+ pfile->buffer->sysp = new_sysp;
+ }
+
+ check_eol (pfile);
+ }
+ else if (token->type != CPP_EOF)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "\"%s\" is not a valid filename",
+ cpp_token_as_text (pfile, token));
+ return;
+ }
+
+ skip_rest_of_line (pfile);
+ _cpp_do_file_change (pfile, reason, new_file, new_lineno, new_sysp);
+}
+
+/* Arrange the file_change callback. pfile->line has changed to
+ FILE_LINE of TO_FILE, for reason REASON. SYSP is 1 for a system
+ header, 2 for a system header that needs to be extern "C" protected,
+ and zero otherwise. */
+void
+_cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason,
+ const char *to_file, unsigned int file_line,
+ unsigned int sysp)
+{
+ const struct line_map *map = linemap_add (pfile->line_table, reason, sysp,
+ to_file, file_line);
+ if (map != NULL)
+ linemap_line_start (pfile->line_table, map->to_line, 127);
+
+ if (pfile->cb.file_change)
+ pfile->cb.file_change (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 (cpp_reader *pfile, int code, int print_dir)
+{
+ if (_cpp_begin_message (pfile, code, pfile->cur_token[-1].src_loc, 0))
+ {
+ if (print_dir)
+ fprintf (stderr, "#%s ", pfile->directive->name);
+ pfile->state.prevent_expansion++;
+ cpp_output_line (pfile, stderr);
+ pfile->state.prevent_expansion--;
+ }
+}
+
+static void
+do_error (cpp_reader *pfile)
+{
+ do_diagnostic (pfile, CPP_DL_ERROR, 1);
+}
+
+static void
+do_warning (cpp_reader *pfile)
+{
+ /* We want #warning diagnostics to be emitted in system headers too. */
+ do_diagnostic (pfile, CPP_DL_WARNING_SYSHDR, 1);
+}
+
+/* Report program identification. */
+static void
+do_ident (cpp_reader *pfile)
+{
+ const cpp_token *str = cpp_get_token (pfile);
+
+ if (str->type != CPP_STRING)
+ cpp_error (pfile, CPP_DL_ERROR, "invalid #%s directive",
+ pfile->directive->name);
+ else if (pfile->cb.ident)
+ pfile->cb.ident (pfile, pfile->directive_line, &str->val.str);
+
+ check_eol (pfile);
+}
+
+/* Lookup a PRAGMA name in a singly-linked CHAIN. Returns the
+ 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 (struct pragma_entry *chain, const cpp_hashnode *pragma)
+{
+ while (chain && chain->pragma != pragma)
+ chain = chain->next;
+
+ return chain;
+}
+
+/* Create and insert a pragma entry for NAME at the beginning of a
+ singly-linked CHAIN. If handler is NULL, it is a namespace,
+ otherwise it is a pragma and its handler. If INTERNAL is true
+ this pragma is being inserted by libcpp itself. */
+static struct pragma_entry *
+insert_pragma_entry (cpp_reader *pfile, struct pragma_entry **chain,
+ const cpp_hashnode *pragma, pragma_cb handler,
+ bool allow_expansion, bool internal)
+{
+ struct pragma_entry *new_entry;
+
+ new_entry = (struct pragma_entry *)
+ _cpp_aligned_alloc (pfile, sizeof (struct pragma_entry));
+ new_entry->pragma = pragma;
+ if (handler)
+ {
+ new_entry->is_nspace = 0;
+ new_entry->u.handler = handler;
+ }
+ else
+ {
+ new_entry->is_nspace = 1;
+ new_entry->u.space = NULL;
+ }
+
+ new_entry->allow_expansion = allow_expansion;
+ new_entry->is_internal = internal;
+ new_entry->next = *chain;
+ *chain = new_entry;
+ return new_entry;
+}
+
+/* Register a pragma NAME in namespace SPACE. If SPACE is null, it
+ goes in the global namespace. HANDLER is the handler it will call,
+ which must be non-NULL. If ALLOW_EXPANSION is set, allow macro
+ expansion while parsing pragma NAME. INTERNAL is true if this is a
+ pragma registered by cpplib itself, false if it is registered via
+ cpp_register_pragma */
+static void
+register_pragma (cpp_reader *pfile, const char *space, const char *name,
+ pragma_cb handler, bool allow_expansion, bool internal)
+{
+ struct pragma_entry **chain = &pfile->pragmas;
+ struct pragma_entry *entry;
+ const cpp_hashnode *node;
+
+ if (!handler)
+ abort ();
+
+ if (space)
+ {
+ node = cpp_lookup (pfile, U space, strlen (space));
+ entry = lookup_pragma_entry (*chain, node);
+ if (!entry)
+ entry = insert_pragma_entry (pfile, chain, node, NULL,
+ allow_expansion, internal);
+ else if (!entry->is_nspace)
+ goto clash;
+ chain = &entry->u.space;
+ }
+
+ /* Check for duplicates. */
+ node = cpp_lookup (pfile, U name, strlen (name));
+ entry = lookup_pragma_entry (*chain, node);
+ if (entry)
+ {
+ if (entry->is_nspace)
+ clash:
+ 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, CPP_DL_ICE, "#pragma %s %s is already registered",
+ space, name);
+ else
+ cpp_error (pfile, CPP_DL_ICE, "#pragma %s is already registered", name);
+ }
+ else
+ insert_pragma_entry (pfile, chain, node, handler, allow_expansion,
+ internal);
+}
+
+/* Register a pragma NAME in namespace SPACE. If SPACE is null, it
+ goes in the global namespace. HANDLER is the handler it will call,
+ which must be non-NULL. If ALLOW_EXPANSION is set, allow macro
+ expansion while parsing pragma NAME. This function is exported
+ from libcpp. */
+void
+cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name,
+ pragma_cb handler, bool allow_expansion)
+{
+ register_pragma (pfile, space, name, handler, allow_expansion, false);
+}
+
+/* Register the pragmas the preprocessor itself handles. */
+void
+_cpp_init_internal_pragmas (cpp_reader *pfile)
+{
+ /* Pragmas in the global namespace. */
+ register_pragma (pfile, 0, "once", do_pragma_once, false, true);
+
+ /* New GCC-specific pragmas should be put in the GCC namespace. */
+ register_pragma (pfile, "GCC", "poison", do_pragma_poison, false, true);
+ register_pragma (pfile, "GCC", "system_header", do_pragma_system_header,
+ false, true);
+ register_pragma (pfile, "GCC", "dependency", do_pragma_dependency,
+ false, true);
+
+ /* Kevin abuse for SDCC. */
+ cpp_register_pragma(pfile, 0, "sdcc_hash", do_pragma_sdcc_hash, false);
+ /* SDCC _asm specific */
+ cpp_register_pragma(pfile, 0, "preproc_asm", do_pragma_preproc_asm, false);
+ /* SDCC specific */
+ cpp_register_pragma(pfile, 0, "pedantic_parse_number", do_pragma_pedantic_parse_number, false);
+}
+
+/* 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++ = (char *) 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.
+
+ The library user has the option of deferring execution of
+ #pragmas not handled by cpplib, in which case they are converted
+ to CPP_PRAGMA tokens and inserted into the output stream. */
+static void
+do_pragma (cpp_reader *pfile)
+{
+ const struct pragma_entry *p = NULL;
+ const cpp_token *token, *pragma_token = pfile->cur_token;
+ unsigned int count = 1;
+
+ /* Save the current position so that defer_pragmas mode can
+ copy the entire current line to a string. It will not work
+ to use _cpp_backup_tokens as that does not reverse buffer->cur. */
+ const uchar *line_start = CPP_BUFFER (pfile)->cur;
+
+ pfile->state.prevent_expansion++;
+
+ token = cpp_get_token (pfile);
+ if (token->type == CPP_NAME)
+ {
+ p = lookup_pragma_entry (pfile->pragmas, token->val.node);
+ if (p && p->is_nspace)
+ {
+ count = 2;
+ token = cpp_get_token (pfile);
+ if (token->type == CPP_NAME)
+ p = lookup_pragma_entry (p->u.space, token->val.node);
+ else
+ p = NULL;
+ }
+ }
+
+ if (p)
+ {
+ if (p->is_internal || !CPP_OPTION (pfile, defer_pragmas))
+ {
+ /* Since the handler below doesn't get the line number, that it
+ might need for diagnostics, make sure it has the right
+ numbers in place. */
+ if (pfile->cb.line_change)
+ (*pfile->cb.line_change) (pfile, pragma_token, false);
+ /* Never expand macros if handling a deferred pragma, since
+ the macro definitions now applicable may be different
+ from those at the point the pragma appeared. */
+ if (p->allow_expansion && !pfile->state.in_deferred_pragma)
+ pfile->state.prevent_expansion--;
+ (*p->u.handler) (pfile);
+ if (p->allow_expansion && !pfile->state.in_deferred_pragma)
+ pfile->state.prevent_expansion++;
+ }
+ else
+ {
+ /* Squirrel away the pragma text. Pragmas are
+ newline-terminated. */
+ const uchar *line_end;
+ uchar *s, c, cc;
+ cpp_string body;
+ cpp_token *ptok;
+
+ for (line_end = line_start; (c = *line_end) != '\n'; line_end++)
+ if (c == '"' || c == '\'')
+ {
+ /* Skip over string literal. */
+ do
+ {
+ cc = *++line_end;
+ if (cc == '\\' && line_end[1] != '\n')
+ line_end++;
+ else if (cc == '\n')
+ {
+ line_end--;
+ break;
+ }
+ }
+ while (cc != c);
+ }
+ else if (c == '/')
+ {
+ if (line_end[1] == '*')
+ {
+ /* Skip over C block comment, unless it is multi-line.
+ When encountering multi-line block comment, terminate
+ the pragma token right before that block comment. */
+ const uchar *le = line_end + 2;
+ while (*le != '\n')
+ if (*le++ == '*' && *le == '/')
+ {
+ line_end = le;
+ break;
+ }
+ if (line_end < le)
+ break;
+ }
+ else if (line_end[1] == '/'
+ && (CPP_OPTION (pfile, cplusplus_comments)
+ || cpp_in_system_header (pfile)))
+ {
+ line_end += 2;
+ while (*line_end != '\n')
+ line_end++;
+ break;
+ }
+ }
+
+ body.len = (line_end - line_start) + 1;
+ s = _cpp_unaligned_alloc (pfile, body.len + 1);
+ memcpy (s, line_start, body.len - 1);
+ s[body.len - 1] = '\n';
+ s[body.len] = '\0';
+ body.text = s;
+
+ /* Create a CPP_PRAGMA token. */
+ ptok = &pfile->directive_result;
+ ptok->src_loc = pragma_token->src_loc;
+ ptok->type = CPP_PRAGMA;
+ ptok->flags = pragma_token->flags | NO_EXPAND;
+ ptok->val.str = body;
+ }
+ }
+ else if (pfile->cb.def_pragma)
+ {
+ _cpp_backup_tokens (pfile, count);
+ pfile->cb.def_pragma (pfile, pfile->directive_line);
+ }
+
+ pfile->state.prevent_expansion--;
+}
+
+/* Handle #pragma once. */
+static void
+do_pragma_once (cpp_reader *pfile)
+{
+ if (pfile->buffer->prev == NULL)
+ 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 (cpp_reader *pfile)
+{
+ const cpp_token *tok;
+ cpp_hashnode *hp;
+
+ pfile->state.poisoned_ok = 1;
+ for (;;)
+ {
+ tok = _cpp_lex_token (pfile);
+ if (tok->type == CPP_EOF)
+ break;
+ if (tok->type != CPP_NAME)
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "invalid #pragma GCC poison directive");
+ break;
+ }
+
+ hp = tok->val.node;
+ if (hp->flags & NODE_POISONED)
+ continue;
+
+ if (hp->type == NT_MACRO)
+ cpp_error (pfile, CPP_DL_WARNING, "poisoning existing macro \"%s\"",
+ NODE_NAME (hp));
+ _cpp_free_definition (hp);
+ hp->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
+ }
+ pfile->state.poisoned_ok = 0;
+}
+
+/* SDCC specific
+ sdcc_hash pragma */
+static void
+do_pragma_sdcc_hash (cpp_reader *pfile)
+{
+ const cpp_token *tok = _cpp_lex_token (pfile);
+
+ if (tok->type == CPP_PLUS)
+ {
+ CPP_OPTION(pfile, allow_naked_hash)++;
+ }
+ else if (tok->type == CPP_MINUS)
+ {
+ CPP_OPTION(pfile, allow_naked_hash)--;
+ }
+ else
+ {
+ 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 (cpp_reader *pfile)
+{
+ const cpp_token *tok = _cpp_lex_token (pfile);
+
+ if (tok->type == CPP_PLUS)
+ {
+ CPP_OPTION(pfile, pedantic_parse_number)++;
+ }
+ else if (tok->type == CPP_MINUS)
+ {
+ CPP_OPTION(pfile, pedantic_parse_number)--;
+ }
+ else
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "invalid #pragma pedantic_parse_number directive, need '+' or '-'");
+ }
+}
+
+/* SDCC _asm specific
+ switch _asm block preprocessing on / off */
+static void
+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)++;
+ }
+ else if (tok->type == CPP_MINUS)
+ {
+ CPP_OPTION(pfile, preproc_asm)--;
+ }
+ else
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "invalid #pragma preproc_asm directive, need '+' or '-'");
+ }
+}
+
+/* Mark the current header as a system header. This will suppress
+ some categories of warnings (notably those from -pedantic). It is
+ intended for use in system libraries that cannot be implemented in
+ conforming C, but cannot be certain that their headers appear in a
+ system include directory. To prevent abuse, it is rejected in the
+ primary source file. */
+static void
+do_pragma_system_header (cpp_reader *pfile)
+{
+ cpp_buffer *buffer = pfile->buffer;
+
+ if (buffer->prev == 0)
+ cpp_error (pfile, CPP_DL_WARNING,
+ "#pragma system_header ignored outside include file");
+ else
+ {
+ check_eol (pfile);
+ skip_rest_of_line (pfile);
+ cpp_make_system_header (pfile, 1, 0);
+ }
+}
+
+/* Check the modified date of the current include file against a specified
+ 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 (cpp_reader *pfile)
+{
+ const char *fname;
+ int angle_brackets, ordering;
+
+ fname = parse_include (pfile, &angle_brackets, NULL);
+ if (!fname)
+ return;
+
+ ordering = _cpp_compare_file_date (pfile, fname, angle_brackets);
+ if (ordering < 0)
+ cpp_error (pfile, CPP_DL_WARNING, "cannot find source file %s", fname);
+ else if (ordering > 0)
+ {
+ 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, CPP_DL_WARNING, 0);
+ }
+ }
+
+ free ((void *) fname);
+}
+
+/* Get a token but skip padding. */
+static const cpp_token *
+get_token_no_padding (cpp_reader *pfile)
+{
+ for (;;)
+ {
+ const cpp_token *result = cpp_get_token (pfile);
+ if (result->type != CPP_PADDING)
+ return result;
+ }
+}
+
+/* Check syntax is "(string-literal)". Returns the string on success,
+ or NULL on failure. */
+static const cpp_token *
+get__Pragma_string (cpp_reader *pfile)
+{
+ const cpp_token *string;
+
+ if (get_token_no_padding (pfile)->type != CPP_OPEN_PAREN)
+ return NULL;
+
+ string = get_token_no_padding (pfile);
+ if (string->type != CPP_STRING && string->type != CPP_WSTRING)
+ return NULL;
+
+ if (get_token_no_padding (pfile)->type != CPP_CLOSE_PAREN)
+ return NULL;
+
+ return string;
+}
+
+/* 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 (cpp_reader *pfile, const cpp_string *in)
+{
+ const unsigned char *src, *limit;
+ char *dest, *result;
+
+ dest = result = (char *) 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 = '\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
+ context to force cpp_get_token to lex, and so skip_rest_of_line
+ doesn't go beyond the end of the text. Also, remember the
+ current lexing position so we can return to it later.
+
+ Something like line-at-a-time lexing should remove the need for
+ this. */
+ {
+ cpp_context *saved_context = pfile->context;
+ cpp_token *saved_cur_token = pfile->cur_token;
+ tokenrun *saved_cur_run = pfile->cur_run;
+
+ pfile->context = XNEW (cpp_context);
+ pfile->context->macro = 0;
+ pfile->context->prev = 0;
+ run_directive (pfile, T_PRAGMA, result, dest - result);
+ XDELETE (pfile->context);
+ pfile->context = saved_context;
+ pfile->cur_token = saved_cur_token;
+ pfile->cur_run = saved_cur_run;
+ }
+
+ /* See above comment. For the moment, we'd like
+
+ token1 _Pragma ("foo") token2
+
+ to be output as
+
+ token1
+ # 7 "file.c"
+ #pragma foo
+ # 7 "file.c"
+ token2
+
+ Getting the line markers is a little tricky. */
+ if (pfile->cb.line_change)
+ pfile->cb.line_change (pfile, pfile->cur_token, false);
+}
+
+/* Handle the _Pragma operator. */
+void
+_cpp_do__Pragma (cpp_reader *pfile)
+{
+ const cpp_token *string = get__Pragma_string (pfile);
+ pfile->directive_result.type = CPP_PADDING;
+
+ if (string)
+ destringize_and_run (pfile, &string->val.str);
+ else
+ cpp_error (pfile, CPP_DL_ERROR,
+ "_Pragma takes a parenthesized string literal");
+}
+
+/* Handle a pragma that the front end deferred until now. */
+void
+cpp_handle_deferred_pragma (cpp_reader *pfile, const cpp_string *s)
+{
+ cpp_context *saved_context = pfile->context;
+ cpp_token *saved_cur_token = pfile->cur_token;
+ tokenrun *saved_cur_run = pfile->cur_run;
+ bool saved_defer_pragmas = CPP_OPTION (pfile, defer_pragmas);
+ void (*saved_line_change) (cpp_reader *, const cpp_token *, int)
+ = pfile->cb.line_change;
+
+ pfile->context = XNEW (cpp_context);
+ pfile->context->macro = 0;
+ pfile->context->prev = 0;
+ pfile->cb.line_change = NULL;
+ pfile->state.in_deferred_pragma = true;
+ CPP_OPTION (pfile, defer_pragmas) = false;
+
+ run_directive (pfile, T_PRAGMA, (const char *)s->text, s->len);
+
+ XDELETE (pfile->context);
+ pfile->context = saved_context;
+ pfile->cur_token = saved_cur_token;
+ pfile->cur_run = saved_cur_run;
+ pfile->cb.line_change = saved_line_change;
+ pfile->state.in_deferred_pragma = false;
+ CPP_OPTION (pfile, defer_pragmas) = saved_defer_pragmas;
+}
+
+/* Handle #ifdef. */
+static void
+do_ifdef (cpp_reader *pfile)
+{
+ int skip = 1;
+
+ if (! pfile->state.skipping)
+ {
+ const cpp_hashnode *node = lex_macro_node (pfile);
+
+ if (node)
+ {
+ skip = node->type != NT_MACRO;
+ _cpp_mark_macro_used (node);
+ check_eol (pfile);
+ }
+ }
+
+ push_conditional (pfile, skip, T_IFDEF, 0);
+}
+
+/* Handle #ifndef. */
+static void
+do_ifndef (cpp_reader *pfile)
+{
+ int skip = 1;
+ const cpp_hashnode *node = 0;
+
+ if (! pfile->state.skipping)
+ {
+ node = lex_macro_node (pfile);
+
+ if (node)
+ {
+ skip = node->type == NT_MACRO;
+ _cpp_mark_macro_used (node);
+ check_eol (pfile);
+ }
+ }
+
+ push_conditional (pfile, skip, T_IFNDEF, node);
+}
+
+/* _cpp_parse_expr puts a macro in a "#if !defined ()" expression in
+ pfile->mi_ind_cmacro so we can handle multiple-include
+ 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 (cpp_reader *pfile)
+{
+ int skip = 1;
+
+ if (! pfile->state.skipping)
+ skip = _cpp_parse_expr (pfile) == false;
+
+ push_conditional (pfile, skip, T_IF, pfile->mi_ind_cmacro);
+}
+
+/* Flip skipping state if appropriate and continue without changing
+ if_stack; this is so that the error message for missing #endif's
+ etc. will point to the original #if. */
+static void
+do_else (cpp_reader *pfile)
+{
+ cpp_buffer *buffer = pfile->buffer;
+ struct if_stack *ifs = buffer->if_stack;
+
+ if (ifs == NULL)
+ cpp_error (pfile, CPP_DL_ERROR, "#else without #if");
+ else
+ {
+ if (ifs->type == T_ELSE)
+ {
+ 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;
+
+ /* Skip any future (erroneous) #elses or #elifs. */
+ pfile->state.skipping = ifs->skip_elses;
+ ifs->skip_elses = true;
+
+ /* Invalidate any controlling macro. */
+ ifs->mi_cmacro = 0;
+
+ /* Only check EOL if was not originally skipping. */
+ if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels))
+ check_eol (pfile);
+ }
+}
+
+/* Handle a #elif directive by not changing if_stack either. See the
+ comment above do_else. */
+static void
+do_elif (cpp_reader *pfile)
+{
+ cpp_buffer *buffer = pfile->buffer;
+ struct if_stack *ifs = buffer->if_stack;
+
+ if (ifs == NULL)
+ cpp_error (pfile, CPP_DL_ERROR, "#elif without #if");
+ else
+ {
+ if (ifs->type == T_ELSE)
+ {
+ 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;
+
+ /* Only evaluate this if we aren't skipping elses. During
+ evaluation, set skipping to false to get lexer warnings. */
+ if (ifs->skip_elses)
+ pfile->state.skipping = 1;
+ else
+ {
+ pfile->state.skipping = 0;
+ pfile->state.skipping = ! _cpp_parse_expr (pfile);
+ ifs->skip_elses = ! pfile->state.skipping;
+ }
+
+ /* Invalidate any controlling macro. */
+ ifs->mi_cmacro = 0;
+ }
+}
+
+/* #endif pops the if stack and resets pfile->state.skipping. */
+static void
+do_endif (cpp_reader *pfile)
+{
+ cpp_buffer *buffer = pfile->buffer;
+ struct if_stack *ifs = buffer->if_stack;
+
+ if (ifs == NULL)
+ cpp_error (pfile, CPP_DL_ERROR, "#endif without #if");
+ else
+ {
+ /* Only check EOL if was not originally skipping. */
+ if (!ifs->was_skipping && CPP_OPTION (pfile, warn_endif_labels))
+ check_eol (pfile);
+
+ /* If potential control macro, we go back outside again. */
+ if (ifs->next == 0 && ifs->mi_cmacro)
+ {
+ pfile->mi_valid = true;
+ pfile->mi_cmacro = ifs->mi_cmacro;
+ }
+
+ buffer->if_stack = ifs->next;
+ pfile->state.skipping = ifs->was_skipping;
+ obstack_free (&pfile->buffer_ob, ifs);
+ }
+}
+
+/* Push an if_stack entry for a preprocessor conditional, and set
+ pfile->state.skipping to SKIP. If TYPE indicates the conditional
+ 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 (cpp_reader *pfile, int skip, int type,
+ const cpp_hashnode *cmacro)
+{
+ struct if_stack *ifs;
+ cpp_buffer *buffer = pfile->buffer;
+
+ ifs = XOBNEW (&pfile->buffer_ob, struct if_stack);
+ ifs->line = pfile->directive_line;
+ ifs->next = buffer->if_stack;
+ ifs->skip_elses = pfile->state.skipping || !skip;
+ ifs->was_skipping = pfile->state.skipping;
+ ifs->type = type;
+ /* This condition is effectively a test for top-of-file. */
+ if (pfile->mi_valid && pfile->mi_cmacro == 0)
+ ifs->mi_cmacro = cmacro;
+ else
+ ifs->mi_cmacro = 0;
+
+ pfile->state.skipping = skip;
+ buffer->if_stack = ifs;
+}
+
+/* Read the tokens of the answer into the macro pool, in a directive
+ of type TYPE. Only commit the memory if we intend it as permanent
+ storage, i.e. the #assert case. Returns 0 on success, and sets
+ ANSWERP to point to the answer. */
+static int
+parse_answer (cpp_reader *pfile, struct answer **answerp, int type)
+{
+ const cpp_token *paren;
+ struct answer *answer;
+ unsigned int acount;
+
+ /* In a conditional, it is legal to not have an open paren. We
+ should save the following token in this case. */
+ paren = cpp_get_token (pfile);
+
+ /* If not a paren, see if we're OK. */
+ if (paren->type != CPP_OPEN_PAREN)
+ {
+ /* In a conditional no answer is a test for any answer. It
+ could be followed by any token. */
+ if (type == T_IF)
+ {
+ _cpp_backup_tokens (pfile, 1);
+ return 0;
+ }
+
+ /* #unassert with no answer is valid - it removes all answers. */
+ if (type == T_UNASSERT && paren->type == CPP_EOF)
+ return 0;
+
+ cpp_error (pfile, CPP_DL_ERROR, "missing '(' after predicate");
+ return 1;
+ }
+
+ for (acount = 0;; acount++)
+ {
+ size_t room_needed;
+ const cpp_token *token = cpp_get_token (pfile);
+ cpp_token *dest;
+
+ if (token->type == CPP_CLOSE_PAREN)
+ break;
+
+ if (token->type == CPP_EOF)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "missing ')' to complete answer");
+ return 1;
+ }
+
+ /* struct answer includes the space for one token. */
+ room_needed = (sizeof (struct answer) + acount * sizeof (cpp_token));
+
+ if (BUFF_ROOM (pfile->a_buff) < room_needed)
+ _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (struct answer));
+
+ dest = &((struct answer *) BUFF_FRONT (pfile->a_buff))->first[acount];
+ *dest = *token;
+
+ /* Drop whitespace at start, for answer equivalence purposes. */
+ if (acount == 0)
+ dest->flags &= ~PREV_WHITE;
+ }
+
+ if (acount == 0)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "predicate's answer is empty");
+ return 1;
+ }
+
+ answer = (struct answer *) BUFF_FRONT (pfile->a_buff);
+ answer->count = acount;
+ answer->next = NULL;
+ *answerp = answer;
+
+ return 0;
+}
+
+/* Parses an assertion directive of type TYPE, returning a pointer to
+ 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 (cpp_reader *pfile, struct answer **answerp, int type)
+{
+ cpp_hashnode *result = 0;
+ const cpp_token *predicate;
+
+ /* We don't expand predicates or answers. */
+ pfile->state.prevent_expansion++;
+
+ *answerp = 0;
+ predicate = cpp_get_token (pfile);
+ if (predicate->type == CPP_EOF)
+ cpp_error (pfile, CPP_DL_ERROR, "assertion without predicate");
+ else if (predicate->type != CPP_NAME)
+ 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);
+ unsigned char *sym = (unsigned char *) alloca (len + 1);
+
+ /* Prefix '#' to get it out of macro namespace. */
+ sym[0] = '#';
+ memcpy (sym + 1, NODE_NAME (predicate->val.node), len);
+ result = cpp_lookup (pfile, sym, len + 1);
+ }
+
+ pfile->state.prevent_expansion--;
+ return result;
+}
+
+/* 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 (cpp_hashnode *node, const struct answer *candidate)
+{
+ unsigned int i;
+ struct answer **result;
+
+ for (result = &node->value.answers; *result; result = &(*result)->next)
+ {
+ struct answer *answer = *result;
+
+ if (answer->count == candidate->count)
+ {
+ for (i = 0; i < answer->count; i++)
+ if (! _cpp_equiv_tokens (&answer->first[i], &candidate->first[i]))
+ break;
+
+ if (i == answer->count)
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* Test an assertion within a preprocessor conditional. Returns
+ 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 (cpp_reader *pfile, unsigned int *value)
+{
+ struct answer *answer;
+ cpp_hashnode *node;
+
+ node = parse_assertion (pfile, &answer, T_IF);
+
+ /* For recovery, an erroneous assertion expression is handled as a
+ failing assertion. */
+ *value = 0;
+
+ if (node)
+ *value = (node->type == NT_ASSERTION &&
+ (answer == 0 || *find_answer (node, answer) != 0));
+ else if (pfile->cur_token[-1].type == CPP_EOF)
+ _cpp_backup_tokens (pfile, 1);
+
+ /* We don't commit the memory for the answer - it's temporary only. */
+ return node == 0;
+}
+
+/* Handle #assert. */
+static void
+do_assert (cpp_reader *pfile)
+{
+ struct answer *new_answer;
+ cpp_hashnode *node;
+
+ node = parse_assertion (pfile, &new_answer, T_ASSERT);
+ if (node)
+ {
+ size_t answer_size;
+
+ /* Place the new answer in the answer list. First check there
+ is not a duplicate. */
+ new_answer->next = 0;
+ if (node->type == NT_ASSERTION)
+ {
+ if (*find_answer (node, new_answer))
+ {
+ cpp_error (pfile, CPP_DL_WARNING, "\"%s\" re-asserted",
+ NODE_NAME (node) + 1);
+ return;
+ }
+ new_answer->next = node->value.answers;
+ }
+
+ answer_size = sizeof (struct answer) + ((new_answer->count - 1)
+ * sizeof (cpp_token));
+ /* Commit or allocate storage for the object. */
+ if (pfile->hash_table->alloc_subobject)
+ {
+ struct answer *temp_answer = new_answer;
+ new_answer = (struct answer *) pfile->hash_table->alloc_subobject
+ (answer_size);
+ memcpy (new_answer, temp_answer, answer_size);
+ }
+ else
+ BUFF_FRONT (pfile->a_buff) += answer_size;
+
+ node->type = NT_ASSERTION;
+ node->value.answers = new_answer;
+ check_eol (pfile);
+ }
+}
+
+/* Handle #unassert. */
+static void
+do_unassert (cpp_reader *pfile)
+{
+ cpp_hashnode *node;
+ struct answer *answer;
+
+ node = parse_assertion (pfile, &answer, T_UNASSERT);
+ /* It isn't an error to #unassert something that isn't asserted. */
+ if (node && node->type == NT_ASSERTION)
+ {
+ if (answer)
+ {
+ struct answer **p = find_answer (node, answer), *temp;
+
+ /* Remove the answer from the list. */
+ temp = *p;
+ if (temp)
+ *p = temp->next;
+
+ /* Did we free the last answer? */
+ if (node->value.answers == 0)
+ node->type = NT_VOID;
+
+ check_eol (pfile);
+ }
+ else
+ _cpp_free_definition (node);
+ }
+
+ /* We don't commit the memory for the answer - it's temporary only. */
+}
+
+/* These are for -D, -U, -A. */
+
+/* Process the string STR as if it appeared as the body of a #define.
+ If STR is just an identifier, define it with value 1.
+ If STR has anything after the identifier, then it should
+ be identifier=definition. */
+void
+cpp_define (cpp_reader *pfile, const char *str)
+{
+ char *buf, *p;
+ size_t count;
+
+ /* Copy the entire option so we can modify it.
+ Change the first "=" in the string to a space. If there is none,
+ tack " 1" on the end. */
+
+ count = strlen (str);
+ buf = (char *) alloca (count + 3);
+ memcpy (buf, str, count);
+
+ p = strchr (str, '=');
+ if (p)
+ buf[p - str] = ' ';
+ else
+ {
+ buf[count++] = ' ';
+ buf[count++] = '1';
+ }
+ buf[count] = '\n';
+
+ run_directive (pfile, T_DEFINE, buf, count);
+}
+
+/* Slight variant of the above for use by initialize_builtins. */
+void
+_cpp_define_builtin (cpp_reader *pfile, const char *str)
+{
+ size_t len = strlen (str);
+ char *buf = (char *) 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 (cpp_reader *pfile, const char *macro)
+{
+ size_t len = strlen (macro);
+ char *buf = (char *) 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 (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 (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 (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 = (char *) alloca (count + 2);
+
+ memcpy (buf, str, count);
+ if (p)
+ {
+ buf[p - str] = '(';
+ buf[count++] = ')';
+ }
+ buf[count] = '\n';
+ str = buf;
+
+ run_directive (pfile, type, str, count);
+}
+
+/* The number of errors for a given reader. */
+unsigned int
+cpp_errors (cpp_reader *pfile)
+{
+ return pfile->errors;
+}
+
+/* The options structure. */
+cpp_options *
+cpp_get_options (cpp_reader *pfile)
+{
+ return &pfile->opts;
+}
+
+/* The callbacks structure. */
+cpp_callbacks *
+cpp_get_callbacks (cpp_reader *pfile)
+{
+ return &pfile->cb;
+}
+
+/* Copy the given callbacks structure to our own. */
+void
+cpp_set_callbacks (cpp_reader *pfile, cpp_callbacks *cb)
+{
+ pfile->cb = *cb;
+}
+
+/* The dependencies structure. (Creates one if it hasn't already been.) */
+struct deps *
+cpp_get_deps (cpp_reader *pfile)
+{
+ if (!pfile->deps)
+ pfile->deps = deps_init ();
+ return pfile->deps;
+}
+
+/* Push a new buffer on the buffer stack. Returns the new buffer; it
+ doesn't fail. It does not generate a file change call back; that
+ is the responsibility of the caller. */
+cpp_buffer *
+cpp_push_buffer (cpp_reader *pfile, const uchar *buffer, size_t len,
+ int from_stage3)
+{
+ cpp_buffer *new_buffer = XOBNEW (&pfile->buffer_ob, cpp_buffer);
+
+ /* Clears, amongst other things, if_stack and mi_cmacro. */
+ memset (new_buffer, 0, sizeof (cpp_buffer));
+
+ new_buffer->next_line = new_buffer->buf = buffer;
+ new_buffer->rlimit = buffer + len;
+ new_buffer->from_stage3 = from_stage3;
+ new_buffer->prev = pfile->buffer;
+ new_buffer->need_line = true;
+
+ pfile->buffer = new_buffer;
+
+ return new_buffer;
+}
+
+/* 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 (cpp_reader *pfile)
+{
+ cpp_buffer *buffer = pfile->buffer;
+ 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, CPP_DL_ERROR, ifs->line, 0,
+ "unterminated #%s", dtable[ifs->type].name);
+
+ /* In case of a missing #endif. */
+ pfile->state.skipping = 0;
+
+ /* _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);
+
+ if (inc)
+ {
+ _cpp_pop_file_buffer (pfile, inc);
+
+ _cpp_do_file_change (pfile, LC_LEAVE, 0, 0, 0);
+ }
+}
+
+/* Enter all recognized directives in the hash table. */
+void
+_cpp_init_directives (cpp_reader *pfile)
+{
+ unsigned int i;
+ cpp_hashnode *node;
+
+ for (i = 0; i < (unsigned int) N_DIRECTIVES; i++)
+ {
+ node = cpp_lookup (pfile, dtable[i].name, dtable[i].length);
+ node->is_directive = 1;
+ node->directive_index = i;
+ }
+}
--- /dev/null
+/* Default error handlers for CPP Library.
+ Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998, 1999, 2000,
+ 2001, 2002, 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
+
+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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 "internal.h"
+
+static void print_location (cpp_reader *, source_location, 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 (cpp_reader *pfile, source_location line, unsigned int col)
+{
+ if (line == 0)
+ fprintf (stderr, "%s: ", progname);
+ else
+ {
+ const struct line_map *map;
+ unsigned int lin;
+
+ map = linemap_lookup (pfile->line_table, line);
+ linemap_print_containing_files (pfile->line_table, map);
+
+ lin = SOURCE_LINE (map, line);
+ if (col == 0)
+ {
+ col = SOURCE_COLUMN (map, line);
+ if (col == 0)
+ col = 1;
+ }
+
+ if (lin == 0)
+ fprintf (stderr, "%s:", map->to_file);
+ else if (CPP_OPTION (pfile, show_column) == 0)
+ fprintf (stderr, "%s:%u:", map->to_file, lin);
+ else
+ fprintf (stderr, "%s:%u:%u:", map->to_file, lin, col);
+
+ fputc (' ', stderr);
+ }
+}
+
+/* Set up for a diagnostic: print the file and line, bump the error
+ counter, etc. SRC_LOC is the logical line number; zero means to print
+ at the location of the previously lexed token, which tends to be
+ the correct place by default. The column number can be specified either
+ using COLUMN or (if COLUMN==0) extracting SOURCE_COLUMN from SRC_LOC.
+ (This may seem redundant, but is useful when pre-scanning (cleaning) a line,
+ when we haven't yet verified whether the current line_map has a
+ big enough max_column_hint.)
+
+ Returns 0 if the error has been suppressed. */
+int
+_cpp_begin_message (cpp_reader *pfile, int code,
+ source_location src_loc, unsigned int column)
+{
+ int level = CPP_DL_EXTRACT (code);
+
+ switch (level)
+ {
+ 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 CPP_DL_WARNING_SYSHDR:
+ if (CPP_OPTION (pfile, warnings_are_errors)
+ || (level == CPP_DL_PEDWARN && CPP_OPTION (pfile, pedantic_errors)))
+ {
+ if (CPP_OPTION (pfile, inhibit_errors))
+ return 0;
+ level = CPP_DL_ERROR;
+ pfile->errors++;
+ }
+ else if (CPP_OPTION (pfile, inhibit_warnings))
+ return 0;
+ break;
+
+ case CPP_DL_ERROR:
+ if (CPP_OPTION (pfile, inhibit_errors))
+ return 0;
+ /* ICEs cannot be inhibited. */
+ case CPP_DL_ICE:
+ pfile->errors++;
+ break;
+ }
+
+ print_location (pfile, src_loc, column);
+ if (CPP_DL_WARNING_P (level))
+ fputs (_("warning: "), stderr);
+ else if (level == CPP_DL_ICE)
+ fputs (_("internal error: "), stderr);
+ else
+ fputs (_("error: "), stderr);
+
+ return 1;
+}
+
+/* Don't remove the blank before do, as otherwise the exgettext
+ script will mistake this as a function definition */
+#define v_message(msgid, ap) \
+ do { vfprintf (stderr, _(msgid), ap); putc ('\n', stderr); } while (0)
+
+/* Exported interface. */
+
+/* Print an error at the location of the previously lexed token. */
+void
+cpp_error (cpp_reader * pfile, int level, const char *msgid, ...)
+{
+ source_location src_loc;
+ va_list ap;
+
+ va_start (ap, msgid);
+
+ if (CPP_OPTION (pfile, client_diagnostic))
+ pfile->cb.error (pfile, level, _(msgid), &ap);
+ else
+ {
+ if (CPP_OPTION (pfile, traditional))
+ {
+ if (pfile->state.in_directive)
+ src_loc = pfile->directive_line;
+ else
+ src_loc = pfile->line_table->highest_line;
+ }
+ else
+ {
+ src_loc = pfile->cur_token[-1].src_loc;
+ }
+
+ if (_cpp_begin_message (pfile, level, src_loc, 0))
+ v_message (msgid, ap);
+ }
+
+ va_end (ap);
+}
+
+/* Print an error at a specific location. */
+void
+cpp_error_with_line (cpp_reader *pfile, int level,
+ source_location src_loc, unsigned int column,
+ const char *msgid, ...)
+{
+ va_list ap;
+
+ va_start (ap, msgid);
+
+ if (_cpp_begin_message (pfile, level, src_loc, column))
+ v_message (msgid, ap);
+
+ va_end (ap);
+}
+
+void
+cpp_errno (cpp_reader *pfile, int level, const char *msgid)
+{
+ if (msgid[0] == '\0')
+ msgid = _("stdout");
+
+ cpp_error (pfile, level, "%s: %s", msgid, xstrerror (errno));
+}
--- /dev/null
+/* Parse C expressions for cpplib.
+ Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2004 Free Software Foundation.
+ Contributed by Per Bothner, 1994.
+
+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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "internal.h"
+
+#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT)
+#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2))
+#define LOW_PART(num_part) (num_part & HALF_MASK)
+#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2))
+
+struct op
+{
+ const cpp_token *token; /* The token forming op (for diagnostics). */
+ cpp_num value; /* The value logically "right" of op. */
+ enum cpp_ttype 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 (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 ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))
+#define CPP_UMINUS ((enum cpp_ttype) (CPP_LAST_CPP_OP + 2))
+
+/* 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, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)
+#define SYNTAX_ERROR2(msgid, arg) \
+ 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 (const uchar *s, size_t len)
+{
+ size_t f = 0, l = 0, i = 0;
+
+ while (len--)
+ switch (s[len])
+ {
+ case 'f': case 'F': f++; break;
+ case 'l': case 'L': l++; break;
+ case 'i': case 'I':
+ case 'j': case 'J': i++; break;
+ default:
+ return 0;
+ }
+
+ if (f + l > 1 || i > 1)
+ return 0;
+
+ return ((i ? CPP_N_IMAGINARY : 0)
+ | (f ? CPP_N_SMALL :
+ l ? CPP_N_LARGE : CPP_N_MEDIUM));
+}
+
+/* Subroutine of cpp_classify_number. S points to an integer suffix
+ of length LEN, possibly zero. Returns 0 for an invalid suffix, or a
+ flag vector describing the suffix. */
+static unsigned int
+interpret_int_suffix (const uchar *s, size_t len)
+{
+ size_t u, l, i;
+
+ u = l = i = 0;
+
+ while (len--)
+ switch (s[len])
+ {
+ case 'u': case 'U': u++; break;
+ case 'i': case 'I':
+ case 'j': case 'J': i++; break;
+ case 'l': case 'L': l++;
+ /* If there are two Ls, they must be adjacent and the same case. */
+ if (l == 2 && s[len] != s[len + 1])
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ if (l > 2 || u > 1 || i > 1)
+ return 0;
+
+ return ((i ? CPP_N_IMAGINARY : 0)
+ | (u ? CPP_N_UNSIGNED : 0)
+ | ((l == 0) ? CPP_N_SMALL
+ : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
+}
+
+/* Categorize numeric constants according to their field (integer,
+ floating point, or invalid), radix (decimal, octal, hexadecimal),
+ and type suffixes. */
+unsigned int
+cpp_classify_number (cpp_reader *pfile, const cpp_token *token)
+{
+ const uchar *str = token->val.str.text;
+ const uchar *limit;
+ unsigned int max_digit, result, radix;
+ enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag;
+
+ /* If the lexer has done its job, length one can only be a single
+ digit. Fast-path this very common case. */
+ if (token->val.str.len == 1)
+ return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL;
+
+ limit = str + token->val.str.len;
+ float_flag = NOT_FLOAT;
+ max_digit = 0;
+ radix = 10;
+
+ /* First, interpret the radix. */
+ if (*str == '0')
+ {
+ radix = 8;
+ str++;
+
+ /* Require at least one hex digit to classify it as hex. */
+ if ((*str == 'x' || *str == 'X')
+ && (str[1] == '.' || ISXDIGIT (str[1])))
+ {
+ radix = 16;
+ str++;
+ }
+ }
+
+ /* Now scan for a well-formed integer or float. */
+ for (;;)
+ {
+ unsigned int c = *str++;
+
+ if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16))
+ {
+ c = hex_value (c);
+ if (c > max_digit)
+ max_digit = c;
+ }
+ else if (c == '.')
+ {
+ if (float_flag == NOT_FLOAT)
+ float_flag = AFTER_POINT;
+ else
+ SYNTAX_ERROR ("too many decimal points in number");
+ }
+ else if ((radix <= 10 && (c == 'e' || c == 'E'))
+ || (radix == 16 && (c == 'p' || c == 'P')))
+ {
+ float_flag = AFTER_EXPON;
+ break;
+ }
+ else
+ {
+ /* Start of suffix. */
+ str--;
+ break;
+ }
+ }
+
+ if (float_flag != NOT_FLOAT && radix == 8)
+ radix = 10;
+
+ if (max_digit >= radix)
+ SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit);
+
+ if (float_flag != NOT_FLOAT)
+ {
+ if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99))
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "use of C99 hexadecimal floating constant");
+
+ if (float_flag == AFTER_EXPON)
+ {
+ if (*str == '+' || *str == '-')
+ str++;
+
+ /* Exponent is decimal, even if string is a hex float. */
+ if (!ISDIGIT (*str))
+ SYNTAX_ERROR ("exponent has no digits");
+
+ do
+ str++;
+ while (ISDIGIT (*str));
+ }
+ else if (radix == 16)
+ SYNTAX_ERROR ("hexadecimal floating constants require an exponent");
+
+ result = interpret_float_suffix (str, limit - str);
+ if (result == 0)
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "invalid suffix \"%.*s\" on floating constant",
+ (int) (limit - str), str);
+ return CPP_N_INVALID;
+ }
+
+ /* Traditional C didn't accept any floating suffixes. */
+ if (limit != str
+ && CPP_WTRADITIONAL (pfile)
+ && ! cpp_sys_macro_p (pfile))
+ cpp_error (pfile, CPP_DL_WARNING,
+ "traditional C rejects the \"%.*s\" suffix",
+ (int) (limit - str), str);
+
+ result |= CPP_N_FLOATING;
+ }
+ else
+ {
+ result = interpret_int_suffix (str, limit - str);
+ if (result == 0)
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "invalid suffix \"%.*s\" on integer constant",
+ (int) (limit - str), str);
+ return CPP_N_INVALID;
+ }
+
+ /* Traditional C only accepted the 'L' suffix.
+ Suppress warning about 'LL' with -Wno-long-long. */
+ if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile))
+ {
+ int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY));
+ int large = (result & CPP_N_WIDTH) == CPP_N_LARGE;
+
+ if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long)))
+ cpp_error (pfile, CPP_DL_WARNING,
+ "traditional C rejects the \"%.*s\" suffix",
+ (int) (limit - str), str);
+ }
+
+ if ((result & CPP_N_WIDTH) == CPP_N_LARGE
+ && ! CPP_OPTION (pfile, c99)
+ && CPP_OPTION (pfile, warn_long_long))
+ 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, CPP_DL_PEDWARN,
+ "imaginary constants are a GCC extension");
+
+ if (radix == 10)
+ result |= CPP_N_DECIMAL;
+ else if (radix == 16)
+ result |= CPP_N_HEX;
+ else
+ result |= CPP_N_OCTAL;
+
+ return result;
+
+ syntax_error:
+ return CPP_N_INVALID;
+}
+
+/* cpp_interpret_integer converts an integer constant into a cpp_num,
+ of precision options->precision.
+
+ We do not provide any interface for decimal->float conversion,
+ 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 (cpp_reader *pfile, const cpp_token *token,
+ unsigned int type)
+{
+ const uchar *p, *end;
+ cpp_num result;
+
+ result.low = 0;
+ result.high = 0;
+ result.unsignedp = !!(type & CPP_N_UNSIGNED);
+ result.overflow = false;
+
+ p = token->val.str.text;
+ end = p + token->val.str.len;
+
+ /* Common case of a single digit. */
+ if (token->val.str.len == 1)
+ result.low = p[0] - '0';
+ else
+ {
+ cpp_num_part max;
+ size_t precision = CPP_OPTION (pfile, precision);
+ unsigned int base = 10, c = 0;
+ bool overflow = false;
+
+ if ((type & CPP_N_RADIX) == CPP_N_OCTAL)
+ {
+ base = 8;
+ p++;
+ }
+ else if ((type & CPP_N_RADIX) == CPP_N_HEX)
+ {
+ base = 16;
+ p += 2;
+ }
+
+ /* We can add a digit to numbers strictly less than this without
+ needing the precision and slowness of double integers. */
+ max = ~(cpp_num_part) 0;
+ if (precision < PART_PRECISION)
+ max >>= PART_PRECISION - precision;
+ max = (max - base + 1) / base + 1;
+
+ for (; p < end; p++)
+ {
+ c = *p;
+
+ if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
+ c = hex_value (c);
+ else
+ break;
+
+ /* Strict inequality for when max is set to zero. */
+ if (result.low < max)
+ result.low = result.low * base + c;
+ else
+ {
+ result = append_digit (result, c, base, precision);
+ overflow |= result.overflow;
+ max = 0;
+ }
+ }
+
+ if (overflow)
+ 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
+ we still honor an explicit U suffix); but we only have
+ traditional semantics in directives. */
+ else if (!result.unsignedp
+ && !(CPP_OPTION (pfile, traditional)
+ && pfile->state.in_directive)
+ && !num_positive (result, precision))
+ {
+ if (base == 10)
+ cpp_error (pfile, CPP_DL_WARNING,
+ "integer constant is so large that it is unsigned");
+ result.unsignedp = true;
+ }
+ }
+
+ return result;
+}
+
+/* Append DIGIT to NUM, a number of PRECISION bits being read in base BASE. */
+static cpp_num
+append_digit (cpp_num num, int digit, int base, size_t precision)
+{
+ cpp_num result;
+ unsigned int shift = 3 + (base == 16);
+ bool overflow;
+ cpp_num_part add_high, add_low;
+
+ /* Multiply by 8 or 16. Catching this overflow here means we don't
+ need to worry about add_high overflowing. */
+ overflow = !!(num.high >> (PART_PRECISION - shift));
+ result.high = num.high << shift;
+ result.low = num.low << shift;
+ result.high |= num.low >> (PART_PRECISION - shift);
+ result.unsignedp = num.unsignedp;
+
+ if (base == 10)
+ {
+ add_low = num.low << 1;
+ add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1));
+ }
+ else
+ add_high = add_low = 0;
+
+ if (add_low + digit < add_low)
+ add_high++;
+ add_low += digit;
+
+ if (result.low + add_low < result.low)
+ add_high++;
+ if (result.high + add_high < result.high)
+ overflow = true;
+
+ result.low += add_low;
+ result.high += add_high;
+ result.overflow = overflow;
+
+ /* The above code catches overflow of a cpp_num type. This catches
+ overflow of the (possibly shorter) target precision. */
+ num.low = result.low;
+ num.high = result.high;
+ result = num_trim (result, precision);
+ if (!num_eq (result, num))
+ result.overflow = true;
+
+ return result;
+}
+
+/* Handle meeting "defined" in a preprocessor expression. */
+static cpp_num
+parse_defined (cpp_reader *pfile)
+{
+ cpp_num result;
+ int paren = 0;
+ cpp_hashnode *node = 0;
+ const cpp_token *token;
+ cpp_context *initial_context = pfile->context;
+
+ /* Don't expand macros. */
+ pfile->state.prevent_expansion++;
+
+ token = cpp_get_token (pfile);
+ if (token->type == CPP_OPEN_PAREN)
+ {
+ paren = 1;
+ token = cpp_get_token (pfile);
+ }
+
+ if (token->type == CPP_NAME)
+ {
+ node = token->val.node;
+ if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "missing ')' after \"defined\"");
+ node = 0;
+ }
+ }
+ else
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "operator \"defined\" requires an identifier");
+ if (token->flags & NAMED_OP)
+ {
+ cpp_token op;
+
+ op.flags = 0;
+ op.type = token->type;
+ 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));
+ }
+ }
+
+ if (node)
+ {
+ if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
+ cpp_error (pfile, CPP_DL_WARNING,
+ "this use of \"defined\" may not be portable");
+
+ _cpp_mark_macro_used (node);
+
+ /* A possible controlling macro of the form #if !defined ().
+ _cpp_parse_expr checks there was no other junk on the line. */
+ pfile->mi_ind_cmacro = node;
+ }
+
+ pfile->state.prevent_expansion--;
+
+ result.unsignedp = false;
+ result.high = 0;
+ result.overflow = false;
+ result.low = node && node->type == NT_MACRO;
+ return result;
+}
+
+/* Convert a token into a CPP_NUMBER (an interpreted preprocessing
+ number or character constant, or the result of the "defined" or "#"
+ operators). */
+static cpp_num
+eval_token (cpp_reader *pfile, const cpp_token *token)
+{
+ cpp_num result;
+ unsigned int temp;
+ int unsignedp = 0;
+
+ result.unsignedp = false;
+ result.overflow = false;
+
+ switch (token->type)
+ {
+ case CPP_NUMBER:
+ temp = cpp_classify_number (pfile, token);
+ switch (temp & CPP_N_CATEGORY)
+ {
+ case CPP_N_FLOATING:
+ 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, CPP_DL_ERROR,
+ "imaginary number in preprocessor expression");
+ break;
+
+ case CPP_N_INVALID:
+ /* Error already issued. */
+ break;
+ }
+ result.high = result.low = 0;
+ break;
+
+ case CPP_WCHAR:
+ case CPP_CHAR:
+ {
+ cppchar_t cc = cpp_interpret_charconst (pfile, token,
+ &temp, &unsignedp);
+
+ result.high = 0;
+ result.low = cc;
+ /* Sign-extend the result if necessary. */
+ if (!unsignedp && (cppchar_signed_t) cc < 0)
+ {
+ if (PART_PRECISION > BITS_PER_CPPCHAR_T)
+ result.low |= ~(~(cpp_num_part) 0
+ >> (PART_PRECISION - BITS_PER_CPPCHAR_T));
+ result.high = ~(cpp_num_part) 0;
+ result = num_trim (result, CPP_OPTION (pfile, precision));
+ }
+ }
+ break;
+
+ case CPP_NAME:
+ if (token->val.node == pfile->spec_nodes.n_defined)
+ return parse_defined (pfile);
+ else if (CPP_OPTION (pfile, cplusplus)
+ && (token->val.node == pfile->spec_nodes.n_true
+ || token->val.node == pfile->spec_nodes.n_false))
+ {
+ result.high = 0;
+ result.low = (token->val.node == pfile->spec_nodes.n_true);
+ }
+ else
+ {
+ result.high = 0;
+ result.low = 0;
+ if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval)
+ cpp_error (pfile, CPP_DL_WARNING, "\"%s\" is not defined",
+ NODE_NAME (token->val.node));
+ }
+ break;
+
+ default: /* CPP_HASH */
+ _cpp_test_assertion (pfile, &temp);
+ result.high = 0;
+ result.low = temp;
+ }
+
+ result.unsignedp = !!unsignedp;
+ return result;
+}
+\f
+/* Operator precedence and flags table.
+
+After an operator is returned from the lexer, if it has priority less
+than the operator on the top of the stack, we reduce the stack by one
+operator and repeat the test. Since equal priorities do not reduce,
+this is naturally right-associative.
+
+We handle left-associative operators by decrementing the priority of
+just-lexed operators by one, but retaining the priority of operators
+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
+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.
+
+The parser assumes all shifted operators require a left operand unless
+the flag NO_L_OPERAND is set. These semantics are automatic; any
+extra semantics need to be handled with operator-specific code. */
+
+/* Flags. If CHECK_PROMOTION, we warn if the effective sign of an
+ operand changes because of integer promotions. */
+#define NO_L_OPERAND (1 << 0)
+#define LEFT_ASSOC (1 << 1)
+#define CHECK_PROMOTION (1 << 2)
+
+/* Operator to priority map. Must be in the same order as the first
+ N entries of enum cpp_ttype. */
+static const struct cpp_operator
+{
+ uchar prio;
+ uchar flags;
+} optab[] =
+{
+ /* EQ */ {0, 0}, /* Shouldn't happen. */
+ /* NOT */ {16, NO_L_OPERAND},
+ /* GREATER */ {12, LEFT_ASSOC | CHECK_PROMOTION},
+ /* LESS */ {12, LEFT_ASSOC | CHECK_PROMOTION},
+ /* PLUS */ {14, LEFT_ASSOC | CHECK_PROMOTION},
+ /* MINUS */ {14, LEFT_ASSOC | CHECK_PROMOTION},
+ /* MULT */ {15, LEFT_ASSOC | CHECK_PROMOTION},
+ /* DIV */ {15, LEFT_ASSOC | CHECK_PROMOTION},
+ /* MOD */ {15, LEFT_ASSOC | CHECK_PROMOTION},
+ /* AND */ {9, LEFT_ASSOC | CHECK_PROMOTION},
+ /* OR */ {7, LEFT_ASSOC | CHECK_PROMOTION},
+ /* XOR */ {8, LEFT_ASSOC | CHECK_PROMOTION},
+ /* RSHIFT */ {13, LEFT_ASSOC},
+ /* LSHIFT */ {13, LEFT_ASSOC},
+
+ /* MIN */ {10, LEFT_ASSOC | CHECK_PROMOTION},
+ /* MAX */ {10, LEFT_ASSOC | CHECK_PROMOTION},
+
+ /* COMPL */ {16, NO_L_OPERAND},
+ /* AND_AND */ {6, LEFT_ASSOC},
+ /* OR_OR */ {5, LEFT_ASSOC},
+ /* QUERY */ {3, 0},
+ /* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION},
+ /* COMMA */ {2, LEFT_ASSOC},
+ /* OPEN_PAREN */ {1, NO_L_OPERAND},
+ /* CLOSE_PAREN */ {0, 0},
+ /* EOF */ {0, 0},
+ /* EQ_EQ */ {11, LEFT_ASSOC},
+ /* NOT_EQ */ {11, LEFT_ASSOC},
+ /* GREATER_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION},
+ /* LESS_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION},
+ /* UPLUS */ {16, NO_L_OPERAND},
+ /* UMINUS */ {16, NO_L_OPERAND}
+};
+
+/* Parse and evaluate a C expression, reading from PFILE.
+ Returns the truth value of the expression.
+
+ The implementation is an operator precedence parser, i.e. a
+ bottom-up parser, using a stack for not-yet-reduced tokens.
+
+ The stack base is op_stack, and the current stack pointer is 'top'.
+ There is a stack element for each operator (only), and the most
+ recently pushed operator is 'top->op'. An operand (value) is
+ stored in the 'value' field of the stack element of the operator
+ that precedes it. */
+bool
+_cpp_parse_expr (cpp_reader *pfile)
+{
+ struct op *top = pfile->op_stack;
+ unsigned int lex_count;
+ bool saw_leading_not, want_value = true;
+
+ pfile->state.skip_eval = 0;
+
+ /* Set up detection of #if ! defined(). */
+ pfile->mi_ind_cmacro = 0;
+ saw_leading_not = false;
+ lex_count = 0;
+
+ /* Lowest priority operator prevents further reductions. */
+ top->op = CPP_EOF;
+
+ for (;;)
+ {
+ struct op op;
+
+ lex_count++;
+ op.token = cpp_get_token (pfile);
+ op.op = op.token->type;
+
+ switch (op.op)
+ {
+ /* These tokens convert into values. */
+ case CPP_NUMBER:
+ case CPP_CHAR:
+ case CPP_WCHAR:
+ case CPP_NAME:
+ case CPP_HASH:
+ if (!want_value)
+ SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
+ cpp_token_as_text (pfile, op.token));
+ want_value = false;
+ top->value = eval_token (pfile, op.token);
+ continue;
+
+ case CPP_NOT:
+ saw_leading_not = lex_count == 1;
+ break;
+ case CPP_PLUS:
+ if (want_value)
+ op.op = CPP_UPLUS;
+ break;
+ case CPP_MINUS:
+ if (want_value)
+ op.op = CPP_UMINUS;
+ break;
+
+ default:
+ if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ)
+ SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions",
+ cpp_token_as_text (pfile, op.token));
+ break;
+ }
+
+ /* Check we have a value or operator as appropriate. */
+ if (optab[op.op].flags & NO_L_OPERAND)
+ {
+ if (!want_value)
+ SYNTAX_ERROR2 ("missing binary operator before token \"%s\"",
+ cpp_token_as_text (pfile, op.token));
+ }
+ else if (want_value)
+ {
+ /* 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);
+ if (!top)
+ goto syntax_error;
+
+ if (op.op == CPP_EOF)
+ break;
+
+ switch (op.op)
+ {
+ case CPP_CLOSE_PAREN:
+ continue;
+ case CPP_OR_OR:
+ if (!num_zerop (top->value))
+ pfile->state.skip_eval++;
+ break;
+ case CPP_AND_AND:
+ case CPP_QUERY:
+ if (num_zerop (top->value))
+ pfile->state.skip_eval++;
+ break;
+ case CPP_COLON:
+ if (top->op != CPP_QUERY)
+ SYNTAX_ERROR (" ':' without preceding '?'");
+ if (!num_zerop (top[-1].value)) /* Was '?' condition true? */
+ pfile->state.skip_eval++;
+ else
+ pfile->state.skip_eval--;
+ default:
+ break;
+ }
+
+ want_value = true;
+
+ /* Check for and handle stack overflow. */
+ if (++top == pfile->op_limit)
+ top = _cpp_expand_op_stack (pfile);
+
+ top->op = op.op;
+ top->token = op.token;
+ }
+
+ /* The controlling macro expression is only valid if we called lex 3
+ times: <!> <defined expression> and <EOF>. push_conditional ()
+ checks that we are at top-of-file. */
+ if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
+ pfile->mi_ind_cmacro = 0;
+
+ if (top != pfile->op_stack)
+ {
+ cpp_error (pfile, CPP_DL_ICE, "unbalanced stack in #if");
+ syntax_error:
+ return false; /* Return false on syntax error. */
+ }
+
+ return !num_zerop (top->value);
+}
+
+/* Reduce the operator / value stack if possible, in preparation for
+ pushing operator OP. Returns NULL on error, otherwise the top of
+ the stack. */
+static struct 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, CPP_DL_ICE, "impossible operator '%u'", top->op);
+ return 0;
+ }
+
+ if (op == CPP_OPEN_PAREN)
+ return top;
+
+ /* Decrement the priority of left-associative operators to force a
+ reduction with operators of otherwise equal priority. */
+ prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0);
+ while (prio < optab[top->op].prio)
+ {
+ if (CPP_OPTION (pfile, warn_num_sign_change)
+ && optab[top->op].flags & CHECK_PROMOTION)
+ check_promotion (pfile, top);
+
+ switch (top->op)
+ {
+ case CPP_UPLUS:
+ case CPP_UMINUS:
+ case CPP_NOT:
+ case CPP_COMPL:
+ top[-1].value = num_unary_op (pfile, top->value, top->op);
+ break;
+
+ case CPP_PLUS:
+ case CPP_MINUS:
+ case CPP_RSHIFT:
+ case CPP_LSHIFT:
+ case CPP_MIN:
+ case CPP_MAX:
+ case CPP_COMMA:
+ top[-1].value = num_binary_op (pfile, top[-1].value,
+ top->value, top->op);
+ break;
+
+ case CPP_GREATER:
+ case CPP_LESS:
+ case CPP_GREATER_EQ:
+ case CPP_LESS_EQ:
+ top[-1].value
+ = num_inequality_op (pfile, top[-1].value, top->value, top->op);
+ break;
+
+ case CPP_EQ_EQ:
+ case CPP_NOT_EQ:
+ top[-1].value
+ = num_equality_op (pfile, top[-1].value, top->value, top->op);
+ break;
+
+ case CPP_AND:
+ case CPP_OR:
+ case CPP_XOR:
+ top[-1].value
+ = num_bitwise_op (pfile, top[-1].value, top->value, top->op);
+ break;
+
+ case CPP_MULT:
+ top[-1].value = num_mul (pfile, top[-1].value, top->value);
+ break;
+
+ case CPP_DIV:
+ case CPP_MOD:
+ top[-1].value = num_div_op (pfile, top[-1].value,
+ top->value, top->op);
+ break;
+
+ case CPP_OR_OR:
+ top--;
+ if (!num_zerop (top->value))
+ pfile->state.skip_eval--;
+ top->value.low = (!num_zerop (top->value)
+ || !num_zerop (top[1].value));
+ top->value.high = 0;
+ top->value.unsignedp = false;
+ top->value.overflow = false;
+ continue;
+
+ case CPP_AND_AND:
+ top--;
+ if (num_zerop (top->value))
+ pfile->state.skip_eval--;
+ top->value.low = (!num_zerop (top->value)
+ && !num_zerop (top[1].value));
+ top->value.high = 0;
+ top->value.unsignedp = false;
+ top->value.overflow = false;
+ continue;
+
+ case CPP_OPEN_PAREN:
+ if (op != CPP_CLOSE_PAREN)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "missing ')' in expression");
+ return 0;
+ }
+ top--;
+ top->value = top[1].value;
+ return top;
+
+ case CPP_COLON:
+ top -= 2;
+ if (!num_zerop (top->value))
+ {
+ pfile->state.skip_eval--;
+ top->value = top[1].value;
+ }
+ else
+ top->value = top[2].value;
+ top->value.unsignedp = (top[1].value.unsignedp
+ || top[2].value.unsignedp);
+ continue;
+
+ case CPP_QUERY:
+ cpp_error (pfile, CPP_DL_ERROR, "'?' without following ':'");
+ return 0;
+
+ default:
+ goto bad_op;
+ }
+
+ top--;
+ if (top->value.overflow && !pfile->state.skip_eval)
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "integer overflow in preprocessor expression");
+ }
+
+ if (op == CPP_CLOSE_PAREN)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "missing '(' in expression");
+ return 0;
+ }
+
+ return top;
+}
+
+/* Returns the position of the old top of stack after expansion. */
+struct op *
+_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 = XRESIZEVEC (struct op, pfile->op_stack, new_size);
+ pfile->op_limit = pfile->op_stack + new_size;
+
+ return pfile->op_stack + old_size;
+}
+
+/* Emits a warning if the effective sign of either operand of OP
+ changes because of integer promotions. */
+static void
+check_promotion (cpp_reader *pfile, const struct op *op)
+{
+ if (op->value.unsignedp == op[-1].value.unsignedp)
+ return;
+
+ if (op->value.unsignedp)
+ {
+ if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision)))
+ 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, 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 (cpp_num num, size_t precision)
+{
+ if (precision > PART_PRECISION)
+ {
+ precision -= PART_PRECISION;
+ if (precision < PART_PRECISION)
+ num.high &= ((cpp_num_part) 1 << precision) - 1;
+ }
+ else
+ {
+ if (precision < PART_PRECISION)
+ num.low &= ((cpp_num_part) 1 << precision) - 1;
+ num.high = 0;
+ }
+
+ return num;
+}
+
+/* True iff A (presumed signed) >= 0. */
+static bool
+num_positive (cpp_num num, size_t precision)
+{
+ if (precision > PART_PRECISION)
+ {
+ precision -= PART_PRECISION;
+ return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
+ }
+
+ return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
+}
+
+/* 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 (cpp_num num, size_t precision)
+{
+ if (!num.unsignedp)
+ {
+ if (precision > PART_PRECISION)
+ {
+ precision -= PART_PRECISION;
+ if (precision < PART_PRECISION
+ && (num.high & (cpp_num_part) 1 << (precision - 1)))
+ num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
+ }
+ else if (num.low & (cpp_num_part) 1 << (precision - 1))
+ {
+ if (precision < PART_PRECISION)
+ num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision));
+ num.high = ~(cpp_num_part) 0;
+ }
+ }
+
+ return num;
+}
+
+/* Returns the negative of NUM. */
+static cpp_num
+num_negate (cpp_num num, size_t precision)
+{
+ cpp_num copy;
+
+ copy = num;
+ num.high = ~num.high;
+ num.low = ~num.low;
+ if (++num.low == 0)
+ num.high++;
+ num = num_trim (num, precision);
+ num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num));
+
+ return num;
+}
+
+/* Returns true if A >= B. */
+static bool
+num_greater_eq (cpp_num pa, cpp_num pb, size_t precision)
+{
+ bool unsignedp;
+
+ unsignedp = pa.unsignedp || pb.unsignedp;
+
+ if (!unsignedp)
+ {
+ /* Both numbers have signed type. If they are of different
+ sign, the answer is the sign of A. */
+ unsignedp = num_positive (pa, precision);
+
+ if (unsignedp != num_positive (pb, precision))
+ return unsignedp;
+
+ /* Otherwise we can do an unsigned comparison. */
+ }
+
+ return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low);
+}
+
+/* Returns LHS OP RHS, where OP is a bit-wise operation. */
+static cpp_num
+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;
+
+ /* As excess precision is zeroed, there is no need to num_trim () as
+ these operations cannot introduce a set bit there. */
+ if (op == CPP_AND)
+ {
+ lhs.low &= rhs.low;
+ lhs.high &= rhs.high;
+ }
+ else if (op == CPP_OR)
+ {
+ lhs.low |= rhs.low;
+ lhs.high |= rhs.high;
+ }
+ else
+ {
+ lhs.low ^= rhs.low;
+ lhs.high ^= rhs.high;
+ }
+
+ return lhs;
+}
+
+/* Returns LHS OP RHS, where OP is an inequality. */
+static cpp_num
+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));
+
+ if (op == CPP_GREATER_EQ)
+ lhs.low = gte;
+ else if (op == CPP_LESS)
+ lhs.low = !gte;
+ else if (op == CPP_GREATER)
+ lhs.low = gte && !num_eq (lhs, rhs);
+ else /* CPP_LESS_EQ. */
+ lhs.low = !gte || num_eq (lhs, rhs);
+
+ lhs.high = 0;
+ lhs.overflow = false;
+ lhs.unsignedp = false;
+ return lhs;
+}
+
+/* Returns LHS OP RHS, where OP is == or !=. */
+static cpp_num
+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);
+ if (op == CPP_NOT_EQ)
+ eq = !eq;
+ lhs.low = eq;
+ lhs.high = 0;
+ lhs.overflow = false;
+ lhs.unsignedp = false;
+ return lhs;
+}
+
+/* Shift NUM, of width PRECISION, right by N bits. */
+static cpp_num
+num_rshift (cpp_num num, size_t precision, size_t n)
+{
+ cpp_num_part sign_mask;
+ bool x = num_positive (num, precision);
+
+ if (num.unsignedp || x)
+ sign_mask = 0;
+ else
+ sign_mask = ~(cpp_num_part) 0;
+
+ if (n >= precision)
+ num.high = num.low = sign_mask;
+ else
+ {
+ /* Sign-extend. */
+ if (precision < PART_PRECISION)
+ num.high = sign_mask, num.low |= sign_mask << precision;
+ else if (precision < 2 * PART_PRECISION)
+ num.high |= sign_mask << (precision - PART_PRECISION);
+
+ if (n >= PART_PRECISION)
+ {
+ n -= PART_PRECISION;
+ num.low = num.high;
+ num.high = sign_mask;
+ }
+
+ if (n)
+ {
+ num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
+ num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
+ }
+ }
+
+ num = num_trim (num, precision);
+ num.overflow = false;
+ return num;
+}
+
+/* Shift NUM, of width PRECISION, left by N bits. */
+static cpp_num
+num_lshift (cpp_num num, size_t precision, size_t n)
+{
+ if (n >= precision)
+ {
+ num.overflow = !num.unsignedp && !num_zerop (num);
+ num.high = num.low = 0;
+ }
+ else
+ {
+ cpp_num orig, maybe_orig;
+ size_t m = n;
+
+ orig = num;
+ if (m >= PART_PRECISION)
+ {
+ m -= PART_PRECISION;
+ num.high = num.low;
+ num.low = 0;
+ }
+ if (m)
+ {
+ num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
+ num.low <<= m;
+ }
+ num = num_trim (num, precision);
+
+ if (num.unsignedp)
+ num.overflow = false;
+ else
+ {
+ maybe_orig = num_rshift (num, precision, n);
+ num.overflow = !num_eq (orig, maybe_orig);
+ }
+ }
+
+ return num;
+}
+
+/* The four unary operators: +, -, ! and ~. */
+static cpp_num
+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, CPP_DL_WARNING,
+ "traditional C rejects the unary plus operator");
+ num.overflow = false;
+ break;
+
+ case CPP_UMINUS:
+ num = num_negate (num, CPP_OPTION (pfile, precision));
+ break;
+
+ case CPP_COMPL:
+ num.high = ~num.high;
+ num.low = ~num.low;
+ num = num_trim (num, CPP_OPTION (pfile, precision));
+ num.overflow = false;
+ break;
+
+ default: /* case CPP_NOT: */
+ num.low = num_zerop (num);
+ num.high = 0;
+ num.overflow = false;
+ num.unsignedp = false;
+ break;
+ }
+
+ return num;
+}
+
+/* The various binary operators. */
+static cpp_num
+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);
+ bool gte;
+ size_t n;
+
+ switch (op)
+ {
+ /* Shifts. */
+ case CPP_LSHIFT:
+ case CPP_RSHIFT:
+ if (!rhs.unsignedp && !num_positive (rhs, precision))
+ {
+ /* A negative shift is a positive shift the other way. */
+ if (op == CPP_LSHIFT)
+ op = CPP_RSHIFT;
+ else
+ op = CPP_LSHIFT;
+ rhs = num_negate (rhs, precision);
+ }
+ if (rhs.high)
+ n = ~0; /* Maximal. */
+ else
+ n = rhs.low;
+ if (op == CPP_LSHIFT)
+ lhs = num_lshift (lhs, precision, n);
+ else
+ lhs = num_rshift (lhs, precision, n);
+ break;
+
+ /* Min / Max. */
+ case CPP_MIN:
+ case CPP_MAX:
+ {
+ bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+
+ gte = num_greater_eq (lhs, rhs, precision);
+ if (op == CPP_MIN)
+ gte = !gte;
+ if (!gte)
+ lhs = rhs;
+ lhs.unsignedp = unsignedp;
+ }
+ break;
+
+ /* Arithmetic. */
+ case CPP_MINUS:
+ rhs = num_negate (rhs, precision);
+ case CPP_PLUS:
+ result.low = lhs.low + rhs.low;
+ result.high = lhs.high + rhs.high;
+ if (result.low < lhs.low)
+ result.high++;
+ result.unsignedp = lhs.unsignedp || rhs.unsignedp;
+ result.overflow = false;
+
+ result = num_trim (result, precision);
+ if (!result.unsignedp)
+ {
+ bool lhsp = num_positive (lhs, precision);
+ result.overflow = (lhsp == num_positive (rhs, precision)
+ && lhsp != num_positive (result, precision));
+ }
+ return result;
+
+ /* Comma. */
+ default: /* case CPP_COMMA: */
+ 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;
+ }
+
+ return lhs;
+}
+
+/* Multiplies two unsigned cpp_num_parts to give a cpp_num. This
+ cannot overflow. */
+static cpp_num
+num_part_mul (cpp_num_part lhs, cpp_num_part rhs)
+{
+ cpp_num result;
+ cpp_num_part middle[2], temp;
+
+ result.low = LOW_PART (lhs) * LOW_PART (rhs);
+ result.high = HIGH_PART (lhs) * HIGH_PART (rhs);
+
+ middle[0] = LOW_PART (lhs) * HIGH_PART (rhs);
+ middle[1] = HIGH_PART (lhs) * LOW_PART (rhs);
+
+ temp = result.low;
+ result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2);
+ if (result.low < temp)
+ result.high++;
+
+ temp = result.low;
+ result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2);
+ if (result.low < temp)
+ result.high++;
+
+ result.high += HIGH_PART (middle[0]);
+ result.high += HIGH_PART (middle[1]);
+ result.unsignedp = true;
+ result.overflow = false;
+
+ return result;
+}
+
+/* Multiply two preprocessing numbers. */
+static cpp_num
+num_mul (cpp_reader *pfile, cpp_num lhs, cpp_num rhs)
+{
+ cpp_num result, temp;
+ bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+ bool overflow, negate = false;
+ size_t precision = CPP_OPTION (pfile, precision);
+
+ /* Prepare for unsigned multiplication. */
+ if (!unsignedp)
+ {
+ if (!num_positive (lhs, precision))
+ negate = !negate, lhs = num_negate (lhs, precision);
+ if (!num_positive (rhs, precision))
+ negate = !negate, rhs = num_negate (rhs, precision);
+ }
+
+ overflow = lhs.high && rhs.high;
+ result = num_part_mul (lhs.low, rhs.low);
+
+ temp = num_part_mul (lhs.high, rhs.low);
+ result.high += temp.low;
+ if (temp.high)
+ overflow = true;
+
+ temp = num_part_mul (lhs.low, rhs.high);
+ result.high += temp.low;
+ if (temp.high)
+ overflow = true;
+
+ temp.low = result.low, temp.high = result.high;
+ result = num_trim (result, precision);
+ if (!num_eq (result, temp))
+ overflow = true;
+
+ if (negate)
+ result = num_negate (result, precision);
+
+ if (unsignedp)
+ result.overflow = false;
+ else
+ result.overflow = overflow || (num_positive (result, precision) ^ !negate
+ && !num_zerop (result));
+ result.unsignedp = unsignedp;
+
+ return result;
+}
+
+/* Divide two preprocessing numbers, returning the answer or the
+ remainder depending upon OP. */
+static cpp_num
+num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op)
+{
+ cpp_num result, sub;
+ cpp_num_part mask;
+ bool unsignedp = lhs.unsignedp || rhs.unsignedp;
+ bool negate = false, lhs_neg = false;
+ size_t i, precision = CPP_OPTION (pfile, precision);
+
+ /* Prepare for unsigned division. */
+ if (!unsignedp)
+ {
+ if (!num_positive (lhs, precision))
+ negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision);
+ if (!num_positive (rhs, precision))
+ negate = !negate, rhs = num_negate (rhs, precision);
+ }
+
+ /* Find the high bit. */
+ if (rhs.high)
+ {
+ i = precision - 1;
+ mask = (cpp_num_part) 1 << (i - PART_PRECISION);
+ for (; ; i--, mask >>= 1)
+ if (rhs.high & mask)
+ break;
+ }
+ else if (rhs.low)
+ {
+ if (precision > PART_PRECISION)
+ i = precision - PART_PRECISION - 1;
+ else
+ i = precision - 1;
+ mask = (cpp_num_part) 1 << i;
+ for (; ; i--, mask >>= 1)
+ if (rhs.low & mask)
+ break;
+ }
+ else
+ {
+ if (!pfile->state.skip_eval)
+ cpp_error (pfile, CPP_DL_ERROR, "division by zero in #if");
+ return lhs;
+ }
+
+ /* First nonzero bit of RHS is bit I. Do naive division by
+ shifting the RHS fully left, and subtracting from LHS if LHS is
+ at least as big, and then repeating but with one less shift.
+ This is not very efficient, but is easy to understand. */
+
+ rhs.unsignedp = true;
+ lhs.unsignedp = true;
+ i = precision - i - 1;
+ sub = num_lshift (rhs, precision, i);
+
+ result.high = result.low = 0;
+ for (;;)
+ {
+ if (num_greater_eq (lhs, sub, precision))
+ {
+ lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS);
+ if (i >= PART_PRECISION)
+ result.high |= (cpp_num_part) 1 << (i - PART_PRECISION);
+ else
+ result.low |= (cpp_num_part) 1 << i;
+ }
+ if (i-- == 0)
+ break;
+ sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1));
+ sub.high >>= 1;
+ }
+
+ /* We divide so that the remainder has the sign of the LHS. */
+ if (op == CPP_DIV)
+ {
+ result.unsignedp = unsignedp;
+ result.overflow = false;
+ if (!unsignedp)
+ {
+ if (negate)
+ result = num_negate (result, precision);
+ result.overflow = num_positive (result, precision) ^ !negate;
+ }
+
+ return result;
+ }
+
+ /* CPP_MOD. */
+ lhs.unsignedp = unsignedp;
+ lhs.overflow = false;
+ if (lhs_neg)
+ lhs = num_negate (lhs, precision);
+
+ return lhs;
+}
--- /dev/null
+/* Part of CPP library. File handling.
+ Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 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
+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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "internal.h"
+#include "mkdeps.h"
+#include "hashtab.h"
+#include "md5.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
+# define STAT_SIZE_RELIABLE(ST) true
+#endif
+
+#ifdef __DJGPP__
+#include <io.h>
+ /* 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
+
+/* 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;
+
+ /* The full path used to find the file. */
+ const char *path;
+
+ /* The full path of the pch file. */
+ const char *pchname;
+
+ /* The file's path with the basename stripped. NULL if it hasn't
+ been calculated yet. */
+ const char *dir_name;
+
+ /* Chain through all files. */
+ struct _cpp_file *next_file;
+
+ /* The contents of NAME after calling read_file(). */
+ const uchar *buffer;
+
+ /* The macro, if any, preventing re-inclusion. */
+ const cpp_hashnode *cmacro;
+
+ /* 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;
+
+ /* As filled in by stat(2) for the file. */
+ struct stat st;
+
+ /* File descriptor. Invalid if -1, otherwise open. */
+ int fd;
+
+ /* Zero if this file was successfully opened and stat()-ed,
+ otherwise errno obtained from failure. */
+ int err_no;
+
+ /* Number of times the file has been stacked for preprocessing. */
+ unsigned short stack_count;
+
+ /* If opened with #import or contains #pragma once. */
+ bool once_only;
+
+ /* If read() failed before. */
+ bool dont_read;
+
+ /* If this file is the main file. */
+ bool main_file;
+
+ /* If BUFFER above contains the true contents of the file. */
+ bool buffer_valid;
+
+ /* File is a PCH (on return from find_include_file). */
+ bool pch;
+};
+
+/* 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;
+};
+
+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 int pchf_save_compare (const void *e1, const void *e2);
+static int pchf_compare (const void *d_p, const void *e_p);
+static bool check_file_against_entries (cpp_reader *, _cpp_file *, bool);
+
+/* 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;
+ set_stdin_to_binary_mode ();
+ }
+ else
+ file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
+
+ if (file->fd != -1)
+ {
+ 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;
+ }
+
+ close (file->fd);
+ file->fd = -1;
+ }
+ else if (errno == ENOTDIR)
+ errno = ENOENT;
+
+ file->err_no = errno;
+
+ return false;
+}
+
+/* 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
+pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
+{
+ 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;
+
+ flen = strlen (path);
+ len = flen + sizeof (extension);
+ pchname = XNEWVEC (char, len);
+ memcpy (pchname, path, flen);
+ memcpy (pchname + flen, extension, sizeof (extension));
+
+ if (stat (pchname, &st) == 0)
+ {
+ DIR *pchdir;
+ struct dirent *d;
+ size_t dlen, plen = len;
+
+ if (!S_ISDIR (st.st_mode))
+ valid = validate_pch (pfile, file, pchname);
+ else if ((pchdir = opendir (pchname)) != NULL)
+ {
+ 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 = XRESIZEVEC (char, pchname, len);
+ }
+ memcpy (pchname + plen, d->d_name, dlen);
+ valid = validate_pch (pfile, file, pchname);
+ if (valid)
+ break;
+ }
+ closedir (pchdir);
+ }
+ if (valid)
+ file->pch = true;
+ else
+ *invalid_pch = true;
+ }
+
+ if (valid)
+ file->pchname = pchname;
+ else
+ free (pchname);
+
+ return valid;
+}
+
+/* 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. */
+
+static bool
+find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
+{
+ char *path;
+
+ if (CPP_OPTION (pfile, remap) && (path = remap_filename (pfile, file)))
+ ;
+ else
+ if (file->dir->construct)
+ path = file->dir->construct (file->name, file->dir);
+ else
+ path = append_file_to_dir (file->name, file->dir);
+
+ if (path)
+ {
+ 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;
+ }
+ else
+ {
+ file->err_no = ENOENT;
+ file->path = NULL;
+ }
+
+ return false;
+}
+
+/* Return tue iff the missing_header callback found the given HEADER. */
+static bool
+search_path_exhausted (cpp_reader *pfile, const char *header, _cpp_file *file)
+{
+ missing_header_cb func = pfile->cb.missing_header;
+
+ /* When the regular search path doesn't work, try context dependent
+ headers search paths. */
+ if (func
+ && file->dir == NULL)
+ {
+ if ((file->path = func (pfile, header, &file->dir)) != NULL)
+ {
+ if (open_file (file))
+ return true;
+ free ((void *)file->path);
+ }
+ file->path = file->name;
+ }
+
+ return false;
+}
+
+bool
+_cpp_find_failed (_cpp_file *file)
+{
+ return file->err_no != 0;
+}
+
+/* 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_search_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);
+
+ /* First check the cache before we resort to memory allocation. */
+ entry = search_cache (*hash_slot, start_dir);
+ if (entry)
+ return entry->u.file;
+
+ 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)
+ {
+ if (search_path_exhausted (pfile, fname, file))
+ {
+ /* Although this file must not go in the cache, because
+ the file found might depend on things (like the current file)
+ that aren't represented in the cache, it still has to go in
+ the list of all files so that #import works. */
+ file->next_file = pfile->all_files;
+ pfile->all_files = file;
+ return file;
+ }
+
+ 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 bool
+read_file_guts (cpp_reader *pfile, _cpp_file *file)
+{
+ ssize_t size, total, count;
+ uchar *buf;
+ bool regular;
+
+ 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
+ space. We can't handle a file that large. (Anyone with
+ a single source file bigger than 2GB needs to rethink
+ their coding style.) Some systems (e.g. AIX 4.1) define
+ SSIZE_MAX to be much smaller than the actual range of the
+ type. Use INTTYPE_MAXIMUM unconditionally to ensure this
+ does not bite us. */
+#ifndef __BORLANDC__
+ if (file->st.st_size > INTTYPE_MAXIMUM (ssize_t))
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "%s is too large", file->path);
+ return false;
+ }
+#endif
+
+ 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 = XNEWVEC (uchar, size + 1);
+ total = 0;
+ while ((count = read (file->fd, buf + total, size - total)) > 0)
+ {
+ total += count;
+
+ if (total == size)
+ {
+ if (regular)
+ break;
+ size *= 2;
+ buf = XRESIZEVEC (uchar, buf, size + 1);
+ }
+ }
+
+ if (count < 0)
+ {
+ cpp_errno (pfile, CPP_DL_ERROR, file->path);
+ return false;
+ }
+
+#ifndef __BORLANDC__
+ /* 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
+
+ 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))
+ {
+ open_file_failed (pfile, file, 0);
+ return false;
+ }
+
+ 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)
+ {
+ _cpp_mark_file_once_only (pfile, file);
+
+ /* Don't stack files that have been stacked before. */
+ if (file->stack_count)
+ return false;
+ }
+
+ /* 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;
+
+ /* Handle PCH files immediately; don't stack them. */
+ if (file->pch)
+ {
+ pfile->cb.read_pch (pfile, file->pchname, file->fd, file->path);
+ close (file->fd);
+ file->fd = -1;
+ return false;
+ }
+
+ if (!read_file (pfile, file))
+ return false;
+
+ /* Check the file against the PCH file. This is done before
+ checking against files we've already seen, since it may save on
+ I/O. */
+ if (check_file_against_entries (pfile, file, import))
+ {
+ /* If this isn't a #import, but yet we can't include the file,
+ that means that it was #import-ed in the PCH file,
+ so we can never include it again. */
+ if (! import)
+ _cpp_mark_file_once_only (pfile, file);
+ return false;
+ }
+
+ /* 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;
+
+ /* 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 (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)
+ {
+ _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;
+ }
+ }
+
+ return f == NULL;
+}
+
+/* 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)
+{
+ cpp_buffer *buffer;
+ int sysp;
+
+ if (!should_stack_file (pfile, file, import))
+ return false;
+
+ if (pfile->buffer == NULL || file->dir == NULL)
+ sysp = 0;
+ else
+ sysp = MAX (pfile->buffer->sysp, file->dir->sysp);
+
+ /* Add the file to the dependencies on its first inclusion. */
+ if (CPP_OPTION (pfile, deps.style) > !!sysp && !file->stack_count)
+ {
+ if (!file->main_file || !CPP_OPTION (pfile, deps.ignore_main_file))
+ deps_add_dep (pfile->deps, file->path);
+ }
+
+ /* Clear buffer_valid since _cpp_clean_line messes it up. */
+ file->buffer_valid = false;
+ file->stack_count++;
+
+ /* Stack the buffer. */
+ buffer = cpp_push_buffer (pfile, file->buffer, file->st.st_size,
+ CPP_OPTION (pfile, preprocessed));
+ buffer->file = file;
+ buffer->sysp = sysp;
+
+ /* 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;
+}
+
+/* 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)
+{
+ cpp_dir *dir;
+ _cpp_file *file;
+
+ if (IS_ABSOLUTE_PATH (fname))
+ return &pfile->no_search_path;
+
+ /* 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 && 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
+ return make_cpp_dir (pfile, dir_name_of_file (file),
+ pfile->buffer ? pfile->buffer->sysp : 0);
+
+ if (dir == NULL)
+ cpp_error (pfile, CPP_DL_ERROR,
+ "no include path in which to search for %s", fname);
+
+ return dir;
+}
+
+/* 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)
+ {
+ size_t len = lbasename (file->path) - file->path;
+ char *dir_name = XNEWVEC (char, len + 1);
+
+ memcpy (dir_name, file->path, len);
+ dir_name[len] = '\0';
+ file->dir_name = dir_name;
+ }
+
+ 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;
+ _cpp_file *file;
+
+ dir = search_path_head (pfile, fname, angle_brackets, type);
+ if (!dir)
+ return false;
+
+ file = _cpp_find_file (pfile, fname, dir, false, angle_brackets);
+
+ /* Compensate for the increment in linemap_add. In the case of a
+ normal #include, we're currently at the start of the line
+ *following* the #include. A separate source_location for this
+ location makes no sense (until we do the LC_LEAVE), and
+ complicates LAST_SOURCE_LINE_LOCATION. This does not apply if we
+ found a PCH file (in which case linemap_add is not called) or we
+ were included from the command-line. */
+ if (! file->pch && file->err_no == 0 && type != IT_CMDLINE)
+ pfile->line_table->highest_location--;
+
+ return _cpp_stack_file (pfile, file, 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->line_table->highest_line > 1 && pfile->buffer ? pfile->buffer->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
+ {
+ /* 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
+ cpp_errno (pfile, CPP_DL_ERROR, file->path);
+ }
+}
+
+/* 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 = XCNEW (_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 = XCNEW (cpp_dir);
+ dir->next = pfile->quote_include;
+ dir->name = (char *) dir_name;
+ dir->len = strlen (dir_name);
+ dir->sysp = sysp;
+ dir->construct = 0;
+
+ /* 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 = XNEWVEC (struct file_hash_entry,
+ pfile->file_hash_entries_allocated);
+}
+
+/* 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 = (struct file_hash_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 (cpp_reader *pfile, int syshdr, int externc)
+{
+ int flags = 0;
+ const struct line_maps *line_table = pfile->line_table;
+ const struct line_map *map = &line_table->maps[line_table->used-1];
+
+ /* 1 = system header, 2 = system header to be treated as C. */
+ if (syshdr)
+ flags = 1 + (externc != 0);
+ pfile->buffer->sysp = flags;
+ _cpp_do_file_change (pfile, LC_RENAME, map->to_file,
+ SOURCE_LINE (map, pfile->line_table->highest_line), flags);
+}
+
+/* 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_change_file (cpp_reader *pfile, enum lc_reason reason,
+ const char *new_name)
+{
+ _cpp_do_file_change (pfile, reason, new_name, 1, 0);
+}
+
+/* Callback function for htab_traverse. */
+static int
+report_missing_guard (void **slot, void *b)
+{
+ struct file_hash_entry *entry = (struct file_hash_entry *) *slot;
+ int *bannerp = (int *) b;
+
+ /* Skip directories. */
+ if (entry->start_dir != NULL)
+ {
+ _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)
+ {
+ if (*bannerp == 0)
+ {
+ fputs (_("Multiple include guards may be useful for:\n"),
+ stderr);
+ *bannerp = 1;
+ }
+
+ fputs (entry->u.file->path, stderr);
+ putc ('\n', stderr);
+ }
+ }
+
+ return 0;
+}
+
+/* Report on all files that might benefit from a multiple include guard.
+ Triggered by -H. */
+void
+_cpp_report_missing_guards (cpp_reader *pfile)
+{
+ int banner = 0;
+
+ 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, return 1, otherwise 0. */
+int
+_cpp_compare_file_date (cpp_reader *pfile, const char *fname,
+ int angle_brackets)
+{
+ _cpp_file *file;
+ struct cpp_dir *dir;
+
+ dir = search_path_head (pfile, fname, angle_brackets, IT_INCLUDE);
+ if (!dir)
+ return -1;
+
+ file = _cpp_find_file (pfile, fname, dir, false, angle_brackets);
+ if (file->err_no)
+ return -1;
+
+ if (file->fd != -1)
+ {
+ close (file->fd);
+ file->fd = -1;
+ }
+
+ return file->st.st_mtime > pfile->buffer->file->st.st_mtime;
+}
+
+/* Pushes the given file onto the buffer stack. Returns nonzero if
+ successful. */
+bool
+cpp_push_include (cpp_reader *pfile, const char *fname)
+{
+ 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 (cpp_reader *pfile, _cpp_file *file)
+{
+ /* Record the inclusion-preventing macro, which could be NULL
+ meaning no controlling macro. */
+ if (pfile->mi_valid && file->cmacro == NULL)
+ file->cmacro = pfile->mi_cmacro;
+
+ /* Invalidate control macros in the #including file. */
+ pfile->mi_valid = false;
+
+ if (file->buffer)
+ {
+ free ((void *) file->buffer);
+ file->buffer = NULL;
+ file->buffer_valid = false;
+ }
+}
+
+/* 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 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)
+{
+ pfile->quote_include = quote;
+ pfile->bracket_include = quote;
+ pfile->quote_ignores_source_dir = quote_ignores_source_dir;
+
+ for (; quote; quote = quote->next)
+ {
+ quote->name_map = NULL;
+ quote->len = strlen (quote->name);
+ if (quote == bracket)
+ pfile->bracket_include = bracket;
+ }
+}
+
+/* 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;
+
+ dlen = dir->len;
+ flen = strlen (fname);
+ path = XNEWVEC (char, 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 (int ch, FILE *f)
+{
+ char *alloc, *set;
+ int len;
+
+ len = 20;
+ set = alloc = XNEWVEC (char, len + 1);
+ if (! is_space (ch))
+ {
+ *set++ = ch;
+ while ((ch = getc (f)) != EOF && ! is_space (ch))
+ {
+ if (set - alloc == len)
+ {
+ len *= 2;
+ alloc = XRESIZEVEC (char, alloc, len + 1);
+ set = alloc + len / 2;
+ }
+ *set++ = ch;
+ }
+ }
+ *set = '\0';
+ ungetc (ch, f);
+ return alloc;
+}
+
+/* Read the file name map file for DIR. */
+static void
+read_name_map (cpp_dir *dir)
+{
+ static const char FILE_NAME_MAP_FILE[] = "header.gcc";
+ char *name;
+ FILE *f;
+ size_t len, count = 0, room = 9;
+
+ len = dir->len;
+ name = (char *) 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 = XNEWVEC (const char *, room);
+
+ /* Silently return NULL if we cannot open. */
+ if (f)
+ {
+ int ch;
+
+ while ((ch = getc (f)) != EOF)
+ {
+ char *to;
+
+ if (is_space (ch))
+ continue;
+
+ if (count + 2 > room)
+ {
+ room += 8;
+ dir->name_map = XRESIZEVEC (const char *, dir->name_map, room);
+ }
+
+ dir->name_map[count] = read_filename_string (ch, f);
+ while ((ch = getc (f)) != EOF && is_hspace (ch))
+ ;
+
+ to = read_filename_string (ch, f);
+ if (IS_ABSOLUTE_PATH (to))
+ dir->name_map[count + 1] = to;
+ else
+ {
+ dir->name_map[count + 1] = append_file_to_dir (to, dir);
+ free (to);
+ }
+
+ count += 2;
+ while ((ch = getc (f)) != '\n')
+ if (ch == EOF)
+ break;
+ }
+
+ fclose (f);
+ }
+
+ /* Terminate the list of maps. */
+ dir->name_map[count] = NULL;
+}
+
+/* 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 (cpp_reader *pfile, _cpp_file *file)
+{
+ const char *fname, *p;
+ char *new_dir;
+ cpp_dir *dir;
+ size_t index, len;
+
+ dir = file->dir;
+ fname = file->name;
+
+ for (;;)
+ {
+ if (!dir->name_map)
+ read_name_map (dir);
+
+ for (index = 0; dir->name_map[index]; index += 2)
+ if (!strcmp (dir->name_map[index], fname))
+ return xstrdup (dir->name_map[index + 1]);
+
+ p = strchr (fname, '/');
+ if (!p || p == fname)
+ return NULL;
+
+ len = dir->len + (p - fname + 1);
+ new_dir = XNEWVEC (char, len + 1);
+ memcpy (new_dir, dir->name, dir->len);
+ memcpy (new_dir + dir->len, fname, p - fname + 1);
+ new_dir[len] = '\0';
+
+ dir = make_cpp_dir (pfile, new_dir, dir->sysp);
+ fname = p + 1;
+ }
+}
+
+/* Returns true if PCHNAME is a valid PCH file for FILE. */
+static bool
+validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname)
+{
+ const char *saved_path = file->path;
+ bool valid = false;
+
+ file->path = pchname;
+ if (open_file (file))
+ {
+ valid = 1 & pfile->cb.valid_pch (pfile, pchname, file->fd);
+
+ if (!valid)
+ {
+ close (file->fd);
+ file->fd = -1;
+ }
+
+ if (CPP_OPTION (pfile, print_include_names))
+ {
+ unsigned int i;
+ for (i = 1; i < pfile->line_table->depth; i++)
+ putc ('.', stderr);
+ fprintf (stderr, "%c %s\n",
+ valid ? '!' : 'x', pchname);
+ }
+ }
+
+ file->path = saved_path;
+ return valid;
+}
+
+/* Get the path associated with the _cpp_file F. The path includes
+ the base name from the include directive and the directory it was
+ found in via the search path. */
+
+const char *
+cpp_get_path (struct _cpp_file *f)
+{
+ return f->path;
+}
+
+/* Get the directory associated with the _cpp_file F. */
+
+cpp_dir *
+cpp_get_dir (struct _cpp_file *f)
+{
+ return f->dir;
+}
+
+/* Get the cpp_buffer currently associated with the cpp_reader
+ PFILE. */
+
+cpp_buffer *
+cpp_get_buffer (cpp_reader *pfile)
+{
+ return pfile->buffer;
+}
+
+/* Get the _cpp_file associated with the cpp_buffer B. */
+
+_cpp_file *
+cpp_get_file (cpp_buffer *b)
+{
+ return b->file;
+}
+
+/* Get the previous cpp_buffer given a cpp_buffer B. The previous
+ buffer is the buffer that included the given buffer. */
+
+cpp_buffer *
+cpp_get_prev (cpp_buffer *b)
+{
+ return b->prev;
+}
+\f
+/* This data structure holds the list of header files that were seen
+ while the PCH was being built. The 'entries' field is kept sorted
+ in memcmp() order; yes, this means that on little-endian systems,
+ it's sorted initially by the least-significant byte of 'size', but
+ that's OK. The code does rely on having entries with the same size
+ next to each other. */
+
+struct pchf_entry {
+ /* The size of this file. This is used to save running a MD5 checksum
+ if the sizes don't match. */
+ off_t size;
+ /* The MD5 checksum of this file. */
+ unsigned char sum[16];
+ /* Is this file to be included only once? */
+ bool once_only;
+};
+
+struct pchf_data {
+ /* Number of pchf_entry structures. */
+ size_t count;
+
+ /* Are there any values with once_only set?
+ This is used as an optimisation, it means we don't have to search
+ the structure if we're processing a regular #include. */
+ bool have_once_only;
+
+ struct pchf_entry entries[1];
+};
+
+static struct pchf_data *pchf;
+
+/* A qsort ordering function for pchf_entry structures. */
+
+static int
+pchf_save_compare (const void *e1, const void *e2)
+{
+ return memcmp (e1, e2, sizeof (struct pchf_entry));
+}
+
+/* Create and write to F a pchf_data structure. */
+
+bool
+_cpp_save_file_entries (cpp_reader *pfile, FILE *fp)
+{
+ size_t count = 0;
+ struct pchf_data *result;
+ size_t result_size;
+ _cpp_file *f;
+
+ for (f = pfile->all_files; f; f = f->next_file)
+ ++count;
+
+ result_size = (sizeof (struct pchf_data)
+ + sizeof (struct pchf_entry) * (count - 1));
+ result = XCNEWVAR (struct pchf_data, result_size);
+
+ result->count = 0;
+ result->have_once_only = false;
+
+ for (f = pfile->all_files; f; f = f->next_file)
+ {
+ size_t count;
+
+ /* This should probably never happen, since if a read error occurred
+ the PCH file shouldn't be written... */
+ if (f->dont_read || f->err_no)
+ continue;
+
+ if (f->stack_count == 0)
+ continue;
+
+ count = result->count++;
+
+ result->entries[count].once_only = f->once_only;
+ /* |= is avoided in the next line because of an HP C compiler bug */
+ result->have_once_only = result->have_once_only | f->once_only;
+ if (f->buffer_valid)
+ md5_buffer ((const char *)f->buffer,
+ f->st.st_size, result->entries[count].sum);
+ else
+ {
+ FILE *ff;
+ int oldfd = f->fd;
+
+ if (!open_file (f))
+ {
+ open_file_failed (pfile, f, 0);
+ return false;
+ }
+ ff = fdopen (f->fd, "rb");
+ md5_stream (ff, result->entries[count].sum);
+ fclose (ff);
+ f->fd = oldfd;
+ }
+ result->entries[count].size = f->st.st_size;
+ }
+
+ result_size = (sizeof (struct pchf_data)
+ + sizeof (struct pchf_entry) * (result->count - 1));
+
+ qsort (result->entries, result->count, sizeof (struct pchf_entry),
+ pchf_save_compare);
+
+ return fwrite (result, result_size, 1, fp) == 1;
+}
+
+/* Read the pchf_data structure from F. */
+
+bool
+_cpp_read_file_entries (cpp_reader *pfile ATTRIBUTE_UNUSED, FILE *f)
+{
+ struct pchf_data d;
+
+ if (fread (&d, sizeof (struct pchf_data) - sizeof (struct pchf_entry), 1, f)
+ != 1)
+ return false;
+
+ pchf = XNEWVAR (struct pchf_data, sizeof (struct pchf_data)
+ + sizeof (struct pchf_entry) * (d.count - 1));
+ memcpy (pchf, &d, sizeof (struct pchf_data) - sizeof (struct pchf_entry));
+ if (fread (pchf->entries, sizeof (struct pchf_entry), d.count, f)
+ != d.count)
+ return false;
+ return true;
+}
+
+/* The parameters for pchf_compare. */
+
+struct pchf_compare_data
+{
+ /* The size of the file we're looking for. */
+ off_t size;
+
+ /* The MD5 checksum of the file, if it's been computed. */
+ unsigned char sum[16];
+
+ /* Is SUM valid? */
+ bool sum_computed;
+
+ /* Do we need to worry about entries that don't have ONCE_ONLY set? */
+ bool check_included;
+
+ /* The file that we're searching for. */
+ _cpp_file *f;
+};
+
+/* bsearch comparison function; look for D_P in E_P. */
+
+static int
+pchf_compare (const void *d_p, const void *e_p)
+{
+ const struct pchf_entry *e = (const struct pchf_entry *)e_p;
+ struct pchf_compare_data *d = (struct pchf_compare_data *)d_p;
+ int result;
+
+ result = memcmp (&d->size, &e->size, sizeof (off_t));
+ if (result != 0)
+ return result;
+
+ if (! d->sum_computed)
+ {
+ _cpp_file *const f = d->f;
+
+ md5_buffer ((const char *)f->buffer, f->st.st_size, d->sum);
+ d->sum_computed = true;
+ }
+
+ result = memcmp (d->sum, e->sum, 16);
+ if (result != 0)
+ return result;
+
+ if (d->check_included || e->once_only)
+ return 0;
+ else
+ return 1;
+}
+
+/* Check that F is not in a list read from a PCH file (if any).
+ Assumes that f->buffer_valid is true. Return TRUE if the file
+ should not be read. */
+
+static bool
+check_file_against_entries (cpp_reader *pfile ATTRIBUTE_UNUSED,
+ _cpp_file *f,
+ bool check_included)
+{
+ struct pchf_compare_data d;
+
+ if (pchf == NULL
+ || (! check_included && ! pchf->have_once_only))
+ return false;
+
+ d.size = f->st.st_size;
+ d.sum_computed = false;
+ d.f = f;
+ d.check_included = check_included;
+ return bsearch (&d, pchf->entries, pchf->count, sizeof (struct pchf_entry),
+ pchf_compare) != NULL;
+}
--- /dev/null
+/* Hash tables for the CPP library.
+ Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
+ 1999, 2000, 2001, 2002 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
+
+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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 "internal.h"
+
+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 (hash_table *table)
+{
+ cpp_hashnode *node;
+
+ node = XOBNEW (&table->pfile->hash_ob, 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 (cpp_reader *pfile, hash_table *table)
+{
+ struct spec_nodes *s;
+
+ if (table == NULL)
+ {
+ pfile->our_hashtable = 1;
+ table = ht_create (13); /* 8K (=2^13) entries. */
+ table->alloc_node = (hashnode (*) (hash_table *)) alloc_node;
+
+ _obstack_begin (&pfile->hash_ob, 0, 0,
+ (void *(*) (long)) xmalloc,
+ (void (*) (void *)) free);
+ }
+
+ table->pfile = pfile;
+ pfile->hash_table = table;
+
+ /* Now we can initialize things that use the hash table. */
+ _cpp_init_directives (pfile);
+ _cpp_init_internal_pragmas (pfile);
+
+ s = &pfile->spec_nodes;
+ s->n_defined = cpp_lookup (pfile, DSC("defined"));
+ s->n_true = cpp_lookup (pfile, DSC("true"));
+ s->n_false = cpp_lookup (pfile, DSC("false"));
+ s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__"));
+ s->n__VA_ARGS__->flags |= NODE_DIAGNOSTIC;
+ /* SDCC _asm specific */
+ s->n__asm = cpp_lookup (pfile, DSC("_asm"));
+}
+
+/* Tear down the identifier hash table. */
+void
+_cpp_destroy_hashtable (cpp_reader *pfile)
+{
+ if (pfile->our_hashtable)
+ {
+ ht_destroy (pfile->hash_table);
+ obstack_free (&pfile->hash_ob, 0);
+ }
+}
+
+/* Returns the hash entry for the STR of length LEN, creating one
+ if necessary. */
+cpp_hashnode *
+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));
+}
+
+/* Determine whether the str STR, of length LEN, is a defined macro. */
+int
+cpp_defined (cpp_reader *pfile, const unsigned char *str, int len)
+{
+ cpp_hashnode *node;
+
+ node = CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_NO_INSERT));
+
+ /* If it's of type NT_MACRO, it cannot be poisoned. */
+ return node && node->type == NT_MACRO;
+}
+
+/* For all nodes in the hashtable, callback CB with parameters PFILE,
+ the node, and V. */
+void
+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. */
+ ht_forall (pfile->hash_table, (ht_cb) cb, v);
+}
--- /dev/null
+/* Structures that hang off cpp_identifier, for PCH.
+ Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 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
+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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "cpplib.h"
+
+#if !defined (HAVE_UCHAR) && !defined (IN_GCC)
+typedef unsigned char uchar;
+#endif
+
+#define U (const unsigned char *) /* Intended use: U"string" */
+
+/* Chained list of answers to an assertion. */
+struct answer GTY(())
+{
+ struct answer *next;
+ unsigned int count;
+ cpp_token GTY ((length ("%h.count"))) first[1];
+};
+
+/* Each macro definition is recorded in a cpp_macro structure.
+ Variadic macros cannot occur with traditional cpp. */
+struct cpp_macro GTY(())
+{
+ /* Parameters, if any. */
+ cpp_hashnode ** GTY ((nested_ptr (union tree_node,
+ "%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL",
+ "%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"),
+ length ("%h.paramc")))
+ params;
+
+ /* Replacement tokens (ISO) or replacement text (traditional). See
+ comment at top of cpptrad.c for how traditional function-like
+ macros are encoded. */
+ union cpp_macro_u
+ {
+ cpp_token * GTY ((tag ("0"), length ("%0.count"))) tokens;
+ const unsigned char * GTY ((tag ("1"))) text;
+ } GTY ((desc ("%1.traditional"))) exp;
+
+ /* Definition line number. */
+ source_location line;
+
+ /* Number of tokens in expansion, or bytes for traditional macros. */
+ unsigned int count;
+
+ /* Number of parameters. */
+ unsigned short paramc;
+
+ /* If a function-like macro. */
+ unsigned int fun_like : 1;
+
+ /* If a variadic macro. */
+ unsigned int variadic : 1;
+
+ /* If macro defined in system header. */
+ unsigned int syshdr : 1;
+
+ /* Nonzero if it has been expanded or had its existence tested. */
+ unsigned int used : 1;
+
+ /* Indicate which field of 'exp' is in use. */
+ unsigned int traditional : 1;
+};
--- /dev/null
+/* Definitions for CPP library.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004, 2005
+ 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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! */
+#ifndef LIBCPP_CPPLIB_H
+#define LIBCPP_CPPLIB_H
+
+#include <sys/types.h>
+#include "symtab.h"
+#include "line-map.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct cpp_reader cpp_reader;
+typedef struct cpp_buffer cpp_buffer;
+typedef struct cpp_options cpp_options;
+typedef struct cpp_token cpp_token;
+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 _cpp_file;
+
+/* The first three groups, apart from '=', can appear in preprocessor
+ expressions (+= and -= are used to indicate unary + and - resp.).
+ This allows a lookup table to be implemented in _cpp_parse_expr.
+
+ The first group, to CPP_LAST_EQ, can be immediately followed by an
+ '='. The lexer needs operators ending in '=', like ">>=", to be in
+ the same order as their counterparts without the '=', like ">>". */
+
+#define TTYPE_TABLE \
+ OP(EQ, "=") \
+ OP(NOT, "!") \
+ OP(GREATER, ">") /* compare */ \
+ OP(LESS, "<") \
+ OP(PLUS, "+") /* math */ \
+ OP(MINUS, "-") \
+ OP(MULT, "*") \
+ OP(DIV, "/") \
+ OP(MOD, "%") \
+ OP(AND, "&") /* bit ops */ \
+ OP(OR, "|") \
+ OP(XOR, "^") \
+ OP(RSHIFT, ">>") \
+ OP(LSHIFT, "<<") \
+ OP(MIN, "<?") /* extension */ \
+ OP(MAX, ">?") \
+ \
+ OP(COMPL, "~") \
+ OP(AND_AND, "&&") /* logical */ \
+ OP(OR_OR, "||") \
+ OP(QUERY, "?") \
+ OP(COLON, ":") \
+ OP(COMMA, ",") /* grouping */ \
+ OP(OPEN_PAREN, "(") \
+ OP(CLOSE_PAREN, ")") \
+ TK(EOF, NONE) \
+ OP(EQ_EQ, "==") /* compare */ \
+ OP(NOT_EQ, "!=") \
+ OP(GREATER_EQ, ">=") \
+ OP(LESS_EQ, "<=") \
+ \
+ /* These two are unary + / - in preprocessor expressions. */ \
+ OP(PLUS_EQ, "+=") /* math */ \
+ OP(MINUS_EQ, "-=") \
+ \
+ OP(MULT_EQ, "*=") \
+ OP(DIV_EQ, "/=") \
+ OP(MOD_EQ, "%=") \
+ OP(AND_EQ, "&=") /* bit ops */ \
+ OP(OR_EQ, "|=") \
+ OP(XOR_EQ, "^=") \
+ OP(RSHIFT_EQ, ">>=") \
+ OP(LSHIFT_EQ, "<<=") \
+ OP(MIN_EQ, "<?=") /* extension */ \
+ OP(MAX_EQ, ">?=") \
+ /* Digraphs together, beginning with CPP_FIRST_DIGRAPH. */ \
+ OP(HASH, "#") /* digraphs */ \
+ OP(PASTE, "##") \
+ OP(OPEN_SQUARE, "[") \
+ OP(CLOSE_SQUARE, "]") \
+ OP(OPEN_BRACE, "{") \
+ OP(CLOSE_BRACE, "}") \
+ /* The remainder of the punctuation. Order is not significant. */ \
+ OP(SEMICOLON, ";") /* structure */ \
+ OP(ELLIPSIS, "...") \
+ OP(PLUS_PLUS, "++") /* increment */ \
+ OP(MINUS_MINUS, "--") \
+ OP(DEREF, "->") /* accessors */ \
+ OP(DOT, ".") \
+ OP(SCOPE, "::") \
+ OP(DEREF_STAR, "->*") \
+ OP(DOT_STAR, ".*") \
+ OP(ATSIGN, "@") /* used in Objective-C */ \
+ \
+ TK(NAME, IDENT) /* word */ \
+ TK(AT_NAME, IDENT) /* @word - Objective-C */ \
+ TK(NUMBER, LITERAL) /* 34_be+ta */ \
+ \
+ TK(CHAR, LITERAL) /* 'char' */ \
+ TK(WCHAR, LITERAL) /* L'char' */ \
+ TK(OTHER, LITERAL) /* stray punctuation */ \
+ \
+ TK(STRING, LITERAL) /* "string" */ \
+ TK(WSTRING, LITERAL) /* L"string" */ \
+ TK(OBJC_STRING, LITERAL) /* @"string" - Objective-C */ \
+ TK(HEADER_NAME, LITERAL) /* <stdio.h> in #include */ \
+ \
+ TK(COMMENT, LITERAL) /* Only if output comments. */ \
+ /* SPELL_LITERAL happens to DTRT. */ \
+ TK(MACRO_ARG, NONE) /* Macro argument. */ \
+ TK(PRAGMA, NONE) /* Only if deferring pragmas */ \
+ TK(PADDING, NONE) /* Whitespace for -E. */ \
+\
+ /* SDCC _asm specific */ \
+ TK(ASM, LITERAL) /* _asm ... _endasm ; */
+
+#define OP(e, s) CPP_ ## e,
+#define TK(e, s) CPP_ ## e,
+enum cpp_ttype
+{
+ TTYPE_TABLE
+ N_TTYPES,
+
+ /* Positions in the table. */
+ CPP_LAST_EQ = CPP_MAX,
+ CPP_FIRST_DIGRAPH = CPP_HASH,
+ CPP_LAST_PUNCTUATOR= CPP_DOT_STAR,
+ CPP_LAST_CPP_OP = CPP_LESS_EQ
+};
+#undef OP
+#undef TK
+
+/* C language kind, used when calling cpp_create_reader. */
+enum c_lang {CLK_GNUC89 = 0, CLK_GNUC99, CLK_STDC89, CLK_STDC94, CLK_STDC99,
+ CLK_GNUCXX, CLK_CXX98, CLK_ASM};
+
+/* Payload of a NUMBER, STRING, CHAR or COMMENT token. */
+struct cpp_string GTY(())
+{
+ unsigned int len;
+ const unsigned char *text;
+};
+
+/* Flags for the cpp_token structure. */
+#define PREV_WHITE (1 << 0) /* If whitespace before this token. */
+#define DIGRAPH (1 << 1) /* If it was a digraph. */
+#define STRINGIFY_ARG (1 << 2) /* If macro argument to be stringified. */
+#define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator. */
+#define NAMED_OP (1 << 4) /* C++ named operators. */
+#define NO_EXPAND (1 << 5) /* Do not macro-expand this token. */
+#define BOL (1 << 6) /* Token at beginning of line. */
+
+/* Specify which field, if any, of the cpp_token union is used. */
+
+enum cpp_token_fld_kind {
+ CPP_TOKEN_FLD_NODE,
+ CPP_TOKEN_FLD_SOURCE,
+ CPP_TOKEN_FLD_STR,
+ CPP_TOKEN_FLD_ARG_NO,
+ CPP_TOKEN_FLD_NONE
+};
+
+/* A preprocessing token. This has been carefully packed and should
+ occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */
+struct cpp_token GTY(())
+{
+ source_location src_loc; /* Location of first char of token. */
+ ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT; /* token type */
+ unsigned char flags; /* flags - see above */
+
+ union cpp_token_u
+ {
+ /* An identifier. */
+ cpp_hashnode *
+ GTY ((nested_ptr (union tree_node,
+ "%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL",
+ "%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"),
+ tag ("CPP_TOKEN_FLD_NODE")))
+ node;
+
+ /* Inherit padding from this token. */
+ cpp_token * GTY ((tag ("CPP_TOKEN_FLD_SOURCE"))) source;
+
+ /* A string, or number. */
+ struct cpp_string GTY ((tag ("CPP_TOKEN_FLD_STR"))) str;
+
+ /* Argument no. for a CPP_MACRO_ARG. */
+ unsigned int GTY ((tag ("CPP_TOKEN_FLD_ARG_NO"))) arg_no;
+ } GTY ((desc ("cpp_token_val_index (&%1)"))) val;
+};
+
+/* Say which field is in use. */
+extern enum cpp_token_fld_kind cpp_token_val_index (cpp_token *tok);
+
+/* 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.
+ 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
+# 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;
+
+/* Style of header dependencies to generate. */
+enum cpp_deps_style { DEPS_NONE = 0, DEPS_USER, DEPS_SYSTEM };
+
+/* The possible normalization levels, from most restrictive to least. */
+enum cpp_normalize_level {
+ /* In NFKC. */
+ normalized_KC = 0,
+ /* In NFC. */
+ normalized_C,
+ /* In NFC, except for subsequences where being in NFC would make
+ the identifier invalid. */
+ normalized_identifier_C,
+ /* Not normalized at all. */
+ normalized_none
+};
+
+/* This structure is nested inside struct cpp_reader, and
+ carries all the options visible to the command line. */
+struct cpp_options
+{
+ /* Characters between tab stops. */
+ unsigned int tabstop;
+
+ /* The language we're preprocessing. */
+ enum c_lang lang;
+
+ /* Nonzero means use extra default include directories for C++. */
+ unsigned char cplusplus;
+
+ /* Nonzero means handle cplusplus style comments. */
+ unsigned char cplusplus_comments;
+
+ /* Nonzero means define __OBJC__, treat @ as a special token, and
+ use the OBJC[PLUS]_INCLUDE_PATH environment variable. */
+ unsigned char objc;
+
+ /* Nonzero means don't copy comments into the output file. */
+ unsigned char discard_comments;
+
+ /* Nonzero means don't copy comments into the output file during
+ macro expansion. */
+ unsigned char discard_comments_in_macro_exp;
+
+ /* Nonzero means process the ISO trigraph sequences. */
+ unsigned char trigraphs;
+
+ /* Nonzero means process the ISO digraph sequences. */
+ unsigned char digraphs;
+
+ /* Nonzero means to allow hexadecimal floats and LL suffixes. */
+ unsigned char extended_numbers;
+
+ /* Nonzero means print names of header files (-H). */
+ unsigned char print_include_names;
+
+ /* Nonzero means cpp_pedwarn causes a hard error. */
+ unsigned char pedantic_errors;
+
+ /* 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;
+
+ /* Nonzero means don't print error messages. Has no option to
+ select it, but can be set by a user of cpplib (e.g. fix-header). */
+ unsigned char inhibit_errors;
+
+ /* Nonzero means warn if slash-star appears in a comment. */
+ unsigned char warn_comments;
+
+ /* Nonzero means warn if a user-supplied include directory does not
+ exist. */
+ unsigned char warn_missing_include_dirs;
+
+ /* Nonzero means warn if there are any trigraphs. */
+ unsigned char warn_trigraphs;
+
+ /* Nonzero means warn about multicharacter charconsts. */
+ unsigned char warn_multichar;
+
+ /* Nonzero means warn about various incompatibilities with
+ traditional C. */
+ unsigned char warn_traditional;
+
+ /* Nonzero means warn about long long numeric constants. */
+ unsigned char warn_long_long;
+
+ /* Nonzero means warn about text after an #endif (or #else). */
+ unsigned char warn_endif_labels;
+
+ /* Nonzero means warn about implicit sign changes owing to integer
+ promotions. */
+ unsigned char warn_num_sign_change;
+
+ /* Zero means don't warn about __VA_ARGS__ usage in c89 pedantic mode.
+ Presumably the usage is protected by the appropriate #ifdef. */
+ unsigned char warn_variadic_macros;
+
+ /* Nonzero means turn warnings into errors. */
+ unsigned char warnings_are_errors;
+
+ /* Nonzero means we should look for header.gcc files that remap file
+ names. */
+ unsigned char remap;
+
+ /* Zero means dollar signs are punctuation. */
+ unsigned char dollars_in_ident;
+
+ /* Nonzero means UCNs are accepted in identifiers. */
+ unsigned char extended_identifiers;
+
+ /* 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;
+
+ /* Nonzero means warn of unused macros from the main file. */
+ unsigned char warn_unused_macros;
+
+ /* Nonzero for the 1999 C Standard, including corrigenda and amendments. */
+ unsigned char c99;
+
+ /* Nonzero if we are conforming to a specific C or C++ standard. */
+ unsigned char std;
+
+ /* Nonzero means give all the error messages the ANSI standard requires. */
+ unsigned char pedantic;
+
+ /* Nonzero means we're looking at already preprocessed code, so don't
+ bother trying to do macro expansion and whatnot. */
+ unsigned char preprocessed;
+
+ /* Print column number in error messages. */
+ unsigned char show_column;
+
+ /* Nonzero means handle C++ alternate operator names. */
+ unsigned char operator_names;
+
+ /* True for traditional preprocessing. */
+ unsigned char traditional;
+
+ /* 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;
+
+ /* The minimum permitted level of normalization before a warning
+ is generated. */
+ enum cpp_normalize_level warn_normalize;
+
+ /* 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)
+ */
+ unsigned char allow_naked_hash;
+
+ /* SDCC _asm specific
+ switch _asm block preprocessing on / off */
+ unsigned char preproc_asm;
+
+ /* SDCC specific
+ object file exetnsion */
+ const char *obj_ext;
+
+ /* SDCC specific
+ pedantic_parse_number */
+ unsigned char pedantic_parse_number;
+
+ /* Dependency generation. */
+ struct
+ {
+ /* Style of header dependencies to generate. */
+ enum cpp_deps_style style;
+
+ /* Assume missing files are generated files. */
+ bool missing_files;
+
+ /* Generate phony targets for each dependency apart from the first
+ one. */
+ bool phony_targets;
+
+ /* If true, no dependency is generated on the main file. */
+ bool ignore_main_file;
+ } deps;
+
+ /* Target-specific features set by the front end or client. */
+
+ /* Precision for target CPP arithmetic, target characters, target
+ ints and target wide characters, respectively. */
+ size_t precision, char_precision, int_precision, wchar_precision;
+
+ /* 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;
+
+ /* True means return pragmas as tokens rather than processing
+ them directly. */
+ bool defer_pragmas;
+
+ /* True means error callback should be used for diagnostics. */
+ bool client_diagnostic;
+};
+
+/* Callback for header lookup for HEADER, which is the name of a
+ source file. It is used as a method of last resort to find headers
+ that are not otherwise found during the normal include processing.
+ The return value is the malloced name of a header to try and open,
+ if any, or NULL otherwise. This callback is called only if the
+ header is otherwise unfound. */
+typedef const char *(*missing_header_cb)(cpp_reader *, const char *header, cpp_dir **);
+
+/* Call backs to cpplib client. */
+struct cpp_callbacks
+{
+ /* Called when a new line of preprocessed output is started. */
+ 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, const cpp_token **);
+ 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 *);
+ missing_header_cb missing_header;
+
+ /* Called to emit a diagnostic if client_diagnostic option is true.
+ This callback receives the translated message. */
+ void (*error) (cpp_reader *, int, const char *, va_list *)
+ ATTRIBUTE_FPTR_PRINTF(3,0);
+};
+
+/* 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;
+
+ /* Routine to construct pathname, given the search path name and the
+ HEADER we are trying to find, return a constructed pathname to
+ try and open. If this is NULL, the constructed pathname is as
+ constructed by append_file_to_dir. */
+ char *(*construct) (const char *header, cpp_dir *dir);
+
+ /* The C front end uses these to recognize duplicated
+ directories in the search path. */
+ ino_t ino;
+ dev_t dev;
+
+ /* Is this a user-supplied directory? */
+ bool user_supplied_p;
+};
+
+/* Name under which this program was invoked. */
+extern const char *progname;
+
+/* The structure of a node in the hash table. The hash table has
+ 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. 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
+ diagnostic may be required for this node. Currently this only
+ applies to __VA_ARGS__ and poisoned identifiers. */
+
+/* Hash node flags. */
+#define NODE_OPERATOR (1 << 0) /* C++ named operator. */
+#define NODE_POISONED (1 << 1) /* Poisoned identifier. */
+#define NODE_BUILTIN (1 << 2) /* Builtin macro. */
+#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
+{
+ NT_VOID = 0, /* No definition yet. */
+ NT_MACRO, /* A macro of some form. */
+ NT_ASSERTION /* Predicate for #assert. */
+};
+
+/* Different flavors of builtin macro. _Pragma is an operator, but we
+ handle it with the builtin code for efficiency reasons. */
+enum builtin_type
+{
+ BT_SPECLINE = 0, /* `__LINE__' */
+ BT_DATE, /* `__DATE__' */
+ BT_FILE, /* `__FILE__' */
+ BT_BASE_FILE, /* `__BASE_FILE__' */
+ BT_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
+ BT_TIME, /* `__TIME__' */
+ BT_STDC, /* `__STDC__' */
+ BT_PRAGMA /* `_Pragma' operator */
+};
+
+#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE))
+#define HT_NODE(NODE) ((ht_identifier *) (NODE))
+#define NODE_LEN(NODE) HT_LEN (&(NODE)->ident)
+#define NODE_NAME(NODE) HT_STR (&(NODE)->ident)
+
+/* Specify which field, if any, of the union is used. */
+
+enum {
+ NTV_MACRO,
+ NTV_ANSWER,
+ NTV_BUILTIN,
+ NTV_ARGUMENT,
+ NTV_NONE
+};
+
+#define CPP_HASHNODE_VALUE_IDX(HNODE) \
+ ((HNODE.flags & NODE_MACRO_ARG) ? NTV_ARGUMENT \
+ : HNODE.type == NT_MACRO ? ((HNODE.flags & NODE_BUILTIN) \
+ ? NTV_BUILTIN : NTV_MACRO) \
+ : HNODE.type == NT_ASSERTION ? NTV_ANSWER \
+ : NTV_NONE)
+
+/* 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. */
+
+union _cpp_hashnode_value GTY(())
+{
+ /* If a macro. */
+ cpp_macro * GTY((tag ("NTV_MACRO"))) macro;
+ /* Answers to an assertion. */
+ struct answer * GTY ((tag ("NTV_ANSWER"))) answers;
+ /* Code for a builtin macro. */
+ enum builtin_type GTY ((tag ("NTV_BUILTIN"))) builtin;
+ /* Macro argument index. */
+ unsigned short GTY ((tag ("NTV_ARGUMENT"))) arg_index;
+};
+
+struct cpp_hashnode GTY(())
+{
+ struct ht_identifier ident;
+ 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 _cpp_hashnode_value GTY ((desc ("CPP_HASHNODE_VALUE_IDX (%1)"))) value;
+};
+
+/* 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 *,
+ struct line_maps *);
+
+/* Call this to change the selected language standard (e.g. because of
+ command line options). */
+extern void cpp_set_lang (cpp_reader *, enum c_lang);
+
+/* 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, callback, and deps
+ 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 (cpp_reader *);
+extern cpp_callbacks *cpp_get_callbacks (cpp_reader *);
+extern void cpp_set_callbacks (cpp_reader *, cpp_callbacks *);
+extern struct deps *cpp_get_deps (cpp_reader *);
+
+/* 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. */
+extern const char *cpp_read_main_file (cpp_reader *, const char *);
+
+/* 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 *);
+
+/* 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 (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 (cpp_reader *);
+
+/* Error count. */
+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 *, bool);
+extern void cpp_register_pragma (cpp_reader *, const char *, const char *,
+ void (*) (cpp_reader *), bool);
+extern void cpp_handle_deferred_pragma (cpp_reader *, const cpp_string *);
+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 (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);
+extern bool cpp_interpret_string_notranslate (cpp_reader *,
+ const cpp_string *, size_t,
+ cpp_string *, bool);
+
+/* Convert a host character constant to the execution character set. */
+extern cppchar_t cpp_host_to_exec_charset (cpp_reader *, cppchar_t);
+
+/* 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 (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 (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. */
+typedef unsigned HOST_WIDE_INT cpp_num_part;
+typedef struct cpp_num cpp_num;
+struct cpp_num
+{
+ cpp_num_part high;
+ cpp_num_part low;
+ bool unsignedp; /* True if value should be treated as unsigned. */
+ bool overflow; /* True if the most recent calculation overflowed. */
+};
+
+/* cpplib provides two interfaces for interpretation of preprocessing
+ numbers.
+
+ cpp_classify_number categorizes numeric constants according to
+ their field (integer, floating point, or invalid), radix (decimal,
+ octal, hexadecimal), and type suffixes. */
+
+#define CPP_N_CATEGORY 0x000F
+#define CPP_N_INVALID 0x0000
+#define CPP_N_INTEGER 0x0001
+#define CPP_N_FLOATING 0x0002
+
+#define CPP_N_WIDTH 0x00F0
+#define CPP_N_SMALL 0x0010 /* int, float. */
+#define CPP_N_MEDIUM 0x0020 /* long, double. */
+#define CPP_N_LARGE 0x0040 /* long long, long double. */
+
+#define CPP_N_RADIX 0x0F00
+#define CPP_N_DECIMAL 0x0100
+#define CPP_N_HEX 0x0200
+#define CPP_N_OCTAL 0x0400
+
+#define CPP_N_UNSIGNED 0x1000 /* Properties. */
+#define CPP_N_IMAGINARY 0x2000
+
+/* Classify a CPP_NUMBER token. The return value is a combination of
+ the flags from the above sets. */
+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 (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 (cpp_num, size_t);
+
+/* 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 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 CPP_DL_PEDWARN 0x02
+/* An error. */
+#define CPP_DL_ERROR 0x03
+/* An internal consistency check failed. Prints "internal error: ",
+ otherwise the same as CPP_DL_ERROR. */
+#define CPP_DL_ICE 0x04
+/* Extracts a diagnostic level from an int. */
+#define CPP_DL_EXTRACT(l) (l & 0xf)
+/* Nonzero if a diagnostic level is one of the warnings. */
+#define CPP_DL_WARNING_P(l) (CPP_DL_EXTRACT (l) >= CPP_DL_WARNING \
+ && CPP_DL_EXTRACT (l) <= CPP_DL_PEDWARN)
+
+/* Output a diagnostic of some kind. */
+extern void cpp_error (cpp_reader *, int, const char *msgid, ...)
+ ATTRIBUTE_PRINTF_3;
+
+/* Output a diagnostic with "MSGID: " preceding the
+ error string of errno. No location is printed. */
+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 (cpp_reader *, int, source_location, unsigned,
+ const char *msgid, ...) ATTRIBUTE_PRINTF_5;
+
+/* In cpplex.c */
+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 (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 (cpp_reader *, const unsigned char *,
+ unsigned int);
+
+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 (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 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 *);
+extern const char *cpp_get_path (struct _cpp_file *);
+extern cpp_dir *cpp_get_dir (struct _cpp_file *);
+extern cpp_buffer *cpp_get_buffer (cpp_reader *);
+extern struct _cpp_file *cpp_get_file (cpp_buffer *);
+extern cpp_buffer *cpp_get_prev (cpp_buffer *);
+
+/* 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
+}
+#endif
+
+#endif /* ! LIBCPP_CPPLIB_H */
--- /dev/null
+/* Map logical line numbers to (source file, line number) pairs.
+ Copyright (C) 2001, 2003, 2004
+ 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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! */
+
+#ifndef LIBCPP_LINE_MAP_H
+#define LIBCPP_LINE_MAP_H
+
+/* Reason for adding a line change with add_line_map (). LC_ENTER is
+ when including a new file, e.g. a #include directive in C.
+ LC_LEAVE is when reaching a file's end. LC_RENAME is when a file
+ name or line number changes for neither of the above reasons
+ (e.g. a #line directive in C). */
+enum lc_reason {LC_ENTER = 0, LC_LEAVE, LC_RENAME};
+
+/* A logical line/column 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;
+
+/* Physical source file TO_FILE at line TO_LINE at column 0 is represented
+ by the logical START_LOCATION. TO_LINE+L at column C is represented by
+ START_LOCATION+(L*(1<<column_bits))+C, as long as C<(1<<column_bits),
+ and the result_location is less than the next line_map's start_location.
+ (The top line is line 1 and the leftmost column is column 1; line/column 0
+ means "entire file/line" or "unknown line/column" or "not applicable".)
+ INCLUDED_FROM is an index into the set that gives the line mapping
+ at whose end the current one was included. File(s) at the bottom
+ of the include stack have this set to -1. REASON is the reason for
+ creation of this line map, SYSP is one for a system header, two for
+ a C system header file that therefore needs to be extern "C"
+ protected in C++, and zero otherwise. */
+struct line_map
+{
+ const char *to_file;
+ unsigned int to_line;
+ source_location start_location;
+ int included_from;
+ ENUM_BITFIELD (lc_reason) reason : CHAR_BIT;
+ /* The sysp field isn't really needed now that it's in cpp_buffer. */
+ unsigned char sysp;
+ /* Number of the low-order source_location bits used for a column number. */
+ unsigned int column_bits : 8;
+};
+
+/* A set of chronological line_map structures. */
+struct line_maps
+{
+ struct line_map *maps;
+ unsigned int allocated;
+ unsigned int used;
+
+ unsigned int cache;
+
+ /* The most recently listed include stack, if any, starts with
+ LAST_LISTED as the topmost including file. -1 indicates nothing
+ has been listed yet. */
+ int last_listed;
+
+ /* Depth of the include stack, including the current file. */
+ unsigned int depth;
+
+ /* If true, prints an include trace a la -H. */
+ bool trace_includes;
+
+ /* Highest source_location "given out". */
+ source_location highest_location;
+
+ /* Start of line of highest source_location "given out". */
+ source_location highest_line;
+
+ /* The maximum column number we can quickly allocate. Higher numbers
+ may require allocating a new line_map. */
+ unsigned int max_column_hint;
+};
+
+/* Initialize a line map set. */
+extern void linemap_init (struct line_maps *);
+
+/* Free a line map set. */
+extern void linemap_free (struct line_maps *);
+
+/* Check for and warn about line_maps entered but not exited. */
+
+extern void linemap_check_files_exited (struct line_maps *);
+
+/* Return a source_location for the start (i.e. column==0) of
+ (physical) line TO_LINE in the current source file (as in the
+ most recent linemap_add). MAX_COLUMN_HINT is the highest column
+ number we expect to use in this line (but it does not change
+ the highest_location). */
+
+extern source_location linemap_line_start
+(struct line_maps *set, unsigned int to_line, unsigned int max_column_hint);
+
+/* 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 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.
+
+ 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 *linemap_add
+ (struct line_maps *, enum lc_reason, unsigned int sysp,
+ 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 *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 linemap_print_containing_files (struct line_maps *,
+ const struct line_map *);
+
+/* Converts a map and a source_location to source line. */
+#define SOURCE_LINE(MAP, LINE) \
+ ((((LINE) - (MAP)->start_location) >> (MAP)->column_bits) + (MAP)->to_line)
+
+#define SOURCE_COLUMN(MAP, LINE) \
+ (((LINE) - (MAP)->start_location) & ((1 << (MAP)->column_bits) - 1))
+
+/* Returns the last source line within a map. This is the (last) line
+ of the #include, or other directive, that caused a map change. */
+#define LAST_SOURCE_LINE(MAP) \
+ SOURCE_LINE (MAP, LAST_SOURCE_LINE_LOCATION (MAP))
+#define LAST_SOURCE_LINE_LOCATION(MAP) \
+ ((((MAP)[1].start_location - 1 - (MAP)->start_location) \
+ & ~((1 << (MAP)->column_bits) - 1)) \
+ + (MAP)->start_location)
+
+/* Returns the map a given map was included from. */
+#define INCLUDED_FROM(SET, MAP) (&(SET)->maps[(MAP)->included_from])
+
+/* Nonzero if the map is at the bottom of the include stack. */
+#define MAIN_FILE_P(MAP) ((MAP)->included_from < 0)
+
+/* Set LOC to a source position that is the same line as the most recent
+ linemap_line_start, but with the specified TO_COLUMN column number. */
+
+#define LINEMAP_POSITION_FOR_COLUMN(LOC, SET, TO_COLUMN) { \
+ unsigned int to_column = (TO_COLUMN); \
+ struct line_maps *set = (SET); \
+ if (__builtin_expect (to_column >= set->max_column_hint, 0)) \
+ (LOC) = linemap_position_for_column (set, to_column); \
+ else { \
+ source_location r = set->highest_line; \
+ r = r + to_column; \
+ if (r >= set->highest_location) \
+ set->highest_location = r; \
+ (LOC) = r; \
+ }}
+
+
+extern source_location
+linemap_position_for_column (struct line_maps *set, unsigned int to_column);
+#endif /* !LIBCPP_LINE_MAP_H */
--- /dev/null
+/* Dependency generator for Makefile fragments.
+ 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
+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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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! */
+
+#ifndef LIBCPP_MKDEPS_H
+#define LIBCPP_MKDEPS_H
+
+/* This is the data structure used by all the functions in mkdeps.c.
+ It's quite straightforward, but should be treated as opaque. */
+
+struct deps;
+struct cpp_reader;
+
+/* Create a deps buffer. */
+extern struct deps *deps_init (void);
+
+/* Destroy a deps buffer. */
+extern void deps_free (struct deps *);
+
+/* Add a set of "vpath" directories. The second argument is a colon-
+ separated list of pathnames, like you would set Make's VPATH
+ variable to. If a dependency or target name begins with any of
+ these pathnames (and the next path element is not "..") that
+ pathname is stripped off. */
+extern void deps_add_vpath (struct deps *, const char *);
+
+/* 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 (struct deps *, const char *, int);
+
+/* Sets the default target if none has been given already. An empty
+ 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 (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 (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 (const struct deps *, FILE *);
+
+#endif /* ! LIBCPP_MKDEPS_H */
--- /dev/null
+/* Hash tables.
+ Copyright (C) 2000, 2001, 2003, 2004 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef LIBCPP_SYMTAB_H
+#define LIBCPP_SYMTAB_H
+
+#if defined(__APPLE__) && defined(__MACH__)
+#include "libiberty/obstack.h"
+#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. */
+typedef struct ht_identifier ht_identifier;
+struct ht_identifier GTY(())
+{
+ const unsigned char *str;
+ unsigned int len;
+ unsigned int hash_value;
+};
+
+#define HT_LEN(NODE) ((NODE)->len)
+#define HT_STR(NODE) ((NODE)->str)
+
+typedef struct ht hash_table;
+typedef struct ht_identifier *hashnode;
+
+enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC, HT_ALLOCED};
+
+/* An identifier hash table for cpplib and the front ends. */
+struct ht
+{
+ /* Identifiers are allocated from here. */
+ struct obstack stack;
+
+ hashnode *entries;
+ /* Call back, allocate a node. */
+ hashnode (*alloc_node) (hash_table *);
+ /* Call back, allocate something that hangs off a node like a cpp_macro.
+ NULL means use the usual allocator. */
+ void * (*alloc_subobject) (size_t);
+
+ unsigned int nslots; /* Total slots in the entries array. */
+ unsigned int nelements; /* Number of live elements. */
+
+ /* Link to reader, if any. For the benefit of cpplib. */
+ struct cpp_reader *pfile;
+
+ /* Table usage statistics. */
+ unsigned int searches;
+ unsigned int collisions;
+
+ /* Should 'entries' be freed when it is no longer needed? */
+ bool entries_owned;
+};
+
+/* Initialize the hashtable with 2 ^ order entries. */
+extern hash_table *ht_create (unsigned int order);
+
+/* Frees all memory associated with a hash table. */
+extern void ht_destroy (hash_table *);
+
+extern hashnode ht_lookup (hash_table *, const unsigned char *,
+ size_t, enum ht_lookup_option);
+extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
+ size_t, unsigned int,
+ enum ht_lookup_option);
+#define HT_HASHSTEP(r, c) ((r) * 67 + ((c) - 113));
+#define HT_HASHFINISH(r, len) ((r) + (len))
+
+/* 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) (struct cpp_reader *, hashnode, const void *);
+extern void ht_forall (hash_table *, ht_cb, const void *);
+
+/* Restore the hash table. */
+extern void ht_load (hash_table *ht, hashnode *entries,
+ unsigned int nslots, unsigned int nelements, bool own);
+
+/* Dump allocation statistics to stderr. */
+extern void ht_dump_statistics (hash_table *);
+
+#endif /* LIBCPP_SYMTAB_H */
--- /dev/null
+/* CPP Library.
+ Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "internal.h"
+#include "mkdeps.h"
+#ifdef ENABLE_NLS
+#include "localedir.h"
+#endif
+
+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
+ 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 (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
+
+/* A set of booleans indicating what CPP features each source language
+ requires. */
+struct lang_flags
+{
+ char c99;
+ char cplusplus;
+ char extended_numbers;
+ char extended_identifiers;
+ char std;
+ char cplusplus_comments;
+ char digraphs;
+};
+
+static const struct lang_flags lang_defaults[] =
+{ /* c99 c++ xnum xid std // digr */
+ /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1 },
+ /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1 },
+ /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0 },
+ /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1 },
+ /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1 },
+ /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1 },
+ /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1 },
+ /* ASM */ { 0, 0, 1, 0, 0, 1, 0 }
+ /* xid should be 1 for GNUC99, STDC99, GNUCXX and CXX98 when no
+ longer experimental (when all uses of identifiers in the compiler
+ have been audited for correct handling of extended
+ identifiers). */
+};
+
+/* Sets internal flags correctly for a given language. */
+void
+cpp_set_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, extended_identifiers) = l->extended_identifiers;
+ CPP_OPTION (pfile, std) = l->std;
+ CPP_OPTION (pfile, trigraphs) = l->std;
+ CPP_OPTION (pfile, cplusplus_comments) = l->cplusplus_comments;
+ CPP_OPTION (pfile, digraphs) = l->digraphs;
+}
+
+/* Initialize library global state. */
+static void
+init_library (void)
+{
+ static int initialized = 0;
+
+ if (! initialized)
+ {
+ initialized = 1;
+
+ /* 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 ();
+
+#ifdef ENABLE_NLS
+ (void) bindtextdomain (PACKAGE, LOCALEDIR);
+#endif
+ }
+}
+
+/* Initialize a cpp_reader structure. */
+cpp_reader *
+cpp_create_reader (enum c_lang lang, hash_table *table,
+ struct line_maps *line_table)
+{
+ cpp_reader *pfile;
+
+ /* Initialize this instance of the library if it hasn't been already. */
+ init_library ();
+
+ pfile = XCNEW (cpp_reader);
+
+ cpp_set_lang (pfile, lang);
+ 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, dollars_in_ident) = 1;
+ CPP_OPTION (pfile, warn_dollars) = 1;
+ CPP_OPTION (pfile, warn_variadic_macros) = 1;
+ CPP_OPTION (pfile, warn_normalize) = normalized_C;
+
+ /* 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;
+ CPP_OPTION (pfile, bytes_big_endian) = 1; /* does not matter */
+
+ /* Default to no charset conversion. */
+ CPP_OPTION (pfile, narrow_charset) = _cpp_default_encoding ();
+ CPP_OPTION (pfile, wide_charset) = 0;
+
+ /* Default the input character set to UTF-8. */
+ 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. */
+ pfile->line_table = line_table;
+
+ /* 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. */
+ _obstack_begin (&pfile->buffer_ob, 0, 0,
+ (void *(*) (long)) xmalloc,
+ (void (*) (void *)) free);
+
+ _cpp_init_files (pfile);
+
+ _cpp_init_hashtable (pfile, table);
+
+ return pfile;
+}
+
+/* Free resources used by PFILE. Accessing PFILE after this function
+ returns leads to undefined behavior. Returns the error count. */
+void
+cpp_destroy (cpp_reader *pfile)
+{
+ cpp_context *context, *contextn;
+ tokenrun *run, *runn;
+
+ 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 (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_files (pfile);
+ _cpp_destroy_iconv (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 (context = pfile->base_context.next; context; context = contextn)
+ {
+ contextn = context->next;
+ free (context);
+ }
+
+ 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
+ macro.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 (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->is_directive = 0;
+ hp->directive_index = b->value;
+ }
+}
+
+/* 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);
+
+ if (CPP_OPTION (pfile, traditional))
+ n -= 2;
+ else if (! CPP_OPTION (pfile, stdc_0_in_system_headers)
+ || CPP_OPTION (pfile, std))
+ {
+ n--;
+ _cpp_define_builtin (pfile, "__STDC__ 1");
+ }
+
+ 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 = (enum builtin_type) 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 (hosted)
+ _cpp_define_builtin (pfile, "__STDC_HOSTED__ 1");
+ else
+ _cpp_define_builtin (pfile, "__STDC_HOSTED__ 0");
+
+ 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 (cpp_reader *);
+static void sanity_checks (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, CPP_DL_ICE, "cppchar_t must be an unsigned type");
+
+ if (CPP_OPTION (pfile, precision) > max_precision)
+ 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, 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, 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, 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, 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, CPP_DL_ICE,
+ "CPP half-integer narrower than CPP character");
+
+ if (CPP_OPTION (pfile, wchar_precision) > BITS_PER_CPPCHAR_T)
+ 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));
+}
+#else
+# define sanity_checks(PFILE)
+#endif
+
+/* This is called after options have been parsed, and partially
+ processed. */
+void
+cpp_post_options (cpp_reader *pfile)
+{
+ sanity_checks (pfile);
+
+ post_options (pfile);
+
+ /* 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)
+ pfile->deps = deps_init ();
+
+ /* Set the default target (if there is none already). */
+ deps_add_default_target (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;
+
+ _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);
+ fname = pfile->line_table->maps[pfile->line_table->used-1].to_file;
+ }
+ return fname;
+}
+
+/* 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 (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)
+ {
+ 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;
+ }
+ }
+
+ /* Backup as if nothing happened. */
+ _cpp_backup_tokens (pfile, 1);
+}
+
+/* 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)
+{
+ const cpp_token *hash, *token;
+
+ /* 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)
+ {
+ _cpp_backup_tokens (pfile, 1);
+ return;
+ }
+
+ token = _cpp_lex_direct (pfile);
+
+ if (token->type != CPP_NUMBER)
+ {
+ _cpp_backup_tokens (pfile, 2);
+ return;
+ }
+
+ 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)
+ {
+ char *debugdir = (char *) alloca (token->val.str.len - 3);
+
+ memcpy (debugdir, (const char *) token->val.str.text + 1,
+ token->val.str.len - 4);
+ debugdir[token->val.str.len - 4] = '\0';
+
+ pfile->cb.dir_change (pfile, debugdir);
+ }
+}
+
+/* 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 (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);
+
+ /* lex.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;
+}
+
+static void
+post_options (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;
+ }
+
+ if (CPP_OPTION (pfile, warn_trigraphs) == 2)
+ CPP_OPTION (pfile, warn_trigraphs) = !CPP_OPTION (pfile, trigraphs);
+
+ if (CPP_OPTION (pfile, traditional))
+ {
+ 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;
+ }
+}
--- /dev/null
+/* Part of CPP library.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* This header defines all the internal data structures and functions
+ that need to be visible across files. It should not be used outside
+ cpplib. */
+
+#ifndef LIBCPP_INTERNAL_H
+#define LIBCPP_INTERNAL_H
+
+#include "symtab.h"
+#include "cpp-id-data.h"
+
+#ifndef HAVE_ICONV_H
+#undef HAVE_ICONV
+#endif
+
+#if 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;
+};
+
+#define BITS_PER_CPPCHAR_T (CHAR_BIT * sizeof (cppchar_t))
+
+/* Test if a sign is valid within a preprocessing number. */
+#define VALID_SIGN(c, prevc) \
+ (((c) == '+' || (c) == '-') && \
+ ((prevc) == 'e' || (prevc) == 'E' \
+ || (((prevc) == 'p' || (prevc) == 'P') \
+ && CPP_OPTION (pfile, extended_numbers))))
+
+#define CPP_OPTION(PFILE, OPTION) ((PFILE)->opts.OPTION)
+#define CPP_BUFFER(PFILE) ((PFILE)->buffer)
+#define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base)
+#define CPP_BUF_COL(BUF) CPP_BUF_COLUMN(BUF, (BUF)->cur)
+
+#define CPP_INCREMENT_LINE(PFILE, COLS_HINT) do { \
+ const struct line_maps *line_table = PFILE->line_table; \
+ const struct line_map *map = &line_table->maps[line_table->used-1]; \
+ unsigned int line = SOURCE_LINE (map, line_table->highest_line); \
+ linemap_line_start (PFILE->line_table, line + 1, COLS_HINT); \
+ } while (0)
+
+/* Maximum nesting of cpp_buffers. We use a static limit, partly for
+ efficiency, and partly to limit runaway recursion. */
+#define CPP_STACK_MAX 200
+
+/* Host alignment handling. */
+struct dummy
+{
+ char c;
+ union
+ {
+ double d;
+ int *p;
+ } u;
+};
+
+#define DEFAULT_ALIGNMENT offsetof (struct dummy, u)
+#define CPP_ALIGN2(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
+#define CPP_ALIGN(size) CPP_ALIGN2 (size, DEFAULT_ALIGNMENT)
+
+#define _cpp_mark_macro_used(NODE) do { \
+ if ((NODE)->type == NT_MACRO && !((NODE)->flags & NODE_BUILTIN)) \
+ (NODE)->value.macro->used = 1; } while (0)
+
+/* A generic memory buffer, and operations on it. */
+typedef struct _cpp_buff _cpp_buff;
+struct _cpp_buff
+{
+ struct _cpp_buff *next;
+ unsigned char *base, *cur, *limit;
+};
+
+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)
+
+/* #include types. */
+enum include_type {IT_INCLUDE, IT_INCLUDE_NEXT, IT_IMPORT, IT_CMDLINE};
+
+union utoken
+{
+ const cpp_token *token;
+ const cpp_token **ptoken;
+};
+
+/* A "run" of tokens; part of a chain of runs. */
+typedef struct tokenrun tokenrun;
+struct tokenrun
+{
+ tokenrun *next, *prev;
+ cpp_token *base, *limit;
+};
+
+/* Accessor macros for struct cpp_context. */
+#define FIRST(c) ((c)->u.iso.first)
+#define LAST(c) ((c)->u.iso.last)
+#define CUR(c) ((c)->u.trad.cur)
+#define RLIMIT(c) ((c)->u.trad.rlimit)
+
+typedef struct cpp_context cpp_context;
+struct cpp_context
+{
+ /* Doubly-linked list. */
+ cpp_context *next, *prev;
+
+ union
+ {
+ /* For ISO macro expansion. Contexts other than the base context
+ are contiguous tokens. e.g. macro expansions, expanded
+ argument tokens. */
+ struct
+ {
+ union utoken first;
+ union utoken last;
+ } iso;
+
+ /* For traditional macro expansion. */
+ struct
+ {
+ const unsigned char *cur;
+ const unsigned char *rlimit;
+ } trad;
+ } u;
+
+ /* If non-NULL, a buffer used for storage related to this context.
+ When the context is popped, the buffer is released. */
+ _cpp_buff *buff;
+
+ /* For a macro context, the macro node, otherwise NULL. */
+ cpp_hashnode *macro;
+
+ /* True if utoken element is token, else ptoken. */
+ bool direct_p;
+};
+
+struct lexer_state
+{
+ /* Nonzero if first token on line is CPP_HASH. */
+ unsigned char in_directive;
+
+ /* Nonzero if in a directive that will handle padding tokens itself.
+ #include needs this to avoid problems with computed include and
+ spacing between tokens. */
+ unsigned char directive_wants_padding;
+
+ /* True if we are skipping a failed conditional group. */
+ unsigned char skipping;
+
+ /* Nonzero if in a directive that takes angle-bracketed headers. */
+ unsigned char angled_headers;
+
+ /* Nonzero if in a #if or #elif directive. */
+ unsigned char in_expression;
+
+ /* Nonzero to save comments. Turned off if discard_comments, and in
+ all directives apart from #define. */
+ unsigned char save_comments;
+
+ /* Nonzero if lexing __VA_ARGS__ is valid. */
+ unsigned char va_args_ok;
+
+ /* Nonzero if lexing poisoned identifiers is valid. */
+ unsigned char poisoned_ok;
+
+ /* Nonzero to prevent macro expansion. */
+ unsigned char prevent_expansion;
+
+ /* Nonzero when handling a deferred pragma. */
+ unsigned char in_deferred_pragma;
+
+ /* Nonzero when parsing arguments to a function-like macro. */
+ unsigned char parsing_args;
+
+ /* Nonzero if prevent_expansion is true only because output is
+ being discarded. */
+ unsigned char discarding_output;
+
+ /* Nonzero to skip evaluating part of an expression. */
+ unsigned int skip_eval;
+};
+
+/* Special nodes - identifiers with predefined significance. */
+struct spec_nodes
+{
+ cpp_hashnode *n_defined; /* defined operator */
+ cpp_hashnode *n_true; /* C++ keyword true */
+ cpp_hashnode *n_false; /* C++ keyword false */
+ cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */
+ /* SDCC _asm specific */
+ cpp_hashnode *n__asm; /* _asm ... _endasm ; */
+};
+
+typedef struct _cpp_line_note _cpp_line_note;
+struct _cpp_line_note
+{
+ /* Location in the clean line the note refers to. */
+ const unsigned char *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 location. */
+ const unsigned char *line_base; /* Start of current physical line. */
+ const unsigned char *next_line; /* Start of to-be-cleaned logical line. */
+
+ const unsigned char *buf; /* Entire character buffer. */
+ const unsigned char *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. */
+
+ struct cpp_buffer *prev;
+
+ /* 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;
+
+ /* 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,
+ or for -Wtraditional, and only once per file (otherwise it would
+ be far too noisy). */
+ unsigned int warned_cplusplus_comments : 1;
+
+ /* True if we don't process trigraphs and escaped newlines. True
+ for preprocessed input, command line directives, and _Pragma
+ buffers. */
+ unsigned int from_stage3 : 1;
+
+ /* 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. */
+ unsigned int return_at_eof : 1;
+
+ /* One for a system header, two for a C system header file that therefore
+ needs to be extern "C" protected in C++, and zero otherwise. */
+ unsigned char sysp;
+
+ /* 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 cpp_dir dir;
+
+ /* Descriptor for converting from the input character set to the
+ source character set. */
+ struct cset_converter input_cset_desc;
+};
+
+/* A cpp_reader encapsulates the "state" of a pre-processor run.
+ Applying cpp_get_token repeatedly yields a stream of pre-processor
+ tokens. Usually, there is only one cpp_reader object active. */
+struct cpp_reader
+{
+ /* Top of buffer stack. */
+ cpp_buffer *buffer;
+
+ /* Overlaid buffer (can be different after processing #include). */
+ cpp_buffer *overlaid_buffer;
+
+ /* Lexer state. */
+ struct lexer_state state;
+
+ /* Source line tracking. */
+ struct line_maps *line_table;
+
+ /* The line of the '#' of the current directive. */
+ source_location directive_line;
+
+ /* Memory buffers. */
+ _cpp_buff *a_buff; /* Aligned permanent storage. */
+ _cpp_buff *u_buff; /* Unaligned permanent storage. */
+ _cpp_buff *free_buffs; /* Free buffer chain. */
+
+ /* Context stack. */
+ struct cpp_context base_context;
+ struct cpp_context *context;
+
+ /* If in_directive, the directive if known. */
+ const struct directive *directive;
+
+ /* Token generated while handling a directive, if any. */
+ cpp_token directive_result;
+
+ /* 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;
+
+ /* 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;
+
+ /* Lexing. */
+ cpp_token *cur_token;
+ tokenrun base_run, *cur_run;
+ unsigned int lookaheads;
+
+ /* Nonzero prevents the lexer from re-using the token runs. */
+ unsigned int keep_tokens;
+
+ /* Error counter for exit code. */
+ unsigned int errors;
+
+ /* Buffer to hold macro definition string. */
+ unsigned char *macro_buffer;
+ unsigned int macro_buffer_len;
+
+ /* Descriptor for converting from the source character set to the
+ execution character set. */
+ struct cset_converter narrow_cset_desc;
+
+ /* 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 unsigned char *date;
+ const unsigned char *time;
+
+ /* EOF token, and a token forcing paste avoidance. */
+ cpp_token avoid_paste;
+ cpp_token eof;
+
+ /* Opaque handle to the dependencies of mkdeps.c. */
+ struct deps *deps;
+
+ /* Obstack holding all macro hash nodes. This never shrinks.
+ See identifiers.c */
+ struct obstack hash_ob;
+
+ /* Obstack holding buffer and conditional structures. This is a
+ real stack. See directives.c. */
+ struct obstack buffer_ob;
+
+ /* Pragma table - dynamic, because a library user can add to the
+ list of recognized pragmas. */
+ struct pragma_entry *pragmas;
+
+ /* Call backs to cpplib client. */
+ struct cpp_callbacks cb;
+
+ /* Identifier hash table. */
+ struct ht *hash_table;
+
+ /* Expression parser stack. */
+ struct op *op_stack, *op_limit;
+
+ /* User visible options. */
+ struct cpp_options opts;
+
+ /* Special nodes - identifiers with predefined significance to the
+ preprocessor. */
+ struct spec_nodes spec_nodes;
+
+ /* Whether cpplib owns the hashtable. */
+ bool our_hashtable;
+
+ /* Traditional preprocessing output buffer (a logical line). */
+ struct
+ {
+ unsigned char *base;
+ unsigned char *limit;
+ unsigned char *cur;
+ source_location first_line;
+ } out;
+
+ /* Used for buffer overlays by traditional.c. */
+ const unsigned char *saved_cur, *saved_rlimit, *saved_line_base;
+
+ /* 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.
+ If the definition of `numchar' looks odd to you, please look up the
+ definition of a pp-number in the C standard [section 6.4.8 of C99].
+
+ In the unlikely event that characters other than \r and \n enter
+ the set is_vspace, the macro handle_newline() in lex.c must be
+ updated. */
+#define _dollar_ok(x) ((x) == '$' && CPP_OPTION (pfile, dollars_in_ident))
+
+#define is_idchar(x) (ISIDNUM(x) || _dollar_ok(x))
+#define is_numchar(x) ISIDNUM(x)
+#define is_idstart(x) (ISIDST(x) || _dollar_ok(x))
+#define is_numstart(x) ISDIGIT(x)
+#define is_hspace(x) ISBLANK(x)
+#define is_vspace(x) IS_VSPACE(x)
+#define is_nvspace(x) IS_NVSPACE(x)
+#define is_space(x) IS_SPACE_OR_NUL(x)
+
+/* This table is constant if it can be initialized at compile time,
+ which is the case if cpp was compiled with GCC >=2.7, or another
+ compiler that supports C99. */
+#if HAVE_DESIGNATED_INITIALIZERS
+extern const unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
+#else
+extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
+#endif
+
+/* Macros. */
+
+static inline int cpp_in_system_header (cpp_reader *);
+static inline int
+cpp_in_system_header (cpp_reader *pfile)
+{
+ return pfile->buffer ? pfile->buffer->sysp : 0;
+}
+#define CPP_PEDANTIC(PF) CPP_OPTION (PF, pedantic)
+#define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, warn_traditional)
+
+/* In errors.c */
+extern int _cpp_begin_message (cpp_reader *, int,
+ source_location, unsigned int);
+
+/* In macro.c */
+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 unsigned char *, 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 unsigned char *_cpp_builtin_macro_text (cpp_reader *,
+ cpp_hashnode *);
+int _cpp_warn_if_unused_macro (cpp_reader *, cpp_hashnode *, void *);
+/* In identifiers.c */
+extern void _cpp_init_hashtable (cpp_reader *, hash_table *);
+extern void _cpp_destroy_hashtable (cpp_reader *);
+
+/* In files.c */
+typedef struct _cpp_file _cpp_file;
+extern _cpp_file *_cpp_find_file (cpp_reader *, const char *, cpp_dir *,
+ bool, 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 *);
+extern bool _cpp_save_file_entries (cpp_reader *pfile, FILE *f);
+extern bool _cpp_read_file_entries (cpp_reader *, FILE *);
+
+/* In expr.c */
+extern bool _cpp_parse_expr (cpp_reader *);
+extern struct op *_cpp_expand_op_stack (cpp_reader *);
+
+/* In lex.c */
+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 init.c. */
+extern void _cpp_maybe_push_include_file (cpp_reader *);
+
+/* In directives.c */
+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 traditional.c. */
+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 unsigned char *,
+ 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 unsigned char *_cpp_copy_replacement_text (const cpp_macro *,
+ unsigned char *);
+extern size_t _cpp_replacement_text_len (const cpp_macro *);
+
+/* In charset.c. */
+
+/* The normalization state at this point in the sequence.
+ It starts initialized to all zeros, and at the end
+ 'level' is the normalization level of the sequence. */
+
+struct normalize_state
+{
+ /* The previous character. */
+ cppchar_t previous;
+ /* The combining class of the previous character. */
+ unsigned char prev_class;
+ /* The lowest normalization level so far. */
+ enum cpp_normalize_level level;
+};
+#define INITIAL_NORMALIZE_STATE { 0, 0, normalized_KC }
+#define NORMALIZE_STATE_RESULT(st) ((st)->level)
+
+/* We saw a character that matches ISIDNUM(), update a
+ normalize_state appropriately. */
+#define NORMALIZE_STATE_UPDATE_IDNUM(st) \
+ ((st)->previous = 0, (st)->prev_class = 0)
+
+extern cppchar_t _cpp_valid_ucn (cpp_reader *, const unsigned char **,
+ const unsigned char *, int,
+ struct normalize_state *state);
+extern void _cpp_destroy_iconv (cpp_reader *);
+extern unsigned char *_cpp_convert_input (cpp_reader *, const char *,
+ unsigned char *, size_t, size_t,
+ off_t *);
+extern const char *_cpp_default_encoding (void);
+extern cpp_hashnode * _cpp_interpret_identifier (cpp_reader *pfile,
+ const unsigned char *id,
+ size_t len);
+
+/* Utility routines and macros. */
+#define DSC(str) (const unsigned char *)str, sizeof str - 1
+
+/* These are inline functions instead of macros so we can get type
+ checking. */
+static inline int ustrcmp (const unsigned char *, const unsigned char *);
+static inline int ustrncmp (const unsigned char *, const unsigned char *,
+ size_t);
+static inline size_t ustrlen (const unsigned char *);
+static inline unsigned char *uxstrdup (const unsigned char *);
+static inline unsigned char *ustrchr (const unsigned char *, int);
+static inline int ufputs (const unsigned char *, FILE *);
+
+/* Use a const char for the second parameter since it is usually a literal. */
+static inline int ustrcspn (const unsigned char *, const char *);
+
+static inline int
+ustrcmp (const unsigned char *s1, const unsigned char *s2)
+{
+ return strcmp ((const char *)s1, (const char *)s2);
+}
+
+static inline int
+ustrncmp (const unsigned char *s1, const unsigned char *s2, size_t n)
+{
+ return strncmp ((const char *)s1, (const char *)s2, n);
+}
+
+static inline int
+ustrcspn (const unsigned char *s1, const char *s2)
+{
+ return strcspn ((const char *)s1, s2);
+}
+
+static inline size_t
+ustrlen (const unsigned char *s1)
+{
+ return strlen ((const char *)s1);
+}
+
+static inline unsigned char *
+uxstrdup (const unsigned char *s1)
+{
+ return (unsigned char *) xstrdup ((const char *)s1);
+}
+
+static inline unsigned char *
+ustrchr (const unsigned char *s1, int c)
+{
+ return (unsigned char *) strchr ((const char *)s1, c);
+}
+
+static inline int
+ufputs (const unsigned char *s, FILE *f)
+{
+ return fputs ((const char *)s, f);
+}
+
+#endif /* ! LIBCPP_INTERNAL_H */
--- /dev/null
+/* CPP Library - lexical analysis.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 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
+
+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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "internal.h"
+#include <assert.h>
+
+enum spell_type
+{
+ SPELL_OPERATOR = 0,
+ SPELL_IDENT,
+ SPELL_LITERAL,
+ SPELL_NONE
+};
+
+struct token_spelling
+{
+ enum spell_type category;
+ const unsigned char *name;
+};
+
+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) { SPELL_ ## 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)
+
+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 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 (const cpp_token *token, const char *string)
+{
+ if (token->type != CPP_NAME)
+ return 0;
+
+ return !ustrcmp (NODE_NAME (token->val.node), (const uchar *) string);
+}
+
+/* Record a note TYPE at byte POS into the current cleaned logical
+ line. */
+static void
+add_line_note (cpp_buffer *buffer, const uchar *pos, unsigned int type)
+{
+ if (buffer->notes_used == buffer->notes_cap)
+ {
+ buffer->notes_cap = buffer->notes_cap * 2 + 200;
+ buffer->notes = XRESIZEVEC (_cpp_line_note, buffer->notes,
+ buffer->notes_cap);
+ }
+
+ buffer->notes[buffer->notes_used].pos = pos;
+ buffer->notes[buffer->notes_used].type = type;
+ buffer->notes_used++;
+}
+
+/* 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;
+ 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;
+
+ if (!buffer->from_stage3)
+ {
+ /* 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 (;;)
+ {
+ c = *++s;
+ if (c == '\n' || c == '\r')
+ {
+ 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;
+ }
+ }
+ }
+
+
+ for (;;)
+ {
+ c = *++s;
+ *++d = c;
+
+ if (c == '\n' || c == '\r')
+ {
+ /* Handle DOS line endings. */
+ if (c == '\r' && s != buffer->rlimit && s[1] == '\n')
+ s++;
+ if (s == buffer->rlimit)
+ break;
+
+ /* Escaped? */
+ p = d;
+ while (p != buffer->next_line && is_nvspace (p[-1]))
+ p--;
+ if (p == buffer->next_line || p[-1] != '\\')
+ break;
+
+ 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]])
+ {
+ /* 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
+ {
+ do
+ s++;
+ while (*s != '\n' && *s != '\r');
+ d = (uchar *) s;
+
+ /* 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);
+}
+
+/* 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)
+{
+ cpp_buffer *buffer = pfile->buffer;
+
+ 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_table->highest_line, col,
+ "backslash and newline separated by space");
+
+ if (buffer->next_line > buffer->rlimit)
+ {
+ cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line, col,
+ "backslash-newline at end of file");
+ /* Prevent "no newline at end of file" warning. */
+ buffer->next_line = buffer->rlimit;
+ }
+
+ buffer->line_base = note->pos;
+ CPP_INCREMENT_LINE (pfile, 0);
+ }
+ 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_table->highest_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_table->highest_line, col,
+ "trigraph ??%c ignored, use -trigraphs to enable",
+ note->type);
+ }
+ }
+ }
+ else
+ abort ();
+ }
+}
+
+/* SDCC _asm specific */
+/* Skip an _asm ... _endasm block. We find the end of the comment by
+ seeing _endasm. Returns non-zero if _asm terminated by EOF, zero
+ otherwise. */
+static int
+skip_asm_block (cpp_reader *pfile)
+{
+#define _ENDASM_STR "endasm"
+#define _ENDASM_LEN ((sizeof _ENDASM_STR) - 1)
+
+ cpp_buffer *buffer = pfile->buffer;
+ cppchar_t c = EOF;
+ int prev_space = 0;
+ int ret = 1;
+
+ while (buffer->cur != buffer->rlimit)
+ {
+ prev_space = is_space(c);
+ c = *buffer->cur++;
+
+ if (prev_space && c == '_')
+ {
+ if (buffer->cur + _ENDASM_LEN <= buffer->rlimit &&
+ strncmp(buffer->cur, _ENDASM_STR, _ENDASM_LEN) == 0)
+ {
+ buffer->cur += _ENDASM_LEN;
+ ret = 0;
+ break;
+ }
+ }
+ else if (c == '\n')
+ {
+ unsigned int cols;
+ --buffer->cur;
+ _cpp_process_line_notes (pfile, true);
+ if (buffer->next_line >= buffer->rlimit)
+ return true;
+ _cpp_clean_line (pfile);
+
+ cols = buffer->next_line - buffer->line_base;
+ CPP_INCREMENT_LINE (pfile, cols);
+ }
+ }
+
+ _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.
+
+ Buffer->cur points to the initial asterisk of the comment. */
+bool
+_cpp_skip_block_comment (cpp_reader *pfile)
+{
+ cpp_buffer *buffer = pfile->buffer;
+ const uchar *cur = buffer->cur;
+ uchar c;
+
+ cur++;
+ if (*cur == '/')
+ cur++;
+
+ for (;;)
+ {
+ /* People like decorating comments with '*', so check for '/'
+ instead for efficiency. */
+ c = *cur++;
+
+ if (c == '/')
+ {
+ 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)
+ && cur[0] == '*' && cur[1] != '/')
+ {
+ buffer->cur = cur;
+ cpp_error_with_line (pfile, CPP_DL_WARNING,
+ pfile->line_table->highest_line, CPP_BUF_COL (buffer),
+ "\"/*\" within comment");
+ }
+ }
+ else if (c == '\n')
+ {
+ unsigned int cols;
+ buffer->cur = cur - 1;
+ _cpp_process_line_notes (pfile, true);
+ if (buffer->next_line >= buffer->rlimit)
+ return true;
+ _cpp_clean_line (pfile);
+
+ cols = buffer->next_line - buffer->line_base;
+ CPP_INCREMENT_LINE (pfile, cols);
+
+ cur = buffer->cur;
+ }
+ }
+
+ 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 (cpp_reader *pfile)
+{
+ cpp_buffer *buffer = pfile->buffer;
+ unsigned int orig_line = pfile->line_table->highest_line;
+
+ while (*buffer->cur != '\n')
+ buffer->cur++;
+
+ _cpp_process_line_notes (pfile, true);
+ return orig_line != pfile->line_table->highest_line;
+}
+
+/* Skips whitespace, saving the next non-whitespace character. */
+static void
+skip_whitespace (cpp_reader *pfile, cppchar_t c)
+{
+ cpp_buffer *buffer = pfile->buffer;
+ bool saw_NUL = false;
+
+ do
+ {
+ /* Horizontal space always OK. */
+ if (c == ' ' || c == '\t')
+ ;
+ /* Just \f \v or \0 left. */
+ else if (c == '\0')
+ saw_NUL = true;
+ else if (pfile->state.in_directive && CPP_PEDANTIC (pfile))
+ cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line,
+ CPP_BUF_COL (buffer),
+ "%s in preprocessing directive",
+ c == '\f' ? "form feed" : "vertical tab");
+
+ c = *buffer->cur++;
+ }
+ /* 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--;
+}
+
+/* See if the characters of a number token are valid in a name (no
+ '.', '+' or '-'). */
+static int
+name_p (cpp_reader *pfile, const cpp_string *string)
+{
+ unsigned int i;
+
+ for (i = 0; i < string->len; i++)
+ if (!is_idchar (string->text[i]))
+ return 0;
+
+ return 1;
+}
+
+/* After parsing an identifier or other sequence, produce a warning about
+ sequences not in NFC/NFKC. */
+static void
+warn_about_normalization (cpp_reader *pfile,
+ const cpp_token *token,
+ const struct normalize_state *s)
+{
+ if (CPP_OPTION (pfile, warn_normalize) < NORMALIZE_STATE_RESULT (s)
+ && !pfile->state.skipping)
+ {
+ /* Make sure that the token is printed using UCNs, even
+ if we'd otherwise happily print UTF-8. */
+ unsigned char *buf = XNEWVEC (unsigned char, cpp_token_len (token));
+ size_t sz;
+
+ sz = cpp_spell_token (pfile, token, buf, false) - buf;
+ if (NORMALIZE_STATE_RESULT (s) == normalized_C)
+ cpp_error_with_line (pfile, CPP_DL_WARNING, token->src_loc, 0,
+ "`%.*s' is not in NFKC", (int) sz, buf);
+ else
+ cpp_error_with_line (pfile, CPP_DL_WARNING, token->src_loc, 0,
+ "`%.*s' is not in NFC", (int) sz, buf);
+ }
+}
+
+/* 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,
+ struct normalize_state *state)
+{
+ cpp_buffer *buffer = pfile->buffer;
+
+ if (*buffer->cur == '$')
+ {
+ if (!CPP_OPTION (pfile, dollars_in_ident))
+ return false;
+
+ 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;
+ }
+
+ /* Is this a syntactically valid UCN? */
+ if (CPP_OPTION (pfile, extended_identifiers)
+ && *buffer->cur == '\\'
+ && (buffer->cur[1] == 'u' || buffer->cur[1] == 'U'))
+ {
+ buffer->cur += 2;
+ if (_cpp_valid_ucn (pfile, &buffer->cur, buffer->rlimit, 1 + !first,
+ state))
+ 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, bool starts_ucn,
+ struct normalize_state *nst)
+{
+ cpp_hashnode *result;
+ const uchar *cur;
+ unsigned int len;
+ unsigned int hash = HT_HASHSTEP (0, *base);
+
+ cur = pfile->buffer->cur;
+ if (! starts_ucn)
+ while (ISIDNUM (*cur))
+ {
+ hash = HT_HASHSTEP (hash, *cur);
+ cur++;
+ }
+ pfile->buffer->cur = cur;
+ if (starts_ucn || forms_identifier_p (pfile, false, nst))
+ {
+ /* Slower version for identifiers containing UCNs (or $). */
+ do {
+ while (ISIDNUM (*pfile->buffer->cur))
+ {
+ pfile->buffer->cur++;
+ NORMALIZE_STATE_UPDATE_IDNUM (nst);
+ }
+ } while (forms_identifier_p (pfile, false, nst));
+ result = _cpp_interpret_identifier (pfile, base,
+ pfile->buffer->cur - base);
+ }
+ else
+ {
+ len = cur - base;
+ hash = HT_HASHFINISH (hash, len);
+
+ result = (cpp_hashnode *)
+ ht_lookup_with_hash (pfile->hash_table, base, len, hash, HT_ALLOC);
+ }
+
+ /* 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, 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, CPP_DL_PEDWARN,
+ "__VA_ARGS__ can only appear in the expansion"
+ " of a C99 variadic macro");
+ }
+
+ return result;
+}
+
+/* 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_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;
+
+ uchar c = *(pfile->buffer->cur - 1);
+ struct obstack *stack = &pfile->hash_table->stack;
+ cpp_buffer *buffer = pfile->buffer;
+ int len = 0;
+ int has_whole = 0;
+ int has_fract = 0;
+
+ if ('.' == c)
+ {
+ num_part = NP_FRACT;
+ ++len;
+ obstack_1grow (stack, '.');
+ c = get_effective_char(pfile);
+ }
+ else
+ {
+ if ('0' == c)
+ {
+ has_whole = 1;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+
+ switch (c)
+ {
+ case 'X':
+ case 'x':
+ num_type = NT_HEX;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ break;
+
+ case '.':
+ num_part = NP_FRACT;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ break;
+ }
+ }
+ }
+
+ for (; ; )
+ {
+ switch (num_part)
+ {
+ case NP_WHOLE:
+ if (NT_DEC == num_type)
+ {
+ while (ISDIGIT (c))
+ {
+ has_whole = 1;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+
+ if ('.' == c)
+ {
+ num_part = NP_FRACT;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ continue;
+ }
+ else if ('E' == c || 'e' == c)
+ {
+ if (has_whole || has_fract)
+ {
+ num_part = NP_EXP;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ continue;
+ }
+ else
+ break;
+ }
+ }
+ else
+ {
+ while (ISXDIGIT (c))
+ {
+ has_whole = 1;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+
+ if ('.' == c)
+ {
+ num_part = NP_FRACT;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ continue;
+ }
+ else if ('P' == c || 'p' == c)
+ {
+ if (has_whole || has_fract)
+ {
+ num_part = NP_EXP;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ continue;
+ }
+ else
+ break;
+ }
+ }
+ num_part = NP_INT_SUFFIX;
+ continue;
+
+ case NP_FRACT:
+ if (NT_DEC == num_type)
+ {
+ while (ISDIGIT (c))
+ {
+ has_fract = 1;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+
+ if ('E' == c || 'e' == c)
+ {
+ if (has_whole || has_fract)
+ {
+ num_part = NP_EXP;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ continue;
+ }
+ }
+ }
+ else
+ {
+ while (ISXDIGIT (c))
+ {
+ has_fract = 1;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+
+ if ('P' == c || 'p' == c)
+ {
+ if (has_whole || has_fract)
+ {
+ num_part = NP_EXP;
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ continue;
+ }
+ }
+ }
+ num_part = NP_FLOAT_SUFFIX;
+ continue;
+
+ case NP_EXP:
+ if ('+' == c || '-' == c)
+ {
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+
+ while (ISDIGIT (c))
+ {
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+
+ num_part = NP_FLOAT_SUFFIX;
+ continue;
+
+ case NP_INT_SUFFIX:
+ if ('L' == c || 'l' == c)
+ {
+ uchar prevc = c;
+
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+
+ if (c == prevc)
+ {
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+ }
+ else if ('U' == c || 'u' == c)
+ {
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+ break;
+
+ case NP_FLOAT_SUFFIX:
+ if ('F' == c || 'f' == c)
+ {
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+ else if ('L' == c || 'l' == c)
+ {
+ ++len;
+ obstack_1grow (stack, c);
+ c = get_effective_char(pfile);
+ }
+ break;
+ }
+ break;
+ }
+
+ /* Step back over the unwanted char. */
+ BACKUP ();
+
+ number->text = obstack_finish (stack);
+ number->len = len;
+}
+
+/* Lex a number to NUMBER starting at BUFFER->CUR - 1. */
+static void
+lex_number (cpp_reader *pfile, cpp_string *number,
+ struct normalize_state *nst)
+{
+ const uchar *cur;
+ const uchar *base;
+ uchar *dest;
+
+ base = pfile->buffer->cur - 1;
+ do
+ {
+ cur = pfile->buffer->cur;
+
+ /* N.B. ISIDNUM does not include $. */
+ while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1]))
+ {
+ cur++;
+ NORMALIZE_STATE_UPDATE_IDNUM (nst);
+ }
+
+ pfile->buffer->cur = cur;
+ }
+ while (forms_identifier_p (pfile, false, nst));
+
+ number->len = cur - base;
+ dest = _cpp_unaligned_alloc (pfile, number->len + 1);
+ memcpy (dest, base, number->len);
+ dest[number->len] = '\0';
+ number->text = 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)
+{
+ uchar *dest = _cpp_unaligned_alloc (pfile, len + 1);
+
+ memcpy (dest, base, len);
+ dest[len] = '\0';
+ token->type = type;
+ token->val.str.len = len;
+ token->val.str.text = dest;
+}
+
+/* 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.
+
+ The spelling is NUL-terminated, but it is not guaranteed that this
+ is the first NUL since embedded NULs are preserved. */
+static void
+lex_string (cpp_reader *pfile, cpp_token *token, const uchar *base)
+{
+ 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;
+
+ for (;;)
+ {
+ cppchar_t c = *cur++;
+
+ /* 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')
+ {
+ cur--;
+ type = CPP_OTHER;
+ break;
+ }
+ else if (c == '\0')
+ saw_NUL = true;
+ }
+
+ if (saw_NUL && !pfile->state.skipping)
+ cpp_error (pfile, CPP_DL_WARNING,
+ "null character(s) preserved in literal");
+
+ pfile->buffer->cur = cur;
+ create_literal (pfile, token, base, cur - base, type);
+}
+
+/* Fixed _WIN32 problem with CR-CR-LF sequences when outputting
+ comment blocks (when executed with -C option) and
+ _asm (SDCPP specific) blocks */
+
+/* Count and copy characters from src to dest, excluding CRs:
+ CRs are automatically generated, because the output is
+ opened in TEXT mode. If dest == NULL, only count chars */
+static unsigned int
+copy_text_chars (char *dest, const char *src, unsigned int len)
+{
+ unsigned int n = 0;
+ const char *p;
+
+ for (p = src; p != src + len; ++p)
+ {
+ assert(*p != '\0');
+
+ if (*p != '\r')
+ {
+ if (dest != NULL)
+ *dest++ = *p;
+ ++n;
+ }
+ }
+
+ return n;
+}
+
+/* SDCC _asm specific */
+/* The stored comment includes the comment start and any terminator. */
+static void
+save_asm (cpp_reader *pfile, cpp_token *token, const unsigned char *from)
+{
+#define _ASM_STR "_asm"
+#define _ASM_LEN ((sizeof _ASM_STR) - 1)
+
+ unsigned char *buffer;
+ unsigned int text_len, len;
+
+ len = pfile->buffer->cur - from;
+ /* + _ASM_LEN for the initial '_asm'. */
+ text_len = copy_text_chars (NULL, from, len) + _ASM_LEN;
+ buffer = _cpp_unaligned_alloc (pfile, text_len);
+
+
+ token->type = CPP_ASM;
+ token->val.str.len = text_len;
+ token->val.str.text = buffer;
+
+ memcpy (buffer, _ASM_STR, _ASM_LEN);
+ copy_text_chars (buffer + _ASM_LEN, from, len);
+}
+
+/* The stored comment includes the comment start and any terminator. */
+static void
+save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from,
+ cppchar_t type)
+{
+ unsigned char *buffer;
+ unsigned int len, clen;
+
+ len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'. */
+
+ /* C++ comments probably (not definitely) have moved past a new
+ line, which we don't want to save in the comment. */
+ if (is_vspace (pfile->buffer->cur[-1]))
+ len--;
+
+ /* If we are currently in a directive, then we need to store all
+ C++ comments as C comments internally, and so we need to
+ allocate a little extra space in that case.
+
+ Note that the only time we encounter a directive here is
+ when we are saving comments in a "#define". */
+ clen = (pfile->state.in_directive && type == '/') ? len + 2 : len;
+
+ buffer = _cpp_unaligned_alloc (pfile, clen);
+
+ token->type = CPP_COMMENT;
+ token->val.str.len = clen;
+ token->val.str.text = buffer;
+
+ buffer[0] = '/';
+ copy_text_chars (buffer + 1, from, len);
+
+ /* Finish conversion to a C comment, if necessary. */
+ if (pfile->state.in_directive && type == '/')
+ {
+ buffer[1] = '*';
+ buffer[clen - 2] = '*';
+ buffer[clen - 1] = '/';
+ }
+}
+
+/* Allocate COUNT tokens for RUN. */
+void
+_cpp_init_tokenrun (tokenrun *run, unsigned int count)
+{
+ run->base = XNEWVEC (cpp_token, count);
+ run->limit = run->base + count;
+ run->next = NULL;
+}
+
+/* Returns the next tokenrun, or creates one if there is none. */
+static tokenrun *
+next_tokenrun (tokenrun *run)
+{
+ if (run->next == NULL)
+ {
+ run->next = XNEW (tokenrun);
+ run->next->prev = run;
+ _cpp_init_tokenrun (run->next, 250);
+ }
+
+ return run->next;
+}
+
+/* Allocate a single token that is invalidated at the same time as the
+ rest of the tokens on the line. Has its line and col set to the
+ same as the last lexed token, so that diagnostics appear in the
+ right place. */
+cpp_token *
+_cpp_temp_token (cpp_reader *pfile)
+{
+ cpp_token *old, *result;
+
+ old = pfile->cur_token - 1;
+ if (pfile->cur_token == pfile->cur_run->limit)
+ {
+ pfile->cur_run = next_tokenrun (pfile->cur_run);
+ pfile->cur_token = pfile->cur_run->base;
+ }
+
+ result = pfile->cur_token++;
+ result->src_loc = old->src_loc;
+ return result;
+}
+
+/* Lex a token into RESULT (external interface). Takes care of issues
+ like directive handling, token lookahead, multiple include
+ optimization and skipping. */
+const cpp_token *
+_cpp_lex_token (cpp_reader *pfile)
+{
+ cpp_token *result;
+
+ for (;;)
+ {
+ if (pfile->cur_token == pfile->cur_run->limit)
+ {
+ pfile->cur_run = next_tokenrun (pfile->cur_run);
+ pfile->cur_token = pfile->cur_run->base;
+ }
+
+ if (pfile->lookaheads)
+ {
+ pfile->lookaheads--;
+ result = pfile->cur_token++;
+ }
+ else
+ result = _cpp_lex_direct (pfile);
+
+ if (result->flags & BOL)
+ {
+ /* Is this a directive. If _cpp_handle_directive returns
+ false, it is an assembler #. */
+ if (result->type == CPP_HASH
+ /* 6.10.3 p 11: Directives in a list of macro arguments
+ gives undefined behavior. This implementation
+ handles the directive as normal. */
+ && pfile->state.parsing_args != 1
+ && _cpp_handle_directive (pfile, result->flags & PREV_WHITE))
+ {
+ if (pfile->directive_result.type == CPP_PADDING)
+ continue;
+ else
+ {
+ result = &pfile->directive_result;
+ break;
+ }
+ }
+
+ if (pfile->cb.line_change && !pfile->state.skipping)
+ pfile->cb.line_change (pfile, result, pfile->state.parsing_args);
+ }
+
+ /* We don't skip tokens in directives. */
+ if (pfile->state.in_directive)
+ break;
+
+ /* 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 optimization works. */
+ pfile->mi_valid = false;
+
+ if (!pfile->state.skipping || result->type == CPP_EOF)
+ break;
+ }
+
+ return result;
+}
+
+/* Returns true if a fresh line has been loaded. */
+bool
+_cpp_get_fresh_line (cpp_reader *pfile)
+{
+ int return_at_eof;
+
+ /* We can't get a new line until we leave the current directive. */
+ if (pfile->state.in_directive)
+ return false;
+
+ for (;;)
+ {
+ cpp_buffer *buffer = pfile->buffer;
+
+ if (!buffer->need_line)
+ return true;
+
+ if (buffer->next_line < buffer->rlimit)
+ {
+ _cpp_clean_line (pfile);
+ return true;
+ }
+
+ /* 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_table->highest_line,
+ CPP_BUF_COLUMN (buffer, buffer->cur),
+ "no newline at end of file");
+ }
+
+ 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 \
+ { \
+ 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
+ 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.
+
+ When meeting a newline, returns CPP_EOF if parsing a directive,
+ otherwise returns to the start of the token buffer if permissible.
+ Returns the location of the lexed token. */
+cpp_token *
+_cpp_lex_direct (cpp_reader *pfile)
+{
+ cppchar_t c;
+ cpp_buffer *buffer;
+ const unsigned char *comment_start;
+ 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->src_loc = pfile->line_table->highest_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;
+ update_tokens_line:
+ result->src_loc = pfile->line_table->highest_line;
+
+ skipped_white:
+ if (buffer->cur >= buffer->notes[buffer->cur_note].pos
+ && !pfile->overlaid_buffer)
+ {
+ _cpp_process_line_notes (pfile, false);
+ result->src_loc = pfile->line_table->highest_line;
+ }
+ c = *buffer->cur++;
+
+ LINEMAP_POSITION_FOR_COLUMN (result->src_loc, pfile->line_table,
+ CPP_BUF_COLUMN (buffer, buffer->cur));
+
+ switch (c)
+ {
+ case ' ': case '\t': case '\f': case '\v': case '\0':
+ result->flags |= PREV_WHITE;
+ skip_whitespace (pfile, c);
+ goto skipped_white;
+
+ case '\n':
+ if (buffer->cur < buffer->rlimit)
+ CPP_INCREMENT_LINE (pfile, 0);
+ 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':
+ {
+ struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+ result->type = CPP_NUMBER;
+ if (CPP_OPTION(pfile, pedantic_parse_number))
+ pedantic_lex_number (pfile, &result->val.str);
+ else
+ lex_number (pfile, &result->val.str, &nst);
+ warn_about_normalization (pfile, result, &nst);
+ break;
+ }
+
+ case 'L':
+ /* 'L' may introduce wide characters or strings. */
+ if (*buffer->cur == '\'' || *buffer->cur == '"')
+ {
+ lex_string (pfile, result, buffer->cur - 1);
+ break;
+ }
+ /* Fall through. */
+
+ 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':
+ case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+ case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+ case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K':
+ case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ result->type = CPP_NAME;
+ {
+ struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+ result->val.node = lex_identifier (pfile, buffer->cur - 1, false,
+ &nst);
+ warn_about_normalization (pfile, result, &nst);
+ }
+
+ /* SDCC _asm specific */
+ /* handle _asm ... _endasm ; */
+ if (CPP_OPTION(pfile, preproc_asm) == 0 && result->val.node == pfile->spec_nodes.n__asm)
+ {
+ comment_start = buffer->cur;
+ result->type = CPP_ASM;
+ skip_asm_block (pfile);
+ /* Save the _asm block as a token in its own right. */
+ save_asm (pfile, result, comment_start);
+ }
+ /* Convert named operators to their proper types. */
+ else if (result->val.node->flags & NODE_OPERATOR)
+ {
+ result->flags |= NAMED_OP;
+ result->type = (enum cpp_ttype) result->val.node->directive_index;
+ }
+ break;
+
+ case '\'':
+ case '"':
+ lex_string (pfile, result, buffer->cur - 1);
+ break;
+
+ case '/':
+ /* A potential block or line comment. */
+ comment_start = buffer->cur;
+ c = *buffer->cur;
+
+ if (c == '*')
+ {
+ 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)))
+ {
+ /* Warn about comments only if pedantically GNUC89, and not
+ in system headers. */
+ if (CPP_OPTION (pfile, lang) == CLK_GNUC89 && CPP_PEDANTIC (pfile)
+ && ! buffer->warned_cplusplus_comments)
+ {
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "C++ style comments are not allowed in ISO C90");
+ 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, CPP_DL_WARNING, "multi-line comment");
+ }
+ else if (c == '=')
+ {
+ buffer->cur++;
+ result->type = CPP_DIV_EQ;
+ break;
+ }
+ else
+ {
+ result->type = CPP_DIV;
+ break;
+ }
+
+ if (!pfile->state.save_comments)
+ {
+ result->flags |= PREV_WHITE;
+ goto update_tokens_line;
+ }
+
+ /* Save the comment as a token in its own right. */
+ save_comment (pfile, result, comment_start, c);
+ break;
+
+ case '<':
+ if (pfile->state.angled_headers)
+ {
+ lex_string (pfile, result, buffer->cur - 1);
+ break;
+ }
+
+ result->type = CPP_LESS;
+ if (*buffer->cur == '=')
+ buffer->cur++, result->type = CPP_LESS_EQ;
+ else if (*buffer->cur == '<')
+ {
+ buffer->cur++;
+ IF_NEXT_IS ('=', CPP_LSHIFT_EQ, CPP_LSHIFT);
+ }
+ else if (*buffer->cur == '?' && CPP_OPTION (pfile, cplusplus))
+ {
+ buffer->cur++;
+ IF_NEXT_IS ('=', CPP_MIN_EQ, CPP_MIN);
+ }
+ else if (CPP_OPTION (pfile, digraphs))
+ {
+ 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 '>':
+ result->type = CPP_GREATER;
+ if (*buffer->cur == '=')
+ buffer->cur++, result->type = CPP_GREATER_EQ;
+ else if (*buffer->cur == '>')
+ {
+ 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 '%':
+ result->type = CPP_MOD;
+ if (*buffer->cur == '=')
+ buffer->cur++, result->type = CPP_MOD_EQ;
+ else if (CPP_OPTION (pfile, digraphs))
+ {
+ if (*buffer->cur == ':')
+ {
+ 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;
+ }
+ }
+ break;
+
+ case '.':
+ result->type = CPP_DOT;
+ if (ISDIGIT (*buffer->cur))
+ {
+ struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+ result->type = CPP_NUMBER;
+ if (CPP_OPTION(pfile, pedantic_parse_number))
+ pedantic_lex_number (pfile, &result->val.str);
+ else
+ lex_number (pfile, &result->val.str, &nst);
+ warn_about_normalization (pfile, result, &nst);
+ }
+ 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 '+':
+ 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 '-':
+ result->type = CPP_MINUS;
+ if (*buffer->cur == '>')
+ {
+ buffer->cur++;
+ result->type = CPP_DEREF;
+ 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 '&':
+ 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 '|':
+ 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 ':':
+ 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;
+ }
+ break;
+
+ case '*': IF_NEXT_IS ('=', CPP_MULT_EQ, CPP_MULT); break;
+ case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break;
+ case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break;
+ 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;
+ case ')': result->type = CPP_CLOSE_PAREN; break;
+ case '[': result->type = CPP_OPEN_SQUARE; break;
+ case ']': result->type = CPP_CLOSE_SQUARE; break;
+ case '{': result->type = CPP_OPEN_BRACE; break;
+ case '}': result->type = CPP_CLOSE_BRACE; break;
+ case ';': result->type = CPP_SEMICOLON; break;
+
+ /* @ is a punctuator in Objective-C. */
+ case '@': result->type = CPP_ATSIGN; break;
+
+ case '$':
+ case '\\':
+ {
+ const uchar *base = --buffer->cur;
+ struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+
+ if (forms_identifier_p (pfile, true, &nst))
+ {
+ result->type = CPP_NAME;
+ result->val.node = lex_identifier (pfile, base, true, &nst);
+ warn_about_normalization (pfile, result, &nst);
+ break;
+ }
+ buffer->cur++;
+ }
+
+ default:
+ 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.
+ Does not include preceding whitespace. */
+unsigned int
+cpp_token_len (const cpp_token *token)
+{
+ unsigned int len;
+
+ switch (TOKEN_SPELL (token))
+ {
+ default: len = 4; break;
+ case SPELL_LITERAL: len = token->val.str.len; break;
+ case SPELL_IDENT: len = NODE_LEN (token->val.node) * 10; break;
+ }
+
+ return len;
+}
+
+/* Parse UTF-8 out of NAMEP and place a \U escape in BUFFER.
+ Return the number of bytes read out of NAME. (There are always
+ 10 bytes written to BUFFER.) */
+
+static size_t
+utf8_to_ucn (unsigned char *buffer, const unsigned char *name)
+{
+ int j;
+ int ucn_len = 0;
+ int ucn_len_c;
+ unsigned t;
+ unsigned long utf32;
+
+ /* Compute the length of the UTF-8 sequence. */
+ for (t = *name; t & 0x80; t <<= 1)
+ ucn_len++;
+
+ utf32 = *name & (0x7F >> ucn_len);
+ for (ucn_len_c = 1; ucn_len_c < ucn_len; ucn_len_c++)
+ {
+ utf32 = (utf32 << 6) | (*++name & 0x3F);
+
+ /* Ill-formed UTF-8. */
+ if ((*name & ~0x3F) != 0x80)
+ abort ();
+ }
+
+ *buffer++ = '\\';
+ *buffer++ = 'U';
+ for (j = 7; j >= 0; j--)
+ *buffer++ = "0123456789abcdef"[(utf32 >> (4 * j)) & 0xF];
+ return ucn_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.
+ FORSTRING is true if this is to be the spelling after translation
+ phase 1 (this is different for UCNs).
+ FIXME: Would be nice if we didn't need the PFILE argument. */
+unsigned char *
+cpp_spell_token (cpp_reader *pfile, const cpp_token *token,
+ unsigned char *buffer, bool forstring)
+{
+ switch (TOKEN_SPELL (token))
+ {
+ case SPELL_OPERATOR:
+ {
+ const unsigned char *spelling;
+ unsigned char c;
+
+ if (token->flags & DIGRAPH)
+ spelling
+ = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH];
+ else if (token->flags & NAMED_OP)
+ goto spell_ident;
+ else
+ spelling = TOKEN_NAME (token);
+
+ while ((c = *spelling++) != '\0')
+ *buffer++ = c;
+ }
+ break;
+
+ spell_ident:
+ case SPELL_IDENT:
+ if (forstring)
+ {
+ memcpy (buffer, NODE_NAME (token->val.node),
+ NODE_LEN (token->val.node));
+ buffer += NODE_LEN (token->val.node);
+ }
+ else
+ {
+ size_t i;
+ const unsigned char * name = NODE_NAME (token->val.node);
+
+ for (i = 0; i < NODE_LEN (token->val.node); i++)
+ if (name[i] & ~0x7F)
+ {
+ i += utf8_to_ucn (buffer, name + i) - 1;
+ buffer += 10;
+ }
+ else
+ *buffer++ = NODE_NAME (token->val.node)[i];
+ }
+ break;
+
+ case SPELL_LITERAL:
+ memcpy (buffer, token->val.str.text, token->val.str.len);
+ buffer += token->val.str.len;
+ break;
+
+ case SPELL_NONE:
+ cpp_error (pfile, CPP_DL_ICE,
+ "unspellable token %s", TOKEN_NAME (token));
+ break;
+ }
+
+ return 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 (cpp_reader *pfile, const cpp_token *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, false);
+ end[0] = '\0';
+
+ return start;
+}
+
+/* Used by C front ends, which really should move to using
+ cpp_token_as_text. */
+const char *
+cpp_type2name (enum cpp_ttype type)
+{
+ return (const char *) token_spellings[type].name;
+}
+
+/* Writes the spelling of token to FP, without any preceding space.
+ Separated from cpp_spell_token for efficiency - to avoid stdio
+ double-buffering. */
+void
+cpp_output_token (const cpp_token *token, FILE *fp)
+{
+ switch (TOKEN_SPELL (token))
+ {
+ case SPELL_OPERATOR:
+ {
+ const unsigned char *spelling;
+ int c;
+
+ if (token->flags & DIGRAPH)
+ spelling
+ = digraph_spellings[(int) token->type - (int) CPP_FIRST_DIGRAPH];
+ else if (token->flags & NAMED_OP)
+ goto spell_ident;
+ else
+ spelling = TOKEN_NAME (token);
+
+ c = *spelling;
+ do
+ putc (c, fp);
+ while ((c = *++spelling) != '\0');
+ }
+ break;
+
+ spell_ident:
+ case SPELL_IDENT:
+ {
+ size_t i;
+ const unsigned char * name = NODE_NAME (token->val.node);
+
+ for (i = 0; i < NODE_LEN (token->val.node); i++)
+ if (name[i] & ~0x7F)
+ {
+ unsigned char buffer[10];
+ i += utf8_to_ucn (buffer, name + i) - 1;
+ fwrite (buffer, 1, 10, fp);
+ }
+ else
+ fputc (NODE_NAME (token->val.node)[i], fp);
+ }
+ break;
+
+ case SPELL_LITERAL:
+ fwrite (token->val.str.text, 1, token->val.str.len, fp);
+ break;
+
+ case SPELL_NONE:
+ /* An error, most probably. */
+ break;
+ }
+}
+
+/* Compare two tokens. */
+int
+_cpp_equiv_tokens (const cpp_token *a, const cpp_token *b)
+{
+ if (a->type == b->type && a->flags == b->flags)
+ switch (TOKEN_SPELL (a))
+ {
+ default: /* Keep compiler happy. */
+ case SPELL_OPERATOR:
+ return 1;
+ 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_LITERAL:
+ return (a->val.str.len == b->val.str.len
+ && !memcmp (a->val.str.text, b->val.str.text,
+ a->val.str.len));
+ }
+
+ return 0;
+}
+
+/* Returns nonzero if a space should be inserted to avoid an
+ accidental token paste for output. For simplicity, it is
+ conservative, and occasionally advises a space where one is not
+ needed, e.g. "." and ".2". */
+int
+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;
+
+ if (token1->flags & NAMED_OP)
+ a = CPP_NAME;
+ if (token2->flags & NAMED_OP)
+ b = CPP_NAME;
+
+ c = EOF;
+ if (token2->flags & DIGRAPH)
+ c = digraph_spellings[(int) b - (int) CPP_FIRST_DIGRAPH][0];
+ else if (token_spellings[b].category == SPELL_OPERATOR)
+ c = token_spellings[b].name[0];
+
+ /* Quickly get everything that can paste with an '='. */
+ if ((int) a <= (int) CPP_LAST_EQ && c == '=')
+ return 1;
+
+ switch (a)
+ {
+ case CPP_GREATER: return c == '>' || c == '?';
+ case CPP_LESS: return c == '<' || c == '?' || c == '%' || c == ':';
+ case CPP_PLUS: return c == '+';
+ case CPP_MINUS: return c == '-' || c == '>';
+ case CPP_DIV: return c == '/' || c == '*'; /* Comments. */
+ case CPP_MOD: return c == ':' || c == '>';
+ case CPP_AND: return c == '&';
+ case CPP_OR: return c == '|';
+ case CPP_COLON: return c == ':' || c == '>';
+ case CPP_DEREF: return c == '*';
+ case CPP_DOT: return c == '.' || c == '%' || b == CPP_NUMBER;
+ case CPP_HASH: return c == '#' || c == '%'; /* Digraph form. */
+ case CPP_NAME: return ((b == CPP_NUMBER
+ && name_p (pfile, &token2->val.str))
+ || b == CPP_NAME
+ || b == CPP_CHAR || b == CPP_STRING); /* L */
+ case CPP_NUMBER: return (b == CPP_NUMBER || b == CPP_NAME
+ || c == '.' || c == '+' || c == '-');
+ /* 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;
+ }
+
+ return 0;
+}
+
+/* Output all the remaining tokens on the current line, and a newline
+ character, to FP. Leading whitespace is removed. If there are
+ macros, special token padding is not performed. */
+void
+cpp_output_line (cpp_reader *pfile, FILE *fp)
+{
+ const cpp_token *token;
+
+ token = cpp_get_token (pfile);
+ while (token->type != CPP_EOF)
+ {
+ cpp_output_token (token, fp);
+ token = cpp_get_token (pfile);
+ if (token->flags & PREV_WHITE)
+ putc (' ', fp);
+ }
+
+ putc ('\n', fp);
+}
+
+/* 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
+ range of uses of cpplib, including heavy nested function-like macro
+ expansion. Also check the change in peak memory usage (NJAMD is a
+ good tool for this). */
+#define MIN_BUFF_SIZE 8000
+#define BUFF_SIZE_UPPER_BOUND(MIN_SIZE) (MIN_BUFF_SIZE + (MIN_SIZE) * 3 / 2)
+#define EXTENDED_BUFF_SIZE(BUFF, MIN_EXTRA) \
+ (MIN_EXTRA + ((BUFF)->limit - (BUFF)->cur) * 2)
+
+#if MIN_BUFF_SIZE > BUFF_SIZE_UPPER_BOUND (0)
+ #error BUFF_SIZE_UPPER_BOUND must be at least as large as MIN_BUFF_SIZE!
+#endif
+
+/* 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 (size_t len)
+{
+ _cpp_buff *result;
+ unsigned char *base;
+
+ if (len < MIN_BUFF_SIZE)
+ len = MIN_BUFF_SIZE;
+ len = CPP_ALIGN (len);
+
+ base = XNEWVEC (unsigned char, len + sizeof (_cpp_buff));
+ result = (_cpp_buff *) (base + len);
+ result->base = base;
+ result->cur = base;
+ result->limit = base + len;
+ result->next = NULL;
+ return result;
+}
+
+/* Place a chain of unwanted allocation buffers on the free list. */
+void
+_cpp_release_buff (cpp_reader *pfile, _cpp_buff *buff)
+{
+ _cpp_buff *end = buff;
+
+ while (end->next)
+ end = end->next;
+ end->next = pfile->free_buffs;
+ pfile->free_buffs = buff;
+}
+
+/* Return a free buffer of size at least MIN_SIZE. */
+_cpp_buff *
+_cpp_get_buff (cpp_reader *pfile, size_t min_size)
+{
+ _cpp_buff *result, **p;
+
+ for (p = &pfile->free_buffs;; p = &(*p)->next)
+ {
+ size_t size;
+
+ if (*p == NULL)
+ return new_buff (min_size);
+ result = *p;
+ size = result->limit - result->base;
+ /* Return a buffer that's big enough, but don't waste one that's
+ way too big. */
+ if (size >= min_size && size <= BUFF_SIZE_UPPER_BOUND (min_size))
+ break;
+ }
+
+ *p = result->next;
+ result->next = NULL;
+ result->cur = result->base;
+ return result;
+}
+
+/* Creates a new buffer with enough space to hold the uncommitted
+ remaining bytes of BUFF, and at least MIN_EXTRA more bytes. Copies
+ the excess bytes to the new buffer. Chains the new buffer after
+ BUFF, and returns the new buffer. */
+_cpp_buff *
+_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);
+
+ buff->next = new_buff;
+ memcpy (new_buff->base, buff->cur, BUFF_ROOM (buff));
+ return new_buff;
+}
+
+/* Creates a new buffer with enough space to hold the uncommitted
+ remaining bytes of the buffer pointed to by BUFF, and at least
+ MIN_EXTRA more bytes. Copies the excess bytes to the new buffer.
+ 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 (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);
+
+ new_buff = _cpp_get_buff (pfile, size);
+ memcpy (new_buff->base, old_buff->cur, BUFF_ROOM (old_buff));
+ new_buff->next = old_buff;
+ *pbuff = new_buff;
+}
+
+/* Free a chain of buffers starting at BUFF. */
+void
+_cpp_free_buff (_cpp_buff *buff)
+{
+ _cpp_buff *next;
+
+ for (; buff; buff = next)
+ {
+ next = buff->next;
+ free (buff->base);
+ }
+}
+
+/* Allocate permanent, unaligned storage of length LEN. */
+unsigned char *
+_cpp_unaligned_alloc (cpp_reader *pfile, size_t len)
+{
+ _cpp_buff *buff = pfile->u_buff;
+ unsigned char *result = buff->cur;
+
+ if (len > (size_t) (buff->limit - result))
+ {
+ buff = _cpp_get_buff (pfile, len);
+ buff->next = pfile->u_buff;
+ pfile->u_buff = buff;
+ result = buff->cur;
+ }
+
+ buff->cur = result + len;
+ return result;
+}
+
+/* Allocate permanent, unaligned storage of length LEN from a_buff.
+ That buffer is used for growing allocations when saving macro
+ replacement lists in a #define, and when parsing an answer to an
+ assertion in #assert, #unassert or #if (and therefore possibly
+ whilst expanding macros). It therefore must not be used by any
+ code that they might call: specifically the lexer and the guts of
+ the macro expander.
+
+ All existing other uses clearly fit this restriction: storing
+ registered pragmas during initialization. */
+unsigned char *
+_cpp_aligned_alloc (cpp_reader *pfile, size_t len)
+{
+ _cpp_buff *buff = pfile->a_buff;
+ unsigned char *result = buff->cur;
+
+ if (len > (size_t) (buff->limit - result))
+ {
+ buff = _cpp_get_buff (pfile, len);
+ buff->next = pfile->a_buff;
+ pfile->a_buff = buff;
+ result = buff->cur;
+ }
+
+ buff->cur = result + len;
+ return result;
+}
+
+/* Say which field of TOK is in use. */
+
+enum cpp_token_fld_kind
+cpp_token_val_index (cpp_token *tok)
+{
+ switch (TOKEN_SPELL (tok))
+ {
+ case SPELL_IDENT:
+ return CPP_TOKEN_FLD_NODE;
+ case SPELL_LITERAL:
+ return CPP_TOKEN_FLD_STR;
+ case SPELL_NONE:
+ if (tok->type == CPP_MACRO_ARG)
+ return CPP_TOKEN_FLD_ARG_NO;
+ else if (tok->type == CPP_PADDING)
+ return CPP_TOKEN_FLD_SOURCE;
+ else if (tok->type == CPP_PRAGMA)
+ return CPP_TOKEN_FLD_STR;
+ /* else fall through */
+ default:
+ return CPP_TOKEN_FLD_NONE;
+ }
+}
--- /dev/null
+/* Map logical line numbers to (source file, line number) pairs.
+ Copyright (C) 2001, 2003, 2004
+ 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 "line-map.h"
+
+static void trace_include (const struct line_maps *, const struct line_map *);
+
+/* Initialize a line map set. */
+
+void
+linemap_init (struct line_maps *set)
+{
+ set->maps = NULL;
+ set->allocated = 0;
+ set->used = 0;
+ set->last_listed = -1;
+ set->trace_includes = false;
+ set->depth = 0;
+ set->cache = 0;
+ set->highest_location = 0;
+ set->highest_line = 0;
+ set->max_column_hint = 0;
+}
+
+/* Check for and warn about line_maps entered but not exited. */
+
+void
+linemap_check_files_exited (struct line_maps *set)
+{
+ struct line_map *map;
+ /* Depending upon whether we are handling preprocessed input or
+ not, this can be a user error or an ICE. */
+ for (map = &set->maps[set->used - 1]; ! MAIN_FILE_P (map);
+ map = INCLUDED_FROM (set, map))
+ fprintf (stderr, "line-map.c: file \"%s\" entered but not left\n",
+ map->to_file);
+}
+
+/* Free a line map set. */
+
+void
+linemap_free (struct line_maps *set)
+{
+ if (set->maps)
+ {
+ linemap_check_files_exited (set);
+
+ free (set->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 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
+ 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 *
+linemap_add (struct line_maps *set, enum lc_reason reason,
+ unsigned int sysp, const char *to_file, unsigned int to_line)
+{
+ struct line_map *map;
+ source_location start_location = set->highest_location + 1;
+
+ if (set->used && start_location < set->maps[set->used - 1].start_location)
+ abort ();
+
+ if (set->used == set->allocated)
+ {
+ set->allocated = 2 * set->allocated + 256;
+ set->maps = XRESIZEVEC (struct line_map, set->maps, set->allocated);
+ }
+
+ 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)
+ reason = LC_ENTER;
+ else if (reason == LC_LEAVE)
+ {
+ struct line_map *from;
+ bool error;
+
+ if (MAIN_FILE_P (map - 1))
+ {
+ if (to_file == NULL)
+ {
+ set->depth--;
+ return NULL;
+ }
+ error = true;
+ reason = LC_RENAME;
+ from = map - 1;
+ }
+ else
+ {
+ from = INCLUDED_FROM (set, map - 1);
+ error = to_file && strcmp (from->to_file, to_file);
+ }
+
+ /* Depending upon whether we are handling preprocessed input or
+ not, this can be a user error or an ICE. */
+ if (error)
+ fprintf (stderr, "line-map.c: file \"%s\" left but not entered\n",
+ to_file);
+
+ /* A TO_FILE of NULL is special - we use the natural values. */
+ if (error || to_file == NULL)
+ {
+ to_file = from->to_file;
+ to_line = SOURCE_LINE (from, from[1].start_location);
+ sysp = from->sysp;
+ }
+ }
+
+ map->reason = reason;
+ map->sysp = sysp;
+ map->start_location = start_location;
+ map->to_file = to_file;
+ map->to_line = to_line;
+ set->cache = set->used++;
+ map->column_bits = 0;
+ set->highest_location = start_location;
+ set->highest_line = start_location;
+ set->max_column_hint = 0;
+
+ if (reason == LC_ENTER)
+ {
+ map->included_from = set->depth == 0 ? -1 : (int) (set->used - 2);
+ set->depth++;
+ if (set->trace_includes)
+ trace_include (set, map);
+ }
+ else if (reason == LC_RENAME)
+ map->included_from = map[-1].included_from;
+ else if (reason == LC_LEAVE)
+ {
+ set->depth--;
+ map->included_from = INCLUDED_FROM (set, map - 1)->included_from;
+ }
+
+ return map;
+}
+
+source_location
+linemap_line_start (struct line_maps *set, unsigned int to_line,
+ unsigned int max_column_hint)
+{
+ struct line_map *map = &set->maps[set->used - 1];
+ source_location highest = set->highest_location;
+ source_location r;
+ unsigned int last_line = SOURCE_LINE (map, set->highest_line);
+ int line_delta = to_line - last_line;
+ bool add_map = false;
+ if (line_delta < 0
+ || (line_delta > 10 && line_delta * map->column_bits > 1000)
+ || (max_column_hint >= (1U << map->column_bits))
+ || (max_column_hint <= 80 && map->column_bits >= 10))
+ {
+ add_map = true;
+ }
+ else
+ max_column_hint = set->max_column_hint;
+ if (add_map)
+ {
+ int column_bits;
+ if (max_column_hint > 100000 || highest > 0xC0000000)
+ {
+ /* If the column number is ridiculous or we've allocated a huge
+ number of source_locations, give up on column numbers. */
+ max_column_hint = 0;
+ if (highest >0xF0000000)
+ return 0;
+ column_bits = 0;
+ }
+ else
+ {
+ column_bits = 7;
+ while (max_column_hint >= (1U << column_bits))
+ column_bits++;
+ max_column_hint = 1U << column_bits;
+ }
+ /* Allocate the new line_map. However, if the current map only has a
+ single line we can sometimes just increase its column_bits instead. */
+ if (line_delta < 0
+ || last_line != map->to_line
+ || SOURCE_COLUMN (map, highest) >= (1U << column_bits))
+ map = (struct line_map*) linemap_add (set, LC_RENAME, map->sysp,
+ map->to_file, to_line);
+ map->column_bits = column_bits;
+ r = map->start_location + ((to_line - map->to_line) << column_bits);
+ }
+ else
+ r = highest - SOURCE_COLUMN (map, highest)
+ + (line_delta << map->column_bits);
+ set->highest_line = r;
+ if (r > set->highest_location)
+ set->highest_location = r;
+ set->max_column_hint = max_column_hint;
+ return r;
+}
+
+source_location
+linemap_position_for_column (struct line_maps *set, unsigned int to_column)
+{
+ source_location r = set->highest_line;
+ if (to_column >= set->max_column_hint)
+ {
+ if (r >= 0xC000000 || to_column > 100000)
+ {
+ /* Running low on source_locations - disable column numbers. */
+ return r;
+ }
+ else
+ {
+ struct line_map *map = &set->maps[set->used - 1];
+ r = linemap_line_start (set, SOURCE_LINE (map, r), to_column + 50);
+ }
+ }
+ r = r + to_column;
+ if (r >= set->highest_location)
+ set->highest_location = r;
+ return r;
+}
+
+/* Given a logical line, returns the map from which the corresponding
+ (source file, line) pair can be deduced. Since the set is built
+ chronologically, the logical lines are monotonic increasing, and so
+ the list is sorted and we can use a binary search. */
+
+const struct line_map *
+linemap_lookup (struct line_maps *set, source_location line)
+{
+ unsigned int md, mn, mx;
+ const struct line_map *cached;
+
+ mn = set->cache;
+ mx = set->used;
+
+ cached = &set->maps[mn];
+ /* We should get a segfault if no line_maps have been added yet. */
+ if (line >= cached->start_location)
+ {
+ if (mn + 1 == mx || line < cached[1].start_location)
+ return cached;
+ }
+ else
+ {
+ mx = mn;
+ mn = 0;
+ }
+
+ while (mx - mn > 1)
+ {
+ md = (mn + mx) / 2;
+ if (set->maps[md].start_location > line)
+ mx = md;
+ else
+ mn = md;
+ }
+
+ set->cache = mn;
+ return &set->maps[mn];
+}
+
+/* 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. */
+
+void
+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;
+
+ set->last_listed = map->included_from;
+ map = INCLUDED_FROM (set, map);
+
+ fprintf (stderr, _("In file included from %s:%u"),
+ map->to_file, LAST_SOURCE_LINE (map));
+
+ while (! MAIN_FILE_P (map))
+ {
+ map = INCLUDED_FROM (set, map);
+ /* Translators note: this message is used in conjunction
+ with "In file included from %s:%ld" and some other
+ tricks. We want something like this:
+
+ | In file included from sys/select.h:123,
+ | from sys/types.h:234,
+ | from userfile.c:31:
+ | bits/select.h:45: <error message here>
+
+ with all the "from"s lined up.
+ The trailing comma is at the beginning of this message,
+ and the trailing colon is not translated. */
+ fprintf (stderr, _(",\n from %s:%u"),
+ map->to_file, LAST_SOURCE_LINE (map));
+ }
+
+ fputs (":\n", stderr);
+}
+
+/* Print an include trace, for e.g. the -H option of the preprocessor. */
+
+static void
+trace_include (const struct line_maps *set, const struct line_map *map)
+{
+ unsigned int i = set->depth;
+
+ while (--i)
+ putc ('.', stderr);
+ fprintf (stderr, " %s\n", map->to_file);
+}
--- /dev/null
+/* Part of CPP library. (Macro and #define handling.)
+ Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 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
+
+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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 "internal.h"
+
+typedef struct macro_arg macro_arg;
+struct macro_arg
+{
+ const cpp_token **first; /* First token in unexpanded argument. */
+ const cpp_token **expanded; /* Macro-expanded argument. */
+ const cpp_token *stringified; /* Stringified argument. */
+ unsigned int count; /* # of tokens in argument. */
+ unsigned int expanded_count; /* # of tokens in expanded argument. */
+};
+
+/* Macro expansion. */
+
+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 (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 (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
+ && MAIN_FILE_P (linemap_lookup (pfile->line_table, macro->line)))
+ cpp_error_with_line (pfile, CPP_DL_WARNING, macro->line, 0,
+ "macro \"%s\" is not used", NODE_NAME (node));
+ }
+
+ return 1;
+}
+
+/* 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 (cpp_reader *pfile, unsigned char *text, unsigned int len)
+{
+ cpp_token *token = _cpp_temp_token (pfile);
+
+ text[len] = '\0';
+ token->type = CPP_STRING;
+ token->val.str.len = len;
+ token->val.str.text = text;
+ token->flags = 0;
+ return token;
+}
+
+static const char * const monthnames[] =
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+/* Helper function for builtin_macro. Returns the text generated by
+ a builtin macro. */
+const uchar *
+_cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node)
+{
+ const struct line_map *map;
+ const uchar *result = NULL;
+ unsigned int number = 1;
+
+ switch (node->value.builtin)
+ {
+ default:
+ cpp_error (pfile, CPP_DL_ICE, "invalid built-in macro \"%s\"",
+ NODE_NAME (node));
+ break;
+
+ case BT_FILE:
+ case BT_BASE_FILE:
+ {
+ unsigned int len;
+ const char *name;
+ uchar *buf;
+ map = linemap_lookup (pfile->line_table, pfile->line_table->highest_line);
+
+ if (node->value.builtin == BT_BASE_FILE)
+ while (! MAIN_FILE_P (map))
+ map = INCLUDED_FROM (pfile->line_table, map);
+
+ name = map->to_file;
+ len = strlen (name);
+ buf = _cpp_unaligned_alloc (pfile, len * 2 + 3);
+ result = buf;
+ *buf = '"';
+ buf = cpp_quote_string (buf + 1, (const unsigned char *) name, len);
+ *buf++ = '"';
+ *buf = '\0';
+ }
+ break;
+
+ case BT_INCLUDE_LEVEL:
+ /* The line map depth counts the primary source as level 1, but
+ historically __INCLUDE_DEPTH__ has called the primary source
+ level 0. */
+ number = pfile->line_table->depth - 1;
+ break;
+
+ case BT_SPECLINE:
+ map = &pfile->line_table->maps[pfile->line_table->used-1];
+ /* If __LINE__ is embedded in a macro, it must expand to the
+ line of the macro's invocation, not its definition.
+ Otherwise things like assert() will not work properly. */
+ if (CPP_OPTION (pfile, traditional))
+ number = pfile->line_table->highest_line;
+ else
+ number = pfile->cur_token[-1].src_loc;
+ number = SOURCE_LINE (map, number);
+ break;
+
+ /* __STDC__ has the value 1 under normal circumstances.
+ However, if (a) we are in a system header, (b) the option
+ stdc_0_in_system_headers is true (set by target config), and
+ (c) we are not in strictly conforming mode, then it has the
+ value 0. (b) and (c) are already checked in cpp_init_builtins. */
+ case BT_STDC:
+ if (cpp_in_system_header (pfile))
+ number = 0;
+ else
+ number = 1;
+ break;
+
+ case BT_DATE:
+ case BT_TIME:
+ if (pfile->date == NULL)
+ {
+ /* Allocate __DATE__ and __TIME__ strings from permanent
+ storage. We only do this once, and don't generate them
+ at init time, because time() and localtime() are very
+ slow on some systems. */
+ time_t tt;
+ struct tm *tb = NULL;
+
+ /* (time_t) -1 is a legitimate value for "number of seconds
+ since the Epoch", so we have to do a little dance to
+ distinguish that from a genuine error. */
+ errno = 0;
+ tt = time(NULL);
+ if (tt != (time_t)-1 || errno == 0)
+ tb = localtime (&tt);
+
+ if (tb)
+ {
+ 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);
+
+ pfile->time = _cpp_unaligned_alloc (pfile,
+ sizeof ("\"12:34:56\""));
+ sprintf ((char *) pfile->time, "\"%02d:%02d:%02d\"",
+ tb->tm_hour, tb->tm_min, tb->tm_sec);
+ }
+ else
+ {
+ cpp_errno (pfile, CPP_DL_WARNING,
+ "could not determine date and time");
+
+ pfile->date = U"\"??? ?? ????\"";
+ pfile->time = U"\"??:??:??\"";
+ }
+ }
+
+ if (node->value.builtin == BT_DATE)
+ result = pfile->date;
+ else
+ result = pfile->time;
+ break;
+ }
+
+ if (result == NULL)
+ {
+ /* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */
+ result = _cpp_unaligned_alloc (pfile, 21);
+ sprintf ((char *) result, "%u", number);
+ }
+
+ return result;
+}
+
+/* Convert builtin macros like __FILE__ to a token and push it on the
+ context stack. Also handles _Pragma, for which a new token may not
+ be created. Returns 1 if it generates a new token context, 0 to
+ return the token to the caller. */
+static int
+builtin_macro (cpp_reader *pfile, cpp_hashnode *node)
+{
+ const uchar *buf;
+ size_t len;
+ char *nbuf;
+
+ if (node->value.builtin == BT_PRAGMA)
+ {
+ /* Don't interpret _Pragma within directives. The standard is
+ not clear on this, but to me this makes most sense. */
+ if (pfile->state.in_directive)
+ return 0;
+
+ _cpp_do__Pragma (pfile);
+ if (pfile->directive_result.type == CPP_PRAGMA)
+ {
+ cpp_token *tok = _cpp_temp_token (pfile);
+ *tok = pfile->directive_result;
+ push_token_context (pfile, NULL, tok, 1);
+ }
+
+ return 1;
+ }
+
+ buf = _cpp_builtin_macro_text (pfile, node);
+ len = ustrlen (buf);
+ nbuf = (char *) alloca (len + 1);
+ memcpy (nbuf, buf, len);
+ nbuf[len]='\n';
+
+ 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, CPP_DL_ICE, "invalid built-in macro \"%s\"",
+ NODE_NAME (node));
+ _cpp_pop_buffer (pfile);
+
+ return 1;
+}
+
+/* Copies SRC, of length LEN, to DEST, adding backslashes before all
+ backslashes and double quotes. DEST must be of sufficient size.
+ Returns a pointer to the end of the string. */
+uchar *
+cpp_quote_string (uchar *dest, const uchar *src, unsigned int len)
+{
+ while (len--)
+ {
+ uchar c = *src++;
+
+ if (c == '\\' || c == '"')
+ {
+ *dest++ = '\\';
+ *dest++ = c;
+ }
+ else
+ *dest++ = c;
+ }
+
+ return dest;
+}
+
+/* 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 (cpp_reader *pfile, macro_arg *arg)
+{
+ 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++)
+ {
+ const cpp_token *token = arg->first[i];
+
+ if (token->type == CPP_PADDING)
+ {
+ if (source == NULL)
+ source = token->val.source;
+ continue;
+ }
+
+ escape_it = (token->type == CPP_STRING || token->type == CPP_WSTRING
+ || token->type == CPP_CHAR || token->type == CPP_WCHAR);
+
+ /* Room for each char being written in octal, initial space and
+ final quote and NUL. */
+ len = cpp_token_len (token);
+ if (escape_it)
+ len *= 4;
+ len += 3;
+
+ if ((size_t) (BUFF_LIMIT (pfile->u_buff) - dest) < len)
+ {
+ size_t len_so_far = dest - BUFF_FRONT (pfile->u_buff);
+ _cpp_extend_buff (pfile, &pfile->u_buff, len);
+ dest = BUFF_FRONT (pfile->u_buff) + len_so_far;
+ }
+
+ /* Leading white space? */
+ if (dest - 1 != BUFF_FRONT (pfile->u_buff))
+ {
+ if (source == NULL)
+ source = token;
+ if (source->flags & PREV_WHITE)
+ *dest++ = ' ';
+ }
+ source = NULL;
+
+ if (escape_it)
+ {
+ _cpp_buff *buff = _cpp_get_buff (pfile, len);
+ unsigned char *buf = BUFF_FRONT (buff);
+ len = cpp_spell_token (pfile, token, buf, true) - buf;
+ dest = cpp_quote_string (dest, buf, len);
+ _cpp_release_buff (pfile, buff);
+ }
+ else
+ dest = cpp_spell_token (pfile, token, dest, true);
+
+ if (token->type == CPP_OTHER && token->val.str.text[0] == '\\')
+ backslash_count++;
+ else
+ backslash_count = 0;
+ }
+
+ /* Ignore the final \ of invalid string literals. */
+ if (backslash_count & 1)
+ {
+ cpp_error (pfile, CPP_DL_WARNING,
+ "invalid string literal, ignoring final '\\'");
+ dest--;
+ }
+
+ /* Commit the memory, including NUL, and return the token. */
+ *dest++ = '"';
+ len = dest - BUFF_FRONT (pfile->u_buff);
+ BUFF_FRONT (pfile->u_buff) = dest + 1;
+ return new_string_token (pfile, dest - len, len);
+}
+
+/* Try to paste two tokens. On success, return nonzero. In any
+ 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 (cpp_reader *pfile, const cpp_token **plhs, const cpp_token *rhs)
+{
+ unsigned char *buf, *end;
+ const cpp_token *lhs;
+ unsigned int len;
+ bool valid;
+
+ lhs = *plhs;
+ len = cpp_token_len (lhs) + cpp_token_len (rhs) + 1;
+ buf = (unsigned char *) alloca (len);
+ end = cpp_spell_token (pfile, lhs, buf, false);
+
+ /* Avoid comment headers, since they are still processed in stage 3.
+ It is simpler to insert a space here, rather than modifying the
+ lexer to ignore comments in some circumstances. Simply returning
+ false doesn't work, since we want to clear the PASTE_LEFT flag. */
+ if (lhs->type == CPP_DIV && rhs->type != CPP_EQ)
+ *end++ = ' ';
+ end = cpp_spell_token (pfile, rhs, end, false);
+ *end = '\n';
+
+ 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);
+ *plhs = _cpp_lex_direct (pfile);
+ valid = pfile->buffer->cur == pfile->buffer->rlimit;
+ _cpp_pop_buffer (pfile);
+
+ return valid;
+}
+
+/* Handles an arbitrarily long sequence of ## operators, with initial
+ operand LHS. This implementation is left-associative,
+ non-recursive, and finishes a paste before handling succeeding
+ ones. If a paste fails, we back up to the RHS of the failing ##
+ operator before pushing the context containing the result of prior
+ successful pastes, with the effect that the RHS appears in the
+ output stream after the pasted LHS normally. */
+static void
+paste_all_tokens (cpp_reader *pfile, const cpp_token *lhs)
+{
+ const cpp_token *rhs;
+ cpp_context *context = pfile->context;
+
+ do
+ {
+ /* Take the token directly from the current context. We can do
+ this, because we are in the replacement list of either an
+ object-like macro, or a function-like macro with arguments
+ inserted. In either case, the constraints to #define
+ guarantee we have at least one more token. */
+ if (context->direct_p)
+ rhs = FIRST (context).token++;
+ else
+ rhs = *FIRST (context).ptoken++;
+
+ if (rhs->type == CPP_PADDING)
+ abort ();
+
+ if (!paste_tokens (pfile, &lhs, rhs))
+ {
+ _cpp_backup_tokens (pfile, 1);
+
+ /* Mandatory error for all apart from assembler. */
+ if (CPP_OPTION (pfile, lang) != CLK_ASM)
+ 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));
+ break;
+ }
+ }
+ while (rhs->flags & PASTE_LEFT);
+
+ /* Put the resulting token in its own context. */
+ push_token_context (pfile, NULL, lhs, 1);
+}
+
+/* Returns TRUE if the number of arguments ARGC supplied in an
+ invocation of the MACRO referenced by NODE is valid. An empty
+ invocation to a macro with no parameters should pass ARGC as zero.
+
+ Note that MACRO cannot necessarily be deduced from NODE, in case
+ NODE was redefined whilst collecting arguments. */
+bool
+_cpp_arguments_ok (cpp_reader *pfile, cpp_macro *macro, const cpp_hashnode *node, unsigned int argc)
+{
+ if (argc == macro->paramc)
+ return true;
+
+ if (argc < macro->paramc)
+ {
+ /* As an extension, a rest argument is allowed to not appear in
+ the invocation at all.
+ e.g. #define debug(format, args...) something
+ debug("string");
+
+ This is exactly the same as if there had been an empty rest
+ argument - debug("string", ). */
+
+ if (argc + 1 == macro->paramc && macro->variadic)
+ {
+ if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "ISO C99 requires rest arguments to be used");
+ return true;
+ }
+
+ 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, CPP_DL_ERROR,
+ "macro \"%s\" passed %u arguments, but takes just %u",
+ NODE_NAME (node), argc, macro->paramc);
+
+ return false;
+}
+
+/* Reads and returns the arguments to a function-like macro
+ invocation. Assumes the opening parenthesis has been processed.
+ If there is an error, emits an appropriate diagnostic and returns
+ NULL. Each argument is terminated by a CPP_EOF token, for the
+ future benefit of expand_arg(). */
+static _cpp_buff *
+collect_args (cpp_reader *pfile, const cpp_hashnode *node)
+{
+ _cpp_buff *buff, *base_buff;
+ cpp_macro *macro;
+ macro_arg *args, *arg;
+ const cpp_token *token;
+ unsigned int argc;
+
+ macro = node->value.macro;
+ if (macro->paramc)
+ argc = macro->paramc;
+ else
+ argc = 1;
+ buff = _cpp_get_buff (pfile, argc * (50 * sizeof (cpp_token *)
+ + sizeof (macro_arg)));
+ base_buff = buff;
+ args = (macro_arg *) buff->base;
+ memset (args, 0, argc * sizeof (macro_arg));
+ buff->cur = (unsigned char *) &args[argc];
+ arg = args, argc = 0;
+
+ /* Collect the tokens making up each argument. We don't yet know
+ how many arguments have been supplied, whether too many or too
+ few. Hence the slightly bizarre usage of "argc" and "arg". */
+ do
+ {
+ unsigned int paren_depth = 0;
+ unsigned int ntokens = 0;
+
+ argc++;
+ arg->first = (const cpp_token **) buff->cur;
+
+ for (;;)
+ {
+ /* Require space for 2 new tokens (including a CPP_EOF). */
+ if ((unsigned char *) &arg->first[ntokens + 2] > buff->limit)
+ {
+ buff = _cpp_append_extend_buff (pfile, buff,
+ 1000 * sizeof (cpp_token *));
+ arg->first = (const cpp_token **) buff->cur;
+ }
+
+ token = cpp_get_token (pfile);
+
+ if (token->type == CPP_PADDING)
+ {
+ /* Drop leading padding. */
+ if (ntokens == 0)
+ continue;
+ }
+ else if (token->type == CPP_OPEN_PAREN)
+ paren_depth++;
+ else if (token->type == CPP_CLOSE_PAREN)
+ {
+ if (paren_depth-- == 0)
+ break;
+ }
+ else if (token->type == CPP_COMMA)
+ {
+ /* A comma does not terminate an argument within
+ parentheses or as part of a variable argument. */
+ if (paren_depth == 0
+ && ! (macro->variadic && argc == macro->paramc))
+ break;
+ }
+ else if (token->type == CPP_EOF
+ || (token->type == CPP_HASH && token->flags & BOL))
+ break;
+
+ arg->first[ntokens++] = token;
+ }
+
+ /* Drop trailing padding. */
+ while (ntokens > 0 && arg->first[ntokens - 1]->type == CPP_PADDING)
+ ntokens--;
+
+ arg->count = ntokens;
+ arg->first[ntokens] = &pfile->eof;
+
+ /* Terminate the argument. Excess arguments loop back and
+ overwrite the final legitimate argument, before failing. */
+ if (argc <= macro->paramc)
+ {
+ buff->cur = (unsigned char *) &arg->first[ntokens + 1];
+ if (argc != macro->paramc)
+ arg++;
+ }
+ }
+ while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF);
+
+ if (token->type == CPP_EOF)
+ {
+ /* We still need the CPP_EOF to end directives, and to end
+ pre-expansion of a macro argument. Step back is not
+ unconditional, since we don't want to return a CPP_EOF to our
+ 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, CPP_DL_ERROR,
+ "unterminated argument list invoking macro \"%s\"",
+ NODE_NAME (node));
+ }
+ else
+ {
+ /* A single empty argument is counted as no argument. */
+ if (argc == 1 && macro->paramc == 0 && args[0].count == 0)
+ argc = 0;
+ if (_cpp_arguments_ok (pfile, macro, node, argc))
+ {
+ /* GCC has special semantics for , ## b where b is a varargs
+ parameter: we remove the comma if b was omitted entirely.
+ If b was merely an empty argument, the comma is retained.
+ If the macro takes just one (varargs) parameter, then we
+ retain the comma only if we are standards conforming.
+
+ If FIRST is NULL replace_args () swallows the comma. */
+ if (macro->variadic && (argc < macro->paramc
+ || (argc == 1 && args[0].count == 0
+ && !CPP_OPTION (pfile, std))))
+ args[macro->paramc - 1].first = NULL;
+ return base_buff;
+ }
+ }
+
+ /* An error occurred. */
+ _cpp_release_buff (pfile, base_buff);
+ return NULL;
+}
+
+/* Search for an opening parenthesis to the macro of NODE, in such a
+ way that, if none is found, we don't lose the information in any
+ intervening padding tokens. If we find the parenthesis, collect
+ the arguments and return the buffer containing them. */
+static _cpp_buff *
+funlike_invocation_p (cpp_reader *pfile, cpp_hashnode *node)
+{
+ const cpp_token *token, *padding = NULL;
+
+ for (;;)
+ {
+ token = cpp_get_token (pfile);
+ if (token->type != CPP_PADDING)
+ break;
+ if (padding == NULL
+ || (!(padding->flags & PREV_WHITE) && token->val.source == NULL))
+ padding = token;
+ }
+
+ if (token->type == CPP_OPEN_PAREN)
+ {
+ pfile->state.parsing_args = 2;
+ return collect_args (pfile, node);
+ }
+
+ /* CPP_EOF can be the end of macro arguments, or the end of the
+ file. We mustn't back up over the latter. Ugh. */
+ if (token->type != CPP_EOF || token == &pfile->eof)
+ {
+ /* Back up. We may have skipped padding, in which case backing
+ up more than one token when expanding macros is in general
+ too difficult. We re-insert it in its own context. */
+ _cpp_backup_tokens (pfile, 1);
+ if (padding)
+ push_token_context (pfile, NULL, padding, 1);
+ }
+
+ return NULL;
+}
+
+/* Push the context of a macro with hash entry NODE onto the context
+ stack. If we can successfully expand the macro, we push a context
+ 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 (cpp_reader *pfile, cpp_hashnode *node)
+{
+ /* The presence of a macro invalidates a file's controlling macro. */
+ pfile->mi_valid = false;
+
+ pfile->state.angled_headers = false;
+
+ /* Handle standard macros. */
+ if (! (node->flags & NODE_BUILTIN))
+ {
+ cpp_macro *macro = node->value.macro;
+
+ if (macro->fun_like)
+ {
+ _cpp_buff *buff;
+
+ pfile->state.prevent_expansion++;
+ pfile->keep_tokens++;
+ pfile->state.parsing_args = 1;
+ buff = funlike_invocation_p (pfile, node);
+ pfile->state.parsing_args = 0;
+ pfile->keep_tokens--;
+ pfile->state.prevent_expansion--;
+
+ if (buff == NULL)
+ {
+ if (CPP_WTRADITIONAL (pfile) && ! node->value.macro->syshdr)
+ cpp_error (pfile, CPP_DL_WARNING,
+ "function-like macro \"%s\" must be used with arguments in traditional C",
+ NODE_NAME (node));
+
+ return 0;
+ }
+
+ if (macro->paramc > 0)
+ replace_args (pfile, node, macro, (macro_arg *) buff->base);
+ _cpp_release_buff (pfile, buff);
+ }
+
+ /* Disable the macro within its expansion. */
+ node->flags |= NODE_DISABLED;
+
+ macro->used = 1;
+
+ if (macro->paramc == 0)
+ push_token_context (pfile, node, macro->exp.tokens, macro->count);
+
+ return 1;
+ }
+
+ /* Handle built-in macros and the _Pragma operator. */
+ return builtin_macro (pfile, node);
+}
+
+/* Replace the parameters in a function-like macro of NODE with the
+ actual ARGS, and place the result in a newly pushed token context.
+ Expand each argument before replacing, unless it is operated upon
+ by the # or ## operators. */
+static void
+replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg *args)
+{
+ unsigned int i, total;
+ const cpp_token *src, *limit;
+ const cpp_token **dest, **first;
+ macro_arg *arg;
+ _cpp_buff *buff;
+
+ /* First, fully macro-expand arguments, calculating the number of
+ tokens in the final expansion as we go. The ordering of the if
+ statements below is subtle; we must handle stringification before
+ pasting. */
+ total = macro->count;
+ limit = macro->exp.tokens + macro->count;
+
+ for (src = macro->exp.tokens; src < limit; src++)
+ if (src->type == CPP_MACRO_ARG)
+ {
+ /* Leading and trailing padding tokens. */
+ total += 2;
+
+ /* We have an argument. If it is not being stringified or
+ pasted it is macro-replaced before insertion. */
+ arg = &args[src->val.arg_no - 1];
+
+ if (src->flags & STRINGIFY_ARG)
+ {
+ if (!arg->stringified)
+ arg->stringified = stringify_arg (pfile, arg);
+ }
+ else if ((src->flags & PASTE_LEFT)
+ || (src > macro->exp.tokens && (src[-1].flags & PASTE_LEFT)))
+ total += arg->count - 1;
+ else
+ {
+ if (!arg->expanded)
+ expand_arg (pfile, arg);
+ total += arg->expanded_count - 1;
+ }
+ }
+
+ /* Now allocate space for the expansion, copy the tokens and replace
+ the arguments. */
+ buff = _cpp_get_buff (pfile, total * sizeof (cpp_token *));
+ first = (const cpp_token **) buff->base;
+ dest = first;
+
+ for (src = macro->exp.tokens; src < limit; src++)
+ {
+ unsigned int count;
+ const cpp_token **from, **paste_flag;
+
+ if (src->type != CPP_MACRO_ARG)
+ {
+ *dest++ = src;
+ continue;
+ }
+
+ paste_flag = 0;
+ arg = &args[src->val.arg_no - 1];
+ if (src->flags & STRINGIFY_ARG)
+ count = 1, from = &arg->stringified;
+ else if (src->flags & PASTE_LEFT)
+ count = arg->count, from = arg->first;
+ else if (src != macro->exp.tokens && (src[-1].flags & PASTE_LEFT))
+ {
+ count = arg->count, from = arg->first;
+ if (dest != first)
+ {
+ if (dest[-1]->type == CPP_COMMA
+ && macro->variadic
+ && src->val.arg_no == macro->paramc)
+ {
+ /* Swallow a pasted comma if from == NULL, otherwise
+ drop the paste flag. */
+ if (from == NULL)
+ dest--;
+ else
+ paste_flag = dest - 1;
+ }
+ /* Remove the paste flag if the RHS is a placemarker. */
+ else if (count == 0)
+ paste_flag = dest - 1;
+ }
+ }
+ else
+ count = arg->expanded_count, from = arg->expanded;
+
+ /* Padding on the left of an argument (unless RHS of ##). */
+ if ((!pfile->state.in_directive || pfile->state.directive_wants_padding)
+ && src != macro->exp.tokens && !(src[-1].flags & PASTE_LEFT))
+ *dest++ = padding_token (pfile, src);
+
+ if (count)
+ {
+ memcpy (dest, from, count * sizeof (cpp_token *));
+ dest += count;
+
+ /* With a non-empty argument on the LHS of ##, the last
+ token should be flagged PASTE_LEFT. */
+ if (src->flags & PASTE_LEFT)
+ paste_flag = dest - 1;
+ }
+
+ /* Avoid paste on RHS (even case count == 0). */
+ if (!pfile->state.in_directive && !(src->flags & PASTE_LEFT))
+ *dest++ = &pfile->avoid_paste;
+
+ /* Add a new paste flag, or remove an unwanted one. */
+ if (paste_flag)
+ {
+ cpp_token *token = _cpp_temp_token (pfile);
+ token->type = (*paste_flag)->type;
+ token->val = (*paste_flag)->val;
+ if (src->flags & PASTE_LEFT)
+ token->flags = (*paste_flag)->flags | PASTE_LEFT;
+ else
+ token->flags = (*paste_flag)->flags & ~PASTE_LEFT;
+ *paste_flag = token;
+ }
+ }
+
+ /* Free the expanded arguments. */
+ for (i = 0; i < macro->paramc; i++)
+ if (args[i].expanded)
+ free (args[i].expanded);
+
+ push_ptoken_context (pfile, node, buff, first, dest - first);
+}
+
+/* Return a special padding token, with padding inherited from SOURCE. */
+static const cpp_token *
+padding_token (cpp_reader *pfile, const cpp_token *source)
+{
+ cpp_token *result = _cpp_temp_token (pfile);
+
+ result->type = CPP_PADDING;
+
+ /* Data in GCed data structures cannot be made const so far, so we
+ need a cast here. */
+ result->val.source = (cpp_token *) source;
+ result->flags = 0;
+ return result;
+}
+
+/* Get a new uninitialized context. Create a new one if we cannot
+ re-use an old one. */
+static cpp_context *
+next_context (cpp_reader *pfile)
+{
+ cpp_context *result = pfile->context->next;
+
+ if (result == 0)
+ {
+ result = XNEW (cpp_context);
+ result->prev = pfile->context;
+ result->next = 0;
+ pfile->context->next = result;
+ }
+
+ pfile->context = result;
+ return result;
+}
+
+/* Push a list of pointers to tokens. */
+static void
+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);
+
+ context->direct_p = false;
+ context->macro = macro;
+ context->buff = buff;
+ FIRST (context).ptoken = first;
+ LAST (context).ptoken = first + count;
+}
+
+/* Push a list of tokens. */
+static void
+push_token_context (cpp_reader *pfile, cpp_hashnode *macro,
+ const cpp_token *first, unsigned int count)
+{
+ cpp_context *context = next_context (pfile);
+
+ context->direct_p = true;
+ context->macro = macro;
+ context->buff = NULL;
+ FIRST (context).token = first;
+ LAST (context).token = first + count;
+}
+
+/* Push a traditional macro's replacement text. */
+void
+_cpp_push_text_context (cpp_reader *pfile, cpp_hashnode *macro,
+ const uchar *start, size_t len)
+{
+ cpp_context *context = next_context (pfile);
+
+ context->direct_p = true;
+ context->macro = macro;
+ context->buff = NULL;
+ CUR (context) = start;
+ RLIMIT (context) = start + len;
+ macro->flags |= NODE_DISABLED;
+}
+
+/* Expand an argument ARG before replacing parameters in a
+ function-like macro. This works by pushing a context with the
+ argument's tokens, and then expanding that into a temporary buffer
+ as if it were a normal part of the token stream. collect_args()
+ 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 (cpp_reader *pfile, macro_arg *arg)
+{
+ unsigned int capacity;
+ bool saved_warn_trad;
+
+ if (arg->count == 0)
+ return;
+
+ /* Don't warn about funlike macros when pre-expanding. */
+ saved_warn_trad = CPP_WTRADITIONAL (pfile);
+ CPP_WTRADITIONAL (pfile) = 0;
+
+ /* Loop, reading in the arguments. */
+ capacity = 256;
+ arg->expanded = XNEWVEC (const cpp_token *, capacity);
+
+ push_ptoken_context (pfile, NULL, NULL, arg->first, arg->count + 1);
+ for (;;)
+ {
+ const cpp_token *token;
+
+ if (arg->expanded_count + 1 >= capacity)
+ {
+ capacity *= 2;
+ arg->expanded = XRESIZEVEC (const cpp_token *, arg->expanded,
+ capacity);
+ }
+
+ token = cpp_get_token (pfile);
+
+ if (token->type == CPP_EOF)
+ break;
+
+ arg->expanded[arg->expanded_count++] = token;
+ }
+
+ _cpp_pop_context (pfile);
+
+ CPP_WTRADITIONAL (pfile) = saved_warn_trad;
+}
+
+/* Pop the current context off the stack, re-enabling the macro if the
+ 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 (cpp_reader *pfile)
+{
+ cpp_context *context = pfile->context;
+
+ if (context->macro)
+ context->macro->flags &= ~NODE_DISABLED;
+
+ if (context->buff)
+ _cpp_release_buff (pfile, context->buff);
+
+ pfile->context = context->prev;
+}
+
+/* External routine to get a token. Also used nearly everywhere
+ internally, except for places where we know we can safely call
+ _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
+ expansion, and after any intervening directives. External callers
+ see CPP_EOF only at EOF. Internal callers also see it when meeting
+ a directive inside a macro call, when at the end of a directive and
+ state.in_directive is still 1, and at the end of argument
+ pre-expansion. */
+const cpp_token *
+cpp_get_token (cpp_reader *pfile)
+{
+ const cpp_token *result;
+
+ for (;;)
+ {
+ cpp_hashnode *node;
+ cpp_context *context = pfile->context;
+
+ /* Context->prev == 0 <=> base context. */
+ if (!context->prev)
+ result = _cpp_lex_token (pfile);
+ else if (FIRST (context).token != LAST (context).token)
+ {
+ if (context->direct_p)
+ result = FIRST (context).token++;
+ else
+ result = *FIRST (context).ptoken++;
+
+ if (result->flags & PASTE_LEFT)
+ {
+ paste_all_tokens (pfile, result);
+ if (pfile->state.in_directive)
+ continue;
+ return padding_token (pfile, result);
+ }
+ }
+ else
+ {
+ _cpp_pop_context (pfile);
+ if (pfile->state.in_directive)
+ continue;
+ return &pfile->avoid_paste;
+ }
+
+ if (pfile->state.in_directive && result->type == CPP_COMMENT)
+ continue;
+
+ if (result->type != CPP_NAME)
+ break;
+
+ node = result->val.node;
+
+ if (node->type != NT_MACRO || (result->flags & NO_EXPAND))
+ break;
+
+ if (!(node->flags & NODE_DISABLED))
+ {
+ if (!pfile->state.prevent_expansion
+ && enter_macro_context (pfile, node))
+ {
+ if (pfile->state.in_directive)
+ continue;
+ return padding_token (pfile, result);
+ }
+ }
+ else
+ {
+ /* Flag this token as always unexpandable. FIXME: move this
+ to collect_args()?. */
+ cpp_token *t = _cpp_temp_token (pfile);
+ t->type = result->type;
+ t->flags = result->flags | NO_EXPAND;
+ t->val = result->val;
+ result = t;
+ }
+
+ break;
+ }
+
+ return result;
+}
+
+/* Returns true if we're expanding an object-like macro that was
+ defined in a system header. Just checks the macro at the top of
+ the stack. Used for diagnostic suppression. */
+int
+cpp_sys_macro_p (cpp_reader *pfile)
+{
+ cpp_hashnode *node = pfile->context->macro;
+
+ return node && node->value.macro && node->value.macro->syshdr;
+}
+
+/* Read each token in, until end of the current file. Directives are
+ transparently processed. */
+void
+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. */
+ pfile->buffer->return_at_eof = true;
+
+ pfile->state.discarding_output++;
+ pfile->state.prevent_expansion++;
+
+ if (CPP_OPTION (pfile, traditional))
+ while (_cpp_read_logical_line_trad (pfile))
+ ;
+ else
+ while (cpp_get_token (pfile)->type != CPP_EOF)
+ ;
+
+ pfile->state.discarding_output--;
+ pfile->state.prevent_expansion--;
+}
+
+/* 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 (cpp_reader *pfile, unsigned int count)
+{
+ if (pfile->context->prev == NULL)
+ {
+ pfile->lookaheads += count;
+ while (count--)
+ {
+ pfile->cur_token--;
+ if (pfile->cur_token == pfile->cur_run->base
+ /* Possible with -fpreprocessed and no leading #line. */
+ && pfile->cur_run->prev != NULL)
+ {
+ pfile->cur_run = pfile->cur_run->prev;
+ pfile->cur_token = pfile->cur_run->limit;
+ }
+ }
+ }
+ else
+ {
+ if (count != 1)
+ abort ();
+ if (pfile->context->direct_p)
+ FIRST (pfile->context).token--;
+ else
+ FIRST (pfile->context).ptoken--;
+ }
+}
+
+/* #define directive parsing and handling. */
+
+/* Returns nonzero if a macro redefinition warning is required. */
+static bool
+warn_of_redefinition (cpp_reader *pfile, const cpp_hashnode *node,
+ const cpp_macro *macro2)
+{
+ const cpp_macro *macro1;
+ unsigned int i;
+
+ /* Some redefinitions need to be warned about regardless. */
+ if (node->flags & NODE_WARN)
+ return true;
+
+ /* Redefinition of a macro is allowed if and only if the old and new
+ definitions are the same. (6.10.3 paragraph 2). */
+ macro1 = node->value.macro;
+
+ /* Don't check count here as it can be different in valid
+ traditional redefinitions with just whitespace differences. */
+ if (macro1->paramc != macro2->paramc
+ || macro1->fun_like != macro2->fun_like
+ || macro1->variadic != macro2->variadic)
+ return true;
+
+ /* Check parameter spellings. */
+ for (i = 0; i < macro1->paramc; i++)
+ if (macro1->params[i] != macro2->params[i])
+ return true;
+
+ /* Check the replacement text or tokens. */
+ if (CPP_OPTION (pfile, traditional))
+ return _cpp_expansions_different_trad (macro1, macro2);
+
+ if (macro1->count != macro2->count)
+ return true;
+
+ for (i = 0; i < macro1->count; i++)
+ if (!_cpp_equiv_tokens (¯o1->exp.tokens[i], ¯o2->exp.tokens[i]))
+ return true;
+
+ return false;
+}
+
+/* Free the definition of hashnode H. */
+void
+_cpp_free_definition (cpp_hashnode *h)
+{
+ /* Macros and assertions no longer have anything to free. */
+ h->type = NT_VOID;
+ /* Clear builtin flag in case of redefinition. */
+ h->flags &= ~(NODE_BUILTIN | NODE_DISABLED);
+}
+
+/* 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 (cpp_reader *pfile, cpp_macro *macro, cpp_hashnode *node)
+{
+ unsigned int len;
+ /* Constraint 6.10.3.6 - duplicate parameter names. */
+ if (node->flags & NODE_MACRO_ARG)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "duplicate macro parameter \"%s\"",
+ NODE_NAME (node));
+ return true;
+ }
+
+ if (BUFF_ROOM (pfile->a_buff)
+ < (macro->paramc + 1) * sizeof (cpp_hashnode *))
+ _cpp_extend_buff (pfile, &pfile->a_buff, sizeof (cpp_hashnode *));
+
+ ((cpp_hashnode **) BUFF_FRONT (pfile->a_buff))[macro->paramc++] = node;
+ node->flags |= NODE_MACRO_ARG;
+ len = macro->paramc * sizeof (union _cpp_hashnode_value);
+ if (len > pfile->macro_buffer_len)
+ {
+ pfile->macro_buffer = XRESIZEVEC (unsigned char, 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 (cpp_reader *pfile, cpp_macro *macro)
+{
+ unsigned int prev_ident = 0;
+
+ for (;;)
+ {
+ const cpp_token *token = _cpp_lex_token (pfile);
+
+ switch (token->type)
+ {
+ default:
+ /* Allow/ignore comments in parameter lists if we are
+ preserving comments in macro expansions. */
+ if (token->type == CPP_COMMENT
+ && ! CPP_OPTION (pfile, discard_comments_in_macro_exp))
+ continue;
+
+ cpp_error (pfile, CPP_DL_ERROR,
+ "\"%s\" may not appear in macro parameter list",
+ cpp_token_as_text (pfile, token));
+ return false;
+
+ case CPP_NAME:
+ if (prev_ident)
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "macro parameters must be comma-separated");
+ return false;
+ }
+ prev_ident = 1;
+
+ if (_cpp_save_parameter (pfile, macro, token->val.node))
+ return false;
+ continue;
+
+ case CPP_CLOSE_PAREN:
+ if (prev_ident || macro->paramc == 0)
+ return true;
+
+ /* Fall through to pick up the error. */
+ case CPP_COMMA:
+ if (!prev_ident)
+ {
+ cpp_error (pfile, CPP_DL_ERROR, "parameter name missing");
+ return false;
+ }
+ prev_ident = 0;
+ continue;
+
+ case CPP_ELLIPSIS:
+ macro->variadic = 1;
+ if (!prev_ident)
+ {
+ _cpp_save_parameter (pfile, macro,
+ pfile->spec_nodes.n__VA_ARGS__);
+ pfile->state.va_args_ok = 1;
+ if (! CPP_OPTION (pfile, c99)
+ && CPP_OPTION (pfile, pedantic)
+ && CPP_OPTION (pfile, warn_variadic_macros))
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "anonymous variadic macros were introduced in C99");
+ }
+ else if (CPP_OPTION (pfile, pedantic)
+ && CPP_OPTION (pfile, warn_variadic_macros))
+ 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. */
+ token = _cpp_lex_token (pfile);
+ if (token->type == CPP_CLOSE_PAREN)
+ return true;
+ /* Fall through. */
+
+ case CPP_EOF:
+ cpp_error (pfile, CPP_DL_ERROR, "missing ')' in macro parameter list");
+ return false;
+ }
+ }
+}
+
+/* Allocate room for a token from a macro's replacement list. */
+static cpp_token *
+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));
+
+ return &((cpp_token *) BUFF_FRONT (pfile->a_buff))[macro->count++];
+}
+
+/* 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 (cpp_reader *pfile, cpp_macro *macro)
+{
+ cpp_token *token;
+
+ pfile->cur_token = alloc_expansion_token (pfile, macro);
+ token = _cpp_lex_direct (pfile);
+
+ /* Is this a parameter? */
+ 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->value.arg_index;
+ }
+ else if (CPP_WTRADITIONAL (pfile) && macro->paramc > 0
+ && (token->type == CPP_STRING || token->type == CPP_CHAR))
+ check_trad_stringification (pfile, macro, &token->val.str);
+
+ return token;
+}
+
+static bool
+create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
+{
+ cpp_token *token;
+ const cpp_token *ctoken;
+
+ /* Get the first token of the expansion (or the '(' of a
+ function-like macro). */
+ ctoken = _cpp_lex_token (pfile);
+
+ if (ctoken->type == CPP_OPEN_PAREN && !(ctoken->flags & PREV_WHITE))
+ {
+ bool ok = parse_params (pfile, macro);
+ macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
+ if (!ok)
+ return false;
+
+ /* Success. Commit or allocate the parameter array. */
+ if (pfile->hash_table->alloc_subobject)
+ {
+ cpp_hashnode **params =
+ (cpp_hashnode **) pfile->hash_table->alloc_subobject
+ (sizeof (cpp_hashnode *) * macro->paramc);
+ memcpy (params, macro->params,
+ sizeof (cpp_hashnode *) * macro->paramc);
+ macro->params = params;
+ }
+ else
+ BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc];
+ macro->fun_like = 1;
+ }
+ else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE))
+ {
+ /* While ISO C99 requires whitespace before replacement text
+ in a macro definition, ISO C90 with TC1 allows there characters
+ from the basic source character set. */
+ if (CPP_OPTION (pfile, c99))
+ cpp_error (pfile, CPP_DL_PEDWARN,
+ "ISO C99 requires whitespace after the macro name");
+ else
+ {
+ int warntype = CPP_DL_WARNING;
+ switch (ctoken->type)
+ {
+ case CPP_ATSIGN:
+ case CPP_AT_NAME:
+ case CPP_OBJC_STRING:
+ /* '@' is not in basic character set. */
+ warntype = CPP_DL_PEDWARN;
+ break;
+ case CPP_OTHER:
+ /* Basic character set sans letters, digits and _. */
+ if (strchr ("!\"#%&'()*+,-./:;<=>?[\\]^{|}~",
+ ctoken->val.str.text[0]) == NULL)
+ warntype = CPP_DL_PEDWARN;
+ break;
+ default:
+ /* All other tokens start with a character from basic
+ character set. */
+ break;
+ }
+ cpp_error (pfile, warntype,
+ "missing whitespace after the macro name");
+ }
+ }
+
+ if (macro->fun_like)
+ token = lex_expansion_token (pfile, macro);
+ else
+ {
+ token = alloc_expansion_token (pfile, macro);
+ *token = *ctoken;
+ }
+
+ for (;;)
+ {
+ /* Check the stringifying # constraint 6.10.3.2.1 of
+ function-like macros when lexing the subsequent token. */
+ if (macro->count > 1 && token[-1].type == CPP_HASH && macro->fun_like)
+ {
+ if (token->type == CPP_MACRO_ARG)
+ {
+ token->flags &= ~PREV_WHITE;
+ token->flags |= STRINGIFY_ARG;
+ token->flags |= token[-1].flags & PREV_WHITE;
+ token[-1] = token[0];
+ macro->count--;
+ }
+ /* Let assembler get away with murder. */
+ else if ((CPP_OPTION (pfile, lang) != CLK_ASM)
+ && (!CPP_OPTION(pfile, allow_naked_hash)))
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "'#' is not followed by a macro parameter");
+ return false;
+ }
+ }
+
+ if (token->type == CPP_EOF)
+ break;
+
+ /* Paste operator constraint 6.10.3.3.1. */
+ if (token->type == CPP_PASTE)
+ {
+ /* Token-paste ##, can appear in both object-like and
+ function-like macros, but not at the ends. */
+ if (--macro->count > 0)
+ token = lex_expansion_token (pfile, macro);
+
+ if (macro->count == 0 || token->type == CPP_EOF)
+ {
+ cpp_error (pfile, CPP_DL_ERROR,
+ "'##' cannot appear at either end of a macro expansion");
+ return false;
+ }
+
+ token[-1].flags |= PASTE_LEFT;
+ }
+
+ token = lex_expansion_token (pfile, macro);
+ }
+
+ macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
+ macro->traditional = 0;
+
+ /* Don't count the CPP_EOF. */
+ macro->count--;
+
+ /* Clear whitespace on first token for warn_of_redefinition(). */
+ if (macro->count)
+ macro->exp.tokens[0].flags &= ~PREV_WHITE;
+
+ /* Commit or allocate the memory. */
+ if (pfile->hash_table->alloc_subobject)
+ {
+ cpp_token *tokns =
+ (cpp_token *) pfile->hash_table->alloc_subobject (sizeof (cpp_token)
+ * macro->count);
+ memcpy (tokns, macro->exp.tokens, sizeof (cpp_token) * macro->count);
+ macro->exp.tokens = tokns;
+ }
+ else
+ BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->exp.tokens[macro->count];
+
+ return true;
+}
+
+/* Parse a macro and save its expansion. Returns nonzero on success. */
+bool
+_cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node)
+{
+ cpp_macro *macro;
+ unsigned int i;
+ bool ok;
+
+ if (pfile->hash_table->alloc_subobject)
+ macro = (cpp_macro *) pfile->hash_table->alloc_subobject
+ (sizeof (cpp_macro));
+ else
+ macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
+ macro->line = pfile->directive_line;
+ macro->params = 0;
+ macro->paramc = 0;
+ macro->variadic = 0;
+ macro->used = !CPP_OPTION (pfile, warn_unused_macros);
+ macro->count = 0;
+ macro->fun_like = 0;
+ /* To suppress some diagnostics. */
+ macro->syshdr = pfile->buffer && pfile->buffer->sysp != 0;
+
+ if (CPP_OPTION (pfile, traditional))
+ ok = _cpp_create_trad_definition (pfile, macro);
+ else
+ {
+ cpp_token *saved_cur_token = pfile->cur_token;
+
+ ok = create_iso_definition (pfile, macro);
+
+ /* Restore lexer position because of games lex_expansion_token()
+ plays lexing the macro. We set the type for SEEN_EOL() in
+ directives.c.
+
+ Longer term we should lex the whole line before coming here,
+ and just copy the expansion. */
+ saved_cur_token[-1].type = pfile->cur_token[-1].type;
+ pfile->cur_token = saved_cur_token;
+
+ /* Stop the lexer accepting __VA_ARGS__. */
+ pfile->state.va_args_ok = 0;
+ }
+
+ /* Clear the fast argument lookup indices. */
+ for (i = macro->paramc; i-- > 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;
+
+ if (node->type == NT_MACRO)
+ {
+ if (CPP_OPTION (pfile, warn_unused_macros))
+ _cpp_warn_if_unused_macro (pfile, node, NULL);
+
+ if (warn_of_redefinition (pfile, node, macro))
+ {
+ 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, CPP_DL_PEDWARN,
+ node->value.macro->line, 0,
+ "this is the location of the previous definition");
+ }
+ }
+
+ if (node->type != NT_VOID)
+ _cpp_free_definition (node);
+
+ /* Enter definition in hash table. */
+ node->type = NT_MACRO;
+ node->value.macro = macro;
+ if (! ustrncmp (NODE_NAME (node), DSC ("__STDC_")))
+ node->flags |= NODE_WARN;
+
+ return ok;
+}
+
+/* Warn if a token in STRING matches one of a function-like MACRO's
+ parameters. */
+static void
+check_trad_stringification (cpp_reader *pfile, const cpp_macro *macro,
+ const cpp_string *string)
+{
+ unsigned int i, len;
+ const uchar *p, *q, *limit;
+
+ /* Loop over the string. */
+ 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))
+ p++;
+
+ /* Find the end of the identifier. */
+ q = p;
+ while (q < limit && is_idchar (*q))
+ q++;
+
+ len = q - p;
+
+ /* Loop over the function macro arguments to see if the
+ identifier inside the string matches one of them. */
+ for (i = 0; i < macro->paramc; i++)
+ {
+ const cpp_hashnode *node = macro->params[i];
+
+ if (NODE_LEN (node) == len
+ && !memcmp (p, NODE_NAME (node), len))
+ {
+ cpp_error (pfile, CPP_DL_WARNING,
+ "macro argument \"%s\" would be stringified in traditional C",
+ NODE_NAME (node));
+ break;
+ }
+ }
+ }
+}
+
+/* Returns the name, arguments and expansion of a macro, in a format
+ suitable to be read back in again, and therefore also for DWARF 2
+ debugging info. e.g. "PASTE(X, Y) X ## Y", or "MACNAME EXPANSION".
+ 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 (cpp_reader *pfile, const cpp_hashnode *node)
+{
+ unsigned int i, len;
+ const cpp_macro *macro = node->value.macro;
+ unsigned char *buffer;
+
+ if (node->type != NT_MACRO || (node->flags & NODE_BUILTIN))
+ {
+ cpp_error (pfile, CPP_DL_ICE,
+ "invalid hash type %d in cpp_macro_definition", node->type);
+ return 0;
+ }
+
+ /* Calculate length. */
+ len = NODE_LEN (node) + 2; /* ' ' and NUL. */
+ if (macro->fun_like)
+ {
+ len += 4; /* "()" plus possible final ".." of named
+ varargs (we have + 1 below). */
+ for (i = 0; i < macro->paramc; i++)
+ 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
+ {
+ for (i = 0; i < macro->count; i++)
+ {
+ cpp_token *token = ¯o->exp.tokens[i];
+
+ if (token->type == CPP_MACRO_ARG)
+ len += NODE_LEN (macro->params[token->val.arg_no - 1]);
+ else
+ 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 = XRESIZEVEC (unsigned char,
+ pfile->macro_buffer, len);
+ pfile->macro_buffer_len = len;
+ }
+
+ /* Fill in the buffer. Start with the macro name. */
+ buffer = pfile->macro_buffer;
+ memcpy (buffer, NODE_NAME (node), NODE_LEN (node));
+ buffer += NODE_LEN (node);
+
+ /* Parameter names. */
+ if (macro->fun_like)
+ {
+ *buffer++ = '(';
+ for (i = 0; i < macro->paramc; i++)
+ {
+ cpp_hashnode *param = macro->params[i];
+
+ if (param != pfile->spec_nodes.n__VA_ARGS__)
+ {
+ memcpy (buffer, NODE_NAME (param), NODE_LEN (param));
+ buffer += NODE_LEN (param);
+ }
+
+ if (i + 1 < macro->paramc)
+ /* Don't emit a space after the comma here; we're trying
+ to emit a Dwarf-friendly definition, and the Dwarf spec
+ forbids spaces in the argument list. */
+ *buffer++ = ',';
+ else if (macro->variadic)
+ *buffer++ = '.', *buffer++ = '.', *buffer++ = '.';
+ }
+ *buffer++ = ')';
+ }
+
+ /* The Dwarf spec requires a space after the macro name, even if the
+ definition is the empty string. */
+ *buffer++ = ' ';
+
+ if (CPP_OPTION (pfile, traditional))
+ buffer = _cpp_copy_replacement_text (macro, buffer);
+ else if (macro->count)
+ /* Expansion tokens. */
+ {
+ for (i = 0; i < macro->count; i++)
+ {
+ cpp_token *token = ¯o->exp.tokens[i];
+
+ if (token->flags & PREV_WHITE)
+ *buffer++ = ' ';
+ if (token->flags & STRINGIFY_ARG)
+ *buffer++ = '#';
+
+ if (token->type == CPP_MACRO_ARG)
+ {
+ memcpy (buffer,
+ 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, false);
+
+ if (token->flags & PASTE_LEFT)
+ {
+ *buffer++ = ' ';
+ *buffer++ = '#';
+ *buffer++ = '#';
+ /* Next has PREV_WHITE; see _cpp_create_definition. */
+ }
+ }
+ }
+
+ *buffer = '\0';
+ return pfile->macro_buffer;
+}
--- /dev/null
+/* Dependency generator for Makefile fragments.
+ 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
+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 "mkdeps.h"
+#include "internal.h"
+
+/* Keep this structure local to this file, so clients don't find it
+ easy to start making assumptions. */
+struct deps
+{
+ const char **targetv;
+ unsigned int ntargets; /* number of slots actually occupied */
+ unsigned int targets_size; /* amt of allocated space - in words */
+
+ const char **depv;
+ unsigned int ndeps;
+ unsigned int deps_size;
+};
+
+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
+ characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
+ 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 (const char *filename)
+{
+ int len;
+ const char *p, *q;
+ char *dst, *buffer;
+
+ for (p = filename, len = 0; *p; p++, len++)
+ {
+ switch (*p)
+ {
+ case ' ':
+ case '\t':
+ /* GNU make uses a weird quoting scheme for white space.
+ A space or tab preceded by 2N+1 backslashes represents
+ N backslashes followed by space; a space or tab
+ preceded by 2N backslashes represents N backslashes at
+ the end of a file name; and backslashes in other
+ contexts should not be doubled. */
+ for (q = p - 1; filename <= q && *q == '\\'; q--)
+ len++;
+ len++;
+ break;
+
+ case '$':
+ /* '$' is quoted by doubling it. */
+ len++;
+ break;
+ }
+ }
+
+ /* Now we know how big to make the buffer. */
+ buffer = xmalloc (len + 1);
+
+ for (p = filename, dst = buffer; *p; p++, dst++)
+ {
+ switch (*p)
+ {
+ case ' ':
+ case '\t':
+ for (q = p - 1; filename <= q && *q == '\\'; q--)
+ *dst++ = '\\';
+ *dst++ = '\\';
+ break;
+
+ case '$':
+ *dst++ = '$';
+ break;
+
+ default:
+ /* nothing */;
+ }
+ *dst = *p;
+ }
+
+ *dst = '\0';
+ return buffer;
+}
+
+/* Public routines. */
+
+struct deps *
+deps_init (void)
+{
+ struct deps *d = xmalloc (sizeof (struct deps));
+
+ /* Allocate space for the vectors only if we need it. */
+
+ d->targetv = 0;
+ d->depv = 0;
+
+ d->ntargets = 0;
+ d->targets_size = 0;
+ d->ndeps = 0;
+ d->deps_size = 0;
+
+ return d;
+}
+
+void
+deps_free (struct deps *d)
+{
+ unsigned int i;
+
+ if (d->targetv)
+ {
+ for (i = 0; i < d->ntargets; i++)
+ free ((void *) d->targetv[i]);
+ free (d->targetv);
+ }
+
+ if (d->depv)
+ {
+ for (i = 0; i < d->ndeps; i++)
+ free ((void *) d->depv[i]);
+ free (d->depv);
+ }
+
+ 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 (struct deps *d, const char *t, int quote)
+{
+ if (d->ntargets == d->targets_size)
+ {
+ d->targets_size = d->targets_size * 2 + 4;
+ d->targetv = xrealloc (d->targetv,
+ d->targets_size * sizeof (const char *));
+ }
+
+ if (quote)
+ t = munge (t); /* Also makes permanent copy. */
+ else
+ t = xstrdup (t);
+
+ d->targetv[d->ntargets++] = t;
+}
+
+/* Sets the default target if none has been given already. An empty
+ string as the default target in interpreted as stdin. The string
+ is quoted for MAKE. */
+void
+deps_add_default_target (cpp_reader *pfile, const char *tgt)
+{
+ struct deps *d = pfile->deps;
+
+ /* Only if we have no targets. */
+ if (d->ntargets)
+ return;
+
+ if (tgt[0] == '\0')
+ deps_add_target (d, "-", 1);
+ else
+ {
+#ifndef TARGET_OBJECT_SUFFIX
+# define TARGET_OBJECT_SUFFIX ".o"
+#endif
+ const char *start = lbasename (tgt);
+ char *o;
+ char *suffix;
+ const char *obj_ext;
+
+ if (NULL == CPP_OPTION (pfile, obj_ext))
+ obj_ext = TARGET_OBJECT_SUFFIX;
+ else if (CPP_OPTION (pfile, obj_ext)[0] != '.')
+ {
+ char *t = alloca (strlen (CPP_OPTION (pfile, obj_ext)) + 2);
+ t[0] = '.';
+ strcpy (&t[1], CPP_OPTION (pfile, obj_ext));
+ obj_ext = t;
+ }
+ else
+ obj_ext = CPP_OPTION (pfile, obj_ext);
+
+ 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 (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 = xrealloc (d->depv, d->deps_size * sizeof (const char *));
+ }
+ d->depv[d->ndeps++] = t;
+}
+
+void
+deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
+{
+ unsigned int size, i, column;
+
+ column = 0;
+ if (colmax && colmax < 34)
+ colmax = 34;
+
+ for (i = 0; i < d->ntargets; i++)
+ {
+ size = strlen (d->targetv[i]);
+ column += size;
+ if (colmax && column > colmax)
+ {
+ fputs (" \\\n ", fp);
+ column = 1 + size;
+ }
+ if (i)
+ {
+ putc (' ', fp);
+ column++;
+ }
+ fputs (d->targetv[i], fp);
+ }
+
+ putc (':', fp);
+ putc (' ', fp);
+ column += 2;
+
+ for (i = 0; i < d->ndeps; i++)
+ {
+ size = strlen (d->depv[i]);
+ column += size;
+ if (colmax && column > colmax)
+ {
+ fputs (" \\\n ", fp);
+ column = 1 + size;
+ }
+ if (i)
+ {
+ putc (' ', fp);
+ column++;
+ }
+ fputs (d->depv[i], fp);
+ }
+ putc ('\n', fp);
+}
+
+void
+deps_phony_targets (const struct deps *d, FILE *fp)
+{
+ unsigned int i;
+
+ for (i = 1; i < d->ndeps; i++)
+ {
+ putc ('\n', fp);
+ fputs (d->depv[i], fp);
+ putc (':', 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;
+}
--- /dev/null
+/* Hash tables.
+ Copyright (C) 2000, 2001, 2003, 2004 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 "symtab.h"
+
+/* The code below is a specialization of Vladimir Makarov's expandable
+ hash tables (see libiberty/hashtab.c). The abstraction penalty was
+ too high to continue using the generic form. This code knows
+ intrinsically how to calculate a hash value, and how to compare an
+ existing entry with a potential new one. Also, the ability to
+ delete members from the table has been removed. */
+
+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 (const unsigned char *str, size_t len)
+{
+ size_t n = len;
+ unsigned int r = 0;
+
+ while (n--)
+ r = HT_HASHSTEP (r, *str++);
+
+ return HT_HASHFINISH (r, len);
+}
+
+/* Initialize an identifier hashtable. */
+
+hash_table *
+ht_create (unsigned int order)
+{
+ unsigned int nslots = 1 << order;
+ hash_table *table;
+
+ table = XCNEW (hash_table);
+
+ /* Strings need no alignment. */
+ _obstack_begin (&table->stack, 0, 0,
+ (void *(*) (long)) xmalloc,
+ (void (*) (void *)) free);
+
+ obstack_alignment_mask (&table->stack) = 0;
+
+ table->entries = XCNEWVEC (hashnode, nslots);
+ table->entries_owned = true;
+ table->nslots = nslots;
+ return table;
+}
+
+/* Frees all memory associated with a hash table. */
+
+void
+ht_destroy (hash_table *table)
+{
+ obstack_free (&table->stack, NULL);
+ if (table->entries_owned)
+ free (table->entries);
+ free (table);
+}
+
+/* Returns the hash entry for the a STR of length LEN. If that string
+ already exists in the table, returns the existing entry, and, if
+ INSERT is CPP_ALLOCED, frees the last obstack object. If the
+ identifier hasn't been seen before, and INSERT is CPP_NO_INSERT,
+ returns NULL. Otherwise insert and returns a new entry. A new
+ string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is
+ CPP_ALLOCED and the item is assumed to be at the top of the
+ obstack. */
+hashnode
+ht_lookup (hash_table *table, const unsigned char *str, size_t len,
+ enum ht_lookup_option insert)
+{
+ return ht_lookup_with_hash (table, str, len, calc_hash (str, len),
+ insert);
+}
+
+hashnode
+ht_lookup_with_hash (hash_table *table, const unsigned char *str,
+ size_t len, unsigned int hash,
+ enum ht_lookup_option insert)
+{
+ unsigned int hash2;
+ unsigned int index;
+ size_t sizemask;
+ hashnode node;
+
+ sizemask = table->nslots - 1;
+ index = hash & sizemask;
+ table->searches++;
+
+ node = table->entries[index];
+
+ if (node != NULL)
+ {
+ 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;
+ }
+
+ /* 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)
+ return NULL;
+
+ node = (*table->alloc_node) (table);
+ table->entries[index] = node;
+
+ HT_LEN (node) = (unsigned int) len;
+ node->hash_value = hash;
+ if (insert == HT_ALLOC)
+ HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
+ str, len);
+ else
+ HT_STR (node) = str;
+
+ if (++table->nelements * 4 >= table->nslots * 3)
+ /* Must expand the string table. */
+ ht_expand (table);
+
+ return node;
+}
+
+/* Double the size of a hash table, re-hashing existing entries. */
+
+static void
+ht_expand (hash_table *table)
+{
+ hashnode *nentries, *p, *limit;
+ unsigned int size, sizemask;
+
+ size = table->nslots * 2;
+ nentries = XCNEWVEC (hashnode, size);
+ sizemask = size - 1;
+
+ p = table->entries;
+ limit = p + table->nslots;
+ do
+ if (*p)
+ {
+ unsigned int index, hash, hash2;
+
+ hash = (*p)->hash_value;
+ index = hash & sizemask;
+
+ if (nentries[index])
+ {
+ hash2 = ((hash * 17) & sizemask) | 1;
+ do
+ {
+ index = (index + hash2) & sizemask;
+ }
+ while (nentries[index]);
+ }
+ nentries[index] = *p;
+ }
+ while (++p < limit);
+
+ if (table->entries_owned)
+ free (table->entries);
+ table->entries_owned = true;
+ table->entries = nentries;
+ table->nslots = size;
+}
+
+/* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
+ the node, and V. */
+void
+ht_forall (hash_table *table, ht_cb cb, const void *v)
+{
+ hashnode *p, *limit;
+
+ p = table->entries;
+ limit = p + table->nslots;
+ do
+ if (*p)
+ {
+ if ((*cb) (table->pfile, *p, v) == 0)
+ break;
+ }
+ while (++p < limit);
+}
+
+/* Restore the hash table. */
+void
+ht_load (hash_table *ht, hashnode *entries,
+ unsigned int nslots, unsigned int nelements,
+ bool own)
+{
+ if (ht->entries_owned)
+ free (ht->entries);
+ ht->entries = entries;
+ ht->nslots = nslots;
+ ht->nelements = nelements;
+ ht->entries_owned = own;
+}
+
+/* Dump allocation statistics to stderr. */
+
+void
+ht_dump_statistics (hash_table *table)
+{
+ size_t nelts, nids, overhead, headers;
+ size_t total_bytes, longest;
+ double sum_of_squares, exp_len, exp_len2, exp2_len;
+ hashnode *p, *limit;
+
+#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
+ ? (x) \
+ : ((x) < 1024*1024*10 \
+ ? (x) / 1024 \
+ : (x) / (1024*1024))))
+#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
+
+ total_bytes = longest = sum_of_squares = nids = 0;
+ p = table->entries;
+ limit = p + table->nslots;
+ do
+ if (*p)
+ {
+ size_t n = HT_LEN (*p);
+
+ total_bytes += n;
+ sum_of_squares += (double) n * n;
+ if (n > longest)
+ longest = n;
+ nids++;
+ }
+ while (++p < limit);
+
+ nelts = table->nelements;
+ overhead = obstack_memory_used (&table->stack) - total_bytes;
+ headers = table->nslots * sizeof (hashnode);
+
+ fprintf (stderr, "\nString pool\nentries\t\t%lu\n",
+ (unsigned long) nelts);
+ fprintf (stderr, "identifiers\t%lu (%.2f%%)\n",
+ (unsigned long) nids, nids * 100.0 / nelts);
+ fprintf (stderr, "slots\t\t%lu\n",
+ (unsigned long) table->nslots);
+ fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
+ SCALE (total_bytes), LABEL (total_bytes),
+ SCALE (overhead), LABEL (overhead));
+ fprintf (stderr, "table size\t%lu%c\n",
+ SCALE (headers), LABEL (headers));
+
+ exp_len = (double)total_bytes / (double)nelts;
+ exp2_len = exp_len * exp_len;
+ exp_len2 = (double) sum_of_squares / (double) nelts;
+
+ fprintf (stderr, "coll/search\t%.4f\n",
+ (double) table->collisions / (double) table->searches);
+ fprintf (stderr, "ins/search\t%.4f\n",
+ (double) nelts / (double) table->searches);
+ fprintf (stderr, "avg. entry\t%.2f bytes (+/- %.2f)\n",
+ exp_len, approx_sqrt (exp_len2 - exp2_len));
+ fprintf (stderr, "longest entry\t%lu\n",
+ (unsigned long) longest);
+#undef SCALE
+#undef LABEL
+}
+
+/* Return the approximate positive square root of a number N. This is for
+ statistical reports, not code generation. */
+static double
+approx_sqrt (double x)
+{
+ double s, d;
+
+ if (x < 0)
+ abort ();
+ if (x == 0)
+ return 0;
+
+ s = x;
+ do
+ {
+ d = (s * s - x) / (2 * s);
+ s -= d;
+ }
+ while (d > .0001);
+ return s;
+}
--- /dev/null
+/* Get common system includes and various definitions and declarations based
+ on autoconf macros.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+This file is part of libcpp (aka cpplib).
+
+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, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+
+#ifndef LIBCPP_SYSTEM_H
+#define LIBCPP_SYSTEM_H
+
+/* We must include stdarg.h before stdio.h. */
+#include <stdarg.h>
+
+#ifdef HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+
+#include <stdio.h>
+
+/* Define a generic NULL if one hasn't already been defined. */
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Use the unlocked open routines from libiberty. */
+#define fopen(PATH,MODE) fopen_unlocked(PATH,MODE)
+#define fdopen(FILDES,MODE) fdopen_unlocked(FILDES,MODE)
+#define freopen(PATH,MODE,STREAM) freopen_unlocked(PATH,MODE,STREAM)
+
+/* 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_PUTCHAR_UNLOCKED
+# undef putchar
+# define putchar(C) putchar_unlocked (C)
+# endif
+# ifdef HAVE_GETC_UNLOCKED
+# undef getc
+# define getc(Stream) getc_unlocked (Stream)
+# endif
+# ifdef HAVE_GETCHAR_UNLOCKED
+# undef getchar
+# define getchar() getchar_unlocked ()
+# endif
+# ifdef HAVE_FPUTC_UNLOCKED
+# undef fputc
+# define fputc(C, Stream) fputc_unlocked (C, Stream)
+# endif
+
+# ifdef HAVE_CLEARERR_UNLOCKED
+# undef clearerr
+# define clearerr(Stream) clearerr_unlocked (Stream)
+# if defined (HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED
+extern void clearerr_unlocked (FILE *);
+# endif
+# endif
+# ifdef HAVE_FEOF_UNLOCKED
+# undef feof
+# define feof(Stream) feof_unlocked (Stream)
+# if defined (HAVE_DECL_FEOF_UNLOCKED) && !HAVE_DECL_FEOF_UNLOCKED
+extern int feof_unlocked (FILE *);
+# endif
+# endif
+# ifdef HAVE_FILENO_UNLOCKED
+# undef fileno
+# define fileno(Stream) fileno_unlocked (Stream)
+# if defined (HAVE_DECL_FILENO_UNLOCKED) && !HAVE_DECL_FILENO_UNLOCKED
+extern int fileno_unlocked (FILE *);
+# endif
+# endif
+# ifdef HAVE_FFLUSH_UNLOCKED
+# undef fflush
+# define fflush(Stream) fflush_unlocked (Stream)
+# if defined (HAVE_DECL_FFLUSH_UNLOCKED) && !HAVE_DECL_FFLUSH_UNLOCKED
+extern int fflush_unlocked (FILE *);
+# endif
+# endif
+# ifdef HAVE_FGETC_UNLOCKED
+# undef fgetc
+# define fgetc(Stream) fgetc_unlocked (Stream)
+# if defined (HAVE_DECL_FGETC_UNLOCKED) && !HAVE_DECL_FGETC_UNLOCKED
+extern int fgetc_unlocked (FILE *);
+# endif
+# endif
+# ifdef HAVE_FGETS_UNLOCKED
+# undef fgets
+# define fgets(S, n, Stream) fgets_unlocked (S, n, Stream)
+# if defined (HAVE_DECL_FGETS_UNLOCKED) && !HAVE_DECL_FGETS_UNLOCKED
+extern char *fgets_unlocked (char *, int, FILE *);
+# endif
+# 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_FERROR_UNLOCKED
+# undef ferror
+# define ferror(Stream) ferror_unlocked (Stream)
+# if defined (HAVE_DECL_FERROR_UNLOCKED) && !HAVE_DECL_FERROR_UNLOCKED
+extern int ferror_unlocked (FILE *);
+# endif
+# endif
+# ifdef HAVE_FREAD_UNLOCKED
+# undef fread
+# define fread(Ptr, Size, N, Stream) fread_unlocked (Ptr, Size, N, Stream)
+# if defined (HAVE_DECL_FREAD_UNLOCKED) && !HAVE_DECL_FREAD_UNLOCKED
+extern size_t fread_unlocked (void *, size_t, size_t, 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 size_t 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
+
+#include <sys/types.h>
+#include <errno.h>
+
+#if !defined (errno) && defined (HAVE_DECL_ERRNO) && !HAVE_DECL_ERRNO
+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>
+#else
+# ifdef HAVE_STRING_H
+# include <string.h>
+# else
+# ifdef HAVE_STRINGS_H
+# include <strings.h>
+# endif
+# endif
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+/* Infrastructure for defining missing _MAX and _MIN macros. Note that
+ macros defined with these cannot be used in #if. */
+
+/* The extra casts work around common compiler bugs. */
+#define INTTYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
+ It is necessary at least when t == time_t. */
+#define INTTYPE_MINIMUM(t) ((t) (INTTYPE_SIGNED (t) \
+ ? ~ (t) 0 << (sizeof(t) * CHAR_BIT - 1) : (t) 0))
+#define INTTYPE_MAXIMUM(t) ((t) (~ (t) 0 - INTTYPE_MINIMUM (t)))
+
+/* Use that infrastructure to provide a few constants. */
+#ifndef UCHAR_MAX
+# define UCHAR_MAX INTTYPE_MAXIMUM (unsigned char)
+#endif
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# ifdef HAVE_TIME_H
+# include <time.h>
+# endif
+# endif
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+# endif
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#ifdef HAVE_LANGINFO_CODESET
+# include <langinfo.h>
+#endif
+
+#ifndef HAVE_SETLOCALE
+# define setlocale(category, locale) (locale)
+#endif
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#else
+/* Stubs. */
+# undef dgettext
+# define dgettext(package, msgid) (msgid)
+#endif
+
+#ifndef _
+# define _(msgid) dgettext (PACKAGE, msgid)
+#endif
+
+#ifndef N_
+# define N_(msgid) msgid
+#endif
+
+/* Some systems define these in, e.g., param.h. We undefine these names
+ here to avoid the warnings. We prefer to use our definitions since we
+ know they are correct. */
+
+#undef MIN
+#undef MAX
+#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
+#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
+
+/* The HAVE_DECL_* macros are three-state, undefined, 0 or 1. If they
+ are defined to 0 then we must provide the relevant declaration
+ here. These checks will be in the undefined state while configure
+ is running so be careful to test "defined (HAVE_DECL_*)". */
+
+#if defined (HAVE_DECL_ABORT) && !HAVE_DECL_ABORT
+extern void abort (void);
+#endif
+
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+/* Test if something is a normal file. */
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+/* Test if something is a directory. */
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* Test if something is a character special file. */
+#ifndef S_ISCHR
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+
+/* Test if something is a block special file. */
+#ifndef S_ISBLK
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+
+/* Test if something is a socket. */
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(m) 0
+# endif
+#endif
+
+/* Test if something is a FIFO. */
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(m) 0
+# endif
+#endif
+
+/* Approximate O_NOCTTY and O_BINARY. */
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/* Filename handling macros. */
+#include "filenames.h"
+
+/* Get libiberty declarations. */
+#include "libiberty.h"
+#if defined(__APPLE__) && defined(__MACH__)
+#include <libiberty/safe-ctype.h>
+#else
+#include <safe-ctype.h>
+#endif
+
+/* 1 if we have C99 designated initializers.
+
+ ??? C99 designated initializers are not supported by most C++
+ compilers, including G++. -- gdr, 2005-05-18 */
+#if !defined(HAVE_DESIGNATED_INITIALIZERS)
+#if defined(__APPLE__) && (__MACH__)
+#define HAVE_DESIGNATED_INITIALIZERS 0
+#else
+#define HAVE_DESIGNATED_INITIALIZERS \
+ ((!defined(__cplusplus) && (GCC_VERSION >= 2007)) \
+ || (__STDC_VERSION__ >= 199901L))
+#endif
+#endif
+
+/* Be conservative and only use enum bitfields with GCC.
+ FIXME: provide a complete autoconf test for buggy enum bitfields. */
+
+#if (GCC_VERSION > 2000)
+#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)
+#endif
+
+/* __builtin_expect(A, B) evaluates to A, but notifies the compiler that
+ the most likely value of A is B. This feature was added at some point
+ between 2.95 and 3.0. Let's use 3.0 as the lower bound for now. */
+#if (GCC_VERSION < 3000)
+#define __builtin_expect(a, b) (a)
+#endif
+
+/* Provide a fake boolean type. We make no attempt to use the
+ C99 _Bool, as it may not be available in the bootstrap compiler,
+ and even if it is, it is liable to be buggy.
+ This must be after all inclusion of system headers, as some of
+ them will mess us up. */
+#undef bool
+#undef true
+#undef false
+#undef TRUE
+#undef FALSE
+
+#ifndef __cplusplus
+#define bool unsigned char
+#endif
+#define true 1
+#define false 0
+
+/* Some compilers do not allow the use of unsigned char in bitfields. */
+#define BOOL_BITFIELD unsigned int
+
+/* Poison identifiers we do not want to use. */
+#if (GCC_VERSION >= 3000)
+#undef calloc
+#undef strdup
+#undef malloc
+#undef realloc
+ #pragma GCC poison calloc strdup
+ #pragma GCC poison malloc realloc
+
+/* 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
+
+/* Note: not all uses of the `index' token (e.g. variable names and
+ structure members) have been eliminated. */
+#undef bcopy
+#undef bzero
+#undef bcmp
+#undef rindex
+ #pragma GCC poison bcopy bzero bcmp rindex
+
+#endif /* GCC >= 3.0 */
+
+/* SDCC specific */
+#include "sdcpp.h"
+
+#endif /* ! LIBCPP_SYSTEM_H */
--- /dev/null
+/* CPP Library - traditional lexical analysis and macro expansion.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Contributed by Neil Booth, May 2002
+
+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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "internal.h"
+
+/* The replacement text of a function-like macro is stored as a
+ contiguous sequence of aligned blocks, each representing the text
+ between subsequent parameters.
+
+ Each block comprises the text between its surrounding parameters,
+ the length of that text, and the one-based index of the following
+ parameter. The final block in the replacement text is easily
+ recognizable as it has an argument index of zero. */
+
+struct block
+{
+ unsigned int text_len;
+ unsigned short arg_index;
+ uchar text[1];
+};
+
+#define BLOCK_HEADER_LEN offsetof (struct block, text)
+#define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + (TEXT_LEN))
+
+/* Structure holding information about a function-like macro
+ invocation. */
+struct fun_macro
+{
+ /* Memory buffer holding the trad_arg array. */
+ _cpp_buff *buff;
+
+ /* An array of size the number of macro parameters + 1, containing
+ the offsets of the start of each macro argument in the output
+ buffer. The argument continues until the character before the
+ start of the next one. */
+ size_t *args;
+
+ /* The hashnode of the macro. */
+ cpp_hashnode *node;
+
+ /* The offset of the macro name in the output buffer. */
+ size_t offset;
+
+ /* The line the macro name appeared on. */
+ unsigned int line;
+
+ /* Zero-based index of argument being currently lexed. */
+ unsigned int argc;
+};
+
+/* Lexing state. It is mostly used to prevent macro expansion. */
+enum ls {ls_none = 0, /* Normal state. */
+ ls_fun_open, /* When looking for '('. */
+ ls_fun_close, /* When looking for ')'. */
+ ls_defined, /* After defined. */
+ ls_defined_close, /* Looking for ')' of defined(). */
+ ls_hash, /* After # in preprocessor conditional. */
+ ls_predicate, /* After the predicate, maybe paren? */
+ ls_answer}; /* In answer to predicate. */
+
+/* Lexing TODO: Maybe handle space in escaped newlines. Stop lex.c
+ from recognizing comments and directives during its lexing pass. */
+
+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 (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. */
+ n += 2 + 1;
+
+ if (n > (size_t) (pfile->out.limit - pfile->out.cur))
+ {
+ size_t size = pfile->out.cur - pfile->out.base;
+ size_t new_size = (size + n) * 3 / 2;
+
+ pfile->out.base = XRESIZEVEC (unsigned char, pfile->out.base, new_size);
+ pfile->out.limit = pfile->out.base + new_size;
+ pfile->out.cur = pfile->out.base + size;
+ }
+}
+
+/* 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 *cur = pfile->buffer->cur;
+
+ cur++;
+ if (*cur == '/')
+ cur++;
+
+ /* People like decorating comments with '*', so check for '/'
+ instead for efficiency. */
+ while(! (*cur++ == '/' && cur[-2] == '*') )
+ ;
+
+ pfile->buffer->cur = cur;
+}
+
+/* CUR points to the asterisk introducing a comment in the current
+ context. IN_DEFINE is true if we are in the replacement text of a
+ macro.
+
+ The asterisk and following comment is copied to the buffer pointed
+ to by pfile->out.cur, which must be of sufficient size.
+ Unterminated comments are diagnosed, and correctly terminated in
+ the output. pfile->out.cur is updated depending upon IN_DEFINE,
+ -C, -CC and pfile->state.in_directive.
+
+ Returns a pointer to the first character after the comment in the
+ input buffer. */
+static const uchar *
+copy_comment (cpp_reader *pfile, const uchar *cur, int in_define)
+{
+ bool unterminated, copy = false;
+ source_location src_loc = pfile->line_table->highest_line;
+ cpp_buffer *buffer = pfile->buffer;
+
+ 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, src_loc, 0,
+ "unterminated comment");
+
+ /* Comments in directives become spaces so that tokens are properly
+ separated when the ISO preprocessor re-lexes the line. The
+ exception is #define. */
+ if (pfile->state.in_directive)
+ {
+ if (in_define)
+ {
+ if (CPP_OPTION (pfile, discard_comments_in_macro_exp))
+ pfile->out.cur--;
+ else
+ copy = true;
+ }
+ else
+ pfile->out.cur[-1] = ' ';
+ }
+ else if (CPP_OPTION (pfile, discard_comments))
+ pfile->out.cur--;
+ else
+ 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 buffer->cur;
+}
+
+/* CUR points to any character in the input buffer. Skips over all
+ contiguous horizontal white space and NULs, including comments if
+ SKIP_COMMENTS, until reaching the first non-horizontal-whitespace
+ character or the end of the current context. Escaped newlines are
+ removed.
+
+ The whitespace is copied verbatim to the output buffer, except that
+ comments are handled as described in copy_comment().
+ pfile->out.cur is updated.
+
+ Returns a pointer to the first character after the whitespace in
+ the input buffer. */
+static const uchar *
+skip_whitespace (cpp_reader *pfile, const uchar *cur, int skip_comments)
+{
+ uchar *out = pfile->out.cur;
+
+ for (;;)
+ {
+ unsigned int c = *cur++;
+ *out++ = c;
+
+ if (is_nvspace (c))
+ continue;
+
+ if (c == '/' && *cur == '*' && skip_comments)
+ {
+ pfile->out.cur = out;
+ cur = copy_comment (pfile, cur, false /* in_define */);
+ out = pfile->out.cur;
+ continue;
+ }
+
+ out--;
+ break;
+ }
+
+ pfile->out.cur = out;
+ return cur - 1;
+}
+
+/* Lexes and outputs an identifier starting at CUR, which is assumed
+ to point to a valid first character of an identifier. Returns
+ the hashnode, and updates out.cur. */
+static cpp_hashnode *
+lex_identifier (cpp_reader *pfile, const uchar *cur)
+{
+ size_t len;
+ uchar *out = pfile->out.cur;
+ cpp_hashnode *result;
+
+ do
+ *out++ = *cur++;
+ while (is_numchar (*cur));
+
+ CUR (pfile->context) = cur;
+ len = out - pfile->out.cur;
+ result = (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->out.cur,
+ len, HT_ALLOC);
+ pfile->out.cur = out;
+ return result;
+}
+
+/* Overlays the true file buffer temporarily with text of length LEN
+ starting at START. The true buffer is restored upon calling
+ restore_buff(). */
+void
+_cpp_overlay_buffer (cpp_reader *pfile, const uchar *start, size_t len)
+{
+ cpp_buffer *buffer = pfile->buffer;
+
+ pfile->overlaid_buffer = buffer;
+ pfile->saved_cur = buffer->cur;
+ pfile->saved_rlimit = buffer->rlimit;
+ pfile->saved_line_base = buffer->next_line;
+ buffer->need_line = false;
+
+ buffer->cur = start;
+ buffer->line_base = start;
+ buffer->rlimit = start + len;
+}
+
+/* Restores a buffer overlaid by _cpp_overlay_buffer(). */
+void
+_cpp_remove_overlay (cpp_reader *pfile)
+{
+ cpp_buffer *buffer = pfile->overlaid_buffer;
+
+ buffer->cur = pfile->saved_cur;
+ buffer->rlimit = pfile->saved_rlimit;
+ buffer->line_base = pfile->saved_line_base;
+ buffer->need_line = true;
+
+ pfile->overlaid_buffer = NULL;
+}
+
+/* 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 (cpp_reader *pfile)
+{
+ do
+ {
+ if (pfile->buffer->need_line && !_cpp_get_fresh_line (pfile))
+ return false;
+ }
+ while (!_cpp_scan_out_logical_line (pfile, NULL) || pfile->state.skipping);
+
+ return pfile->buffer != NULL;
+}
+
+/* Set up state for finding the opening '(' of a function-like
+ macro. */
+static void
+maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start, struct fun_macro *macro)
+{
+ unsigned int n = node->value.macro->paramc + 1;
+
+ if (macro->buff)
+ _cpp_release_buff (pfile, macro->buff);
+ macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t));
+ macro->args = (size_t *) BUFF_FRONT (macro->buff);
+ macro->node = node;
+ macro->offset = start - pfile->out.base;
+ macro->argc = 0;
+}
+
+/* Save the OFFSET of the start of the next argument to MACRO. */
+static void
+save_argument (struct fun_macro *macro, size_t offset)
+{
+ macro->argc++;
+ if (macro->argc <= macro->node->value.macro->paramc)
+ macro->args[macro->argc] = offset;
+}
+
+/* Copies the next logical line in the current buffer (starting at
+ buffer->cur) to the output buffer. The output is guaranteed to
+ terminate with a NUL character. buffer->cur is updated.
+
+ 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. */
+bool
+_cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro)
+{
+ bool result = true;
+ cpp_context *context;
+ const uchar *cur;
+ uchar *out;
+ struct fun_macro fmacro;
+ unsigned int c, paren_depth = 0, quote;
+ enum ls lex_state = ls_none;
+ bool header_ok;
+ const uchar *start_of_input_line;
+
+ fmacro.buff = NULL;
+
+ quote = 0;
+ header_ok = pfile->state.angled_headers;
+ CUR (pfile->context) = pfile->buffer->cur;
+ RLIMIT (pfile->context) = pfile->buffer->rlimit;
+ pfile->out.cur = pfile->out.base;
+ pfile->out.first_line = pfile->line_table->highest_line;
+ /* start_of_input_line is needed to make sure that directives really,
+ really start at the first character of the line. */
+ start_of_input_line = pfile->buffer->cur;
+ new_context:
+ context = pfile->context;
+ cur = CUR (context);
+ check_output_buffer (pfile, RLIMIT (context) - cur);
+ out = pfile->out.cur;
+
+ 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;
+
+ /* Whitespace should "continue" out of the switch,
+ non-whitespace should "break" out of it. */
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\v':
+ case '\0':
+ continue;
+
+ case '\n':
+ /* If this is a macro's expansion, pop it. */
+ if (context->prev)
+ {
+ pfile->out.cur = out - 1;
+ _cpp_pop_context (pfile);
+ goto new_context;
+ }
+
+ /* Omit the newline from the output buffer. */
+ pfile->out.cur = out - 1;
+ pfile->buffer->cur = cur;
+ pfile->buffer->need_line = true;
+ CPP_INCREMENT_LINE (pfile, 0);
+
+ if ((lex_state == ls_fun_open || lex_state == ls_fun_close)
+ && !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;
+
+ case '<':
+ if (header_ok)
+ quote = '>';
+ break;
+ case '>':
+ if (c == quote)
+ quote = 0;
+ break;
+
+ case '"':
+ case '\'':
+ if (c == quote)
+ quote = 0;
+ else if (!quote)
+ quote = c;
+ break;
+
+ case '\\':
+ /* 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 && *cur == '*')
+ {
+ pfile->out.cur = out;
+ cur = copy_comment (pfile, cur, macro != 0);
+ out = pfile->out.cur;
+ continue;
+ }
+ break;
+
+ 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':
+ case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+ case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+ case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z':
+ if (!pfile->state.skipping && (quote == 0 || macro))
+ {
+ cpp_hashnode *node;
+ uchar *out_start = out - 1;
+
+ pfile->out.cur = out_start;
+ node = lex_identifier (pfile, cur - 1);
+ out = pfile->out.cur;
+ cur = CUR (context);
+
+ if (node->type == NT_MACRO
+ /* Should we expand for ls_answer? */
+ && (lex_state == ls_none || lex_state == ls_fun_open)
+ && !pfile->state.prevent_expansion)
+ {
+ /* Macros invalidate MI optimization. */
+ pfile->mi_valid = false;
+ if (! (node->flags & NODE_BUILTIN)
+ && node->value.macro->fun_like)
+ {
+ maybe_start_funlike (pfile, node, out_start, &fmacro);
+ lex_state = ls_fun_open;
+ fmacro.line = pfile->line_table->highest_line;
+ continue;
+ }
+ else if (!recursive_macro (pfile, node))
+ {
+ /* Remove the object-like macro's name from the
+ output, and push its replacement text. */
+ pfile->out.cur = out_start;
+ push_replacement_text (pfile, node);
+ lex_state = ls_none;
+ goto new_context;
+ }
+ }
+ 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->value.arg_index);
+ out = pfile->out.base;
+ }
+ else if (lex_state == ls_hash)
+ {
+ lex_state = ls_predicate;
+ continue;
+ }
+ else if (pfile->state.in_expression
+ && node == pfile->spec_nodes.n_defined)
+ {
+ lex_state = ls_defined;
+ continue;
+ }
+ }
+ break;
+
+ case '(':
+ if (quote == 0)
+ {
+ paren_depth++;
+ if (lex_state == ls_fun_open)
+ {
+ if (recursive_macro (pfile, fmacro.node))
+ lex_state = ls_none;
+ else
+ {
+ lex_state = ls_fun_close;
+ paren_depth = 1;
+ out = pfile->out.base + fmacro.offset;
+ fmacro.args[0] = fmacro.offset;
+ }
+ }
+ else if (lex_state == ls_predicate)
+ lex_state = ls_answer;
+ else if (lex_state == ls_defined)
+ lex_state = ls_defined_close;
+ }
+ break;
+
+ case ',':
+ if (quote == 0 && lex_state == ls_fun_close && paren_depth == 1)
+ save_argument (&fmacro, out - pfile->out.base);
+ break;
+
+ case ')':
+ if (quote == 0)
+ {
+ paren_depth--;
+ if (lex_state == ls_fun_close && paren_depth == 0)
+ {
+ cpp_macro *m = fmacro.node->value.macro;
+
+ m->used = 1;
+ lex_state = ls_none;
+ save_argument (&fmacro, out - pfile->out.base);
+
+ /* A single zero-length argument is no argument. */
+ if (fmacro.argc == 1
+ && m->paramc == 0
+ && out == pfile->out.base + fmacro.offset + 1)
+ fmacro.argc = 0;
+
+ if (_cpp_arguments_ok (pfile, m, fmacro.node, fmacro.argc))
+ {
+ /* Remove the macro's invocation from the
+ output, and push its replacement text. */
+ pfile->out.cur = (pfile->out.base
+ + fmacro.offset);
+ CUR (context) = cur;
+ replace_args_and_push (pfile, &fmacro);
+ goto new_context;
+ }
+ }
+ else if (lex_state == ls_answer || lex_state == ls_defined_close)
+ lex_state = ls_none;
+ }
+ break;
+
+ case '#':
+ if (cur - 1 == start_of_input_line
+ /* A '#' from a macro doesn't start a directive. */
+ && !pfile->context->prev
+ && !pfile->state.in_directive)
+ {
+ /* A directive. With the way _cpp_handle_directive
+ currently works, we only want to call it if either we
+ know the directive is OK, or we want it to fail and
+ be removed from the output. If we want it to be
+ passed through (the assembler case) then we must not
+ call _cpp_handle_directive. */
+ pfile->out.cur = out;
+ cur = skip_whitespace (pfile, cur, true /* skip_comments */);
+ out = pfile->out.cur;
+
+ if (*cur == '\n')
+ {
+ /* Null directive. Ignore it and don't invalidate
+ the MI optimization. */
+ pfile->buffer->need_line = true;
+ CPP_INCREMENT_LINE (pfile, 0);
+ result = false;
+ goto done;
+ }
+ else
+ {
+ bool do_it = false;
+
+ if (is_numstart (*cur)
+ && CPP_OPTION (pfile, lang) != CLK_ASM)
+ do_it = true;
+ else if (is_idstart (*cur))
+ /* Check whether we know this directive, but don't
+ advance. */
+ do_it = lex_identifier (pfile, cur)->is_directive;
+
+ if (do_it || CPP_OPTION (pfile, lang) != CLK_ASM)
+ {
+ /* This is a kludge. We want to have the ISO
+ preprocessor lex the next token. */
+ pfile->buffer->cur = cur;
+ _cpp_handle_directive (pfile, false /* indented */);
+ result = false;
+ goto done;
+ }
+ }
+ }
+
+ if (pfile->state.in_expression)
+ {
+ lex_state = ls_hash;
+ continue;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Non-whitespace disables MI optimization and stops treating
+ '<' as a quote in #include. */
+ header_ok = false;
+ if (!pfile->state.in_directive)
+ pfile->mi_valid = false;
+
+ if (lex_state == ls_none)
+ continue;
+
+ /* Some of these transitions of state are syntax errors. The
+ ISO preprocessor will issue errors later. */
+ if (lex_state == ls_fun_open)
+ /* Missing '('. */
+ lex_state = ls_none;
+ else if (lex_state == ls_hash
+ || lex_state == ls_predicate
+ || lex_state == ls_defined)
+ lex_state = ls_none;
+
+ /* ls_answer and ls_defined_close keep going until ')'. */
+ }
+
+ done:
+ if (fmacro.buff)
+ _cpp_release_buff (pfile, fmacro.buff);
+
+ if (lex_state == ls_fun_close)
+ 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 (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
+ {
+ cpp_macro *macro = node->value.macro;
+ macro->used = 1;
+ text = macro->exp.text;
+ macro->traditional = 1;
+ len = macro->count;
+ }
+
+ _cpp_push_text_context (pfile, node, text, len);
+}
+
+/* Returns TRUE if traditional macro recursion is detected. */
+static bool
+recursive_macro (cpp_reader *pfile, cpp_hashnode *node)
+{
+ bool recursing = !!(node->flags & NODE_DISABLED);
+
+ /* Object-like macros that are already expanding are necessarily
+ recursive.
+
+ However, it is possible to have traditional function-like macros
+ that are not infinitely recursive but recurse to any given depth.
+ Further, it is easy to construct examples that get ever longer
+ until the point they stop recursing. So there is no easy way to
+ detect true recursion; instead we assume any expansion more than
+ 20 deep since the first invocation of this macro must be
+ recursing. */
+ if (recursing && node->value.macro->fun_like)
+ {
+ size_t depth = 0;
+ cpp_context *context = pfile->context;
+
+ do
+ {
+ depth++;
+ if (context->macro == node && depth > 20)
+ break;
+ context = context->prev;
+ }
+ while (context);
+ recursing = context != NULL;
+ }
+
+ if (recursing)
+ cpp_error (pfile, CPP_DL_ERROR,
+ "detected recursion whilst expanding macro \"%s\"",
+ NODE_NAME (node));
+
+ return recursing;
+}
+
+/* Return the length of the replacement text of a function-like or
+ object-like non-builtin macro. */
+size_t
+_cpp_replacement_text_len (const cpp_macro *macro)
+{
+ size_t len;
+
+ if (macro->fun_like && (macro->paramc != 0))
+ {
+ const uchar *exp;
+
+ len = 0;
+ for (exp = macro->exp.text;;)
+ {
+ struct block *b = (struct block *) exp;
+
+ len += b->text_len;
+ if (b->arg_index == 0)
+ break;
+ len += NODE_LEN (macro->params[b->arg_index - 1]);
+ exp += BLOCK_LEN (b->text_len);
+ }
+ }
+ else
+ len = macro->count;
+
+ return len;
+}
+
+/* Copy the replacement text of MACRO to DEST, which must be of
+ sufficient size. It is not NUL-terminated. The next character is
+ returned. */
+uchar *
+_cpp_copy_replacement_text (const cpp_macro *macro, uchar *dest)
+{
+ if (macro->fun_like && (macro->paramc != 0))
+ {
+ const uchar *exp;
+
+ for (exp = macro->exp.text;;)
+ {
+ struct block *b = (struct block *) exp;
+ cpp_hashnode *param;
+
+ memcpy (dest, b->text, b->text_len);
+ dest += b->text_len;
+ if (b->arg_index == 0)
+ break;
+ param = macro->params[b->arg_index - 1];
+ memcpy (dest, NODE_NAME (param), NODE_LEN (param));
+ dest += NODE_LEN (param);
+ exp += BLOCK_LEN (b->text_len);
+ }
+ }
+ else
+ {
+ memcpy (dest, macro->exp.text, macro->count);
+ dest += macro->count;
+ }
+
+ return dest;
+}
+
+/* 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
+replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
+{
+ cpp_macro *macro = fmacro->node->value.macro;
+
+ if (macro->paramc == 0)
+ push_replacement_text (pfile, fmacro->node);
+ else
+ {
+ const uchar *exp;
+ uchar *p;
+ _cpp_buff *buff;
+ size_t len = 0;
+
+ /* Calculate the length of the argument-replaced text. */
+ for (exp = macro->exp.text;;)
+ {
+ struct block *b = (struct block *) exp;
+
+ len += b->text_len;
+ if (b->arg_index == 0)
+ break;
+ len += (fmacro->args[b->arg_index]
+ - fmacro->args[b->arg_index - 1] - 1);
+ exp += BLOCK_LEN (b->text_len);
+ }
+
+ /* Allocate room for the expansion plus \n. */
+ buff = _cpp_get_buff (pfile, len + 1);
+
+ /* Copy the expansion and replace arguments. */
+ p = BUFF_FRONT (buff);
+ for (exp = macro->exp.text;;)
+ {
+ struct block *b = (struct block *) exp;
+ size_t arglen;
+
+ memcpy (p, b->text, b->text_len);
+ p += b->text_len;
+ if (b->arg_index == 0)
+ break;
+ arglen = (fmacro->args[b->arg_index]
+ - fmacro->args[b->arg_index - 1] - 1);
+ memcpy (p, pfile->out.base + fmacro->args[b->arg_index - 1],
+ arglen);
+ p += arglen;
+ exp += BLOCK_LEN (b->text_len);
+ }
+
+ /* \n-terminate. */
+ *p = '\n';
+ _cpp_push_text_context (pfile, fmacro->node, BUFF_FRONT (buff), len);
+
+ /* So we free buffer allocation when macro is left. */
+ pfile->context->buff = buff;
+ }
+}
+
+/* Read and record the parameters, if any, of a function-like macro
+ definition. Destroys pfile->out.cur.
+
+ Returns true on success, false on failure (syntax error or a
+ duplicate parameter). On success, CUR (pfile->context) is just
+ past the closing parenthesis. */
+static bool
+scan_parameters (cpp_reader *pfile, cpp_macro *macro)
+{
+ const uchar *cur = CUR (pfile->context) + 1;
+ bool ok;
+
+ for (;;)
+ {
+ cur = skip_whitespace (pfile, cur, true /* skip_comments */);
+
+ if (is_idstart (*cur))
+ {
+ ok = false;
+ if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur)))
+ break;
+ cur = skip_whitespace (pfile, CUR (pfile->context),
+ true /* skip_comments */);
+ if (*cur == ',')
+ {
+ cur++;
+ continue;
+ }
+ ok = (*cur == ')');
+ break;
+ }
+
+ ok = (*cur == ')' && macro->paramc == 0);
+ break;
+ }
+
+ if (!ok)
+ cpp_error (pfile, CPP_DL_ERROR, "syntax error in macro parameter list");
+
+ CUR (pfile->context) = cur + (*cur == ')');
+
+ return ok;
+}
+
+/* Save the text from pfile->out.base to pfile->out.cur as
+ the replacement text for the current macro, followed by argument
+ ARG_INDEX, with zero indicating the end of the replacement
+ text. */
+static void
+save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
+ unsigned int arg_index)
+{
+ size_t len = pfile->out.cur - pfile->out.base;
+ uchar *exp;
+
+ if (macro->paramc == 0)
+ {
+ /* Object-like and function-like macros without parameters
+ simply store their \n-terminated replacement text. */
+ exp = _cpp_unaligned_alloc (pfile, len + 1);
+ memcpy (exp, pfile->out.base, len);
+ exp[len] = '\n';
+ macro->exp.text = exp;
+ macro->traditional = 1;
+ macro->count = len;
+ }
+ else
+ {
+ /* Store the text's length (unsigned int), the argument index
+ (unsigned short, base 1) and then the text. */
+ size_t blen = BLOCK_LEN (len);
+ struct block *block;
+
+ if (macro->count + blen > BUFF_ROOM (pfile->a_buff))
+ _cpp_extend_buff (pfile, &pfile->a_buff, macro->count + blen);
+
+ exp = BUFF_FRONT (pfile->a_buff);
+ block = (struct block *) (exp + macro->count);
+ macro->exp.text = exp;
+ macro->traditional = 1;
+
+ /* Write out the block information. */
+ block->text_len = len;
+ block->arg_index = arg_index;
+ memcpy (block->text, pfile->out.base, len);
+
+ /* Lex the rest into the start of the output buffer. */
+ pfile->out.cur = pfile->out.base;
+
+ macro->count += blen;
+
+ /* If we've finished, commit the memory. */
+ if (arg_index == 0)
+ BUFF_FRONT (pfile->a_buff) += macro->count;
+ }
+}
+
+/* Analyze and save the replacement text of a macro. Returns true on
+ success. */
+bool
+_cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro)
+{
+ const uchar *cur;
+ uchar *limit;
+ cpp_context *context = pfile->context;
+
+ /* The context has not been set up for command line defines, and CUR
+ has not been updated for the macro name for in-file defines. */
+ pfile->out.cur = pfile->out.base;
+ CUR (context) = pfile->buffer->cur;
+ RLIMIT (context) = pfile->buffer->rlimit;
+ check_output_buffer (pfile, RLIMIT (context) - CUR (context));
+
+ /* 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 _cpp_scan_out_logical_line. */
+ if (!ok)
+ macro = NULL;
+ else
+ {
+ BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc];
+ macro->fun_like = 1;
+ }
+ }
+
+ /* Skip leading whitespace in the replacement text. */
+ pfile->buffer->cur
+ = skip_whitespace (pfile, CUR (context),
+ CPP_OPTION (pfile, discard_comments_in_macro_exp));
+
+ pfile->state.prevent_expansion++;
+ _cpp_scan_out_logical_line (pfile, macro);
+ pfile->state.prevent_expansion--;
+
+ if (!macro)
+ return false;
+
+ /* Skip trailing white space. */
+ cur = pfile->out.base;
+ limit = pfile->out.cur;
+ while (limit > cur && is_space (limit[-1]))
+ limit--;
+ pfile->out.cur = limit;
+ save_replacement_text (pfile, macro, 0);
+
+ return true;
+}
+
+/* Copy SRC of length LEN to DEST, but convert all contiguous
+ whitespace to a single space, provided it is not in quotes. The
+ 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 (uchar *dest, const uchar *src, size_t len, uchar *pquote)
+{
+ uchar *orig_dest = dest;
+ uchar quote = *pquote;
+
+ while (len)
+ {
+ if (is_space (*src) && !quote)
+ {
+ do
+ src++, len--;
+ while (len && is_space (*src));
+ *dest++ = ' ';
+ }
+ else
+ {
+ if (*src == '\'' || *src == '"')
+ {
+ if (!quote)
+ quote = *src;
+ else if (quote == *src)
+ quote = 0;
+ }
+ *dest++ = *src++, len--;
+ }
+ }
+
+ *pquote = quote;
+ return dest - orig_dest;
+}
+
+/* Returns true if MACRO1 and MACRO2 have expansions different other
+ than in the form of their whitespace. */
+bool
+_cpp_expansions_different_trad (const cpp_macro *macro1,
+ const cpp_macro *macro2)
+{
+ uchar *p1 = XNEWVEC (uchar, macro1->count + macro2->count);
+ uchar *p2 = p1 + macro1->count;
+ uchar quote1 = 0, quote2 = 0;
+ bool mismatch;
+ size_t len1, len2;
+
+ if (macro1->paramc > 0)
+ {
+ const uchar *exp1 = macro1->exp.text, *exp2 = macro2->exp.text;
+
+ mismatch = true;
+ for (;;)
+ {
+ struct block *b1 = (struct block *) exp1;
+ struct block *b2 = (struct block *) exp2;
+
+ if (b1->arg_index != b2->arg_index)
+ break;
+
+ len1 = canonicalize_text (p1, b1->text, b1->text_len, "e1);
+ len2 = canonicalize_text (p2, b2->text, b2->text_len, "e2);
+ if (len1 != len2 || memcmp (p1, p2, len1))
+ break;
+ if (b1->arg_index == 0)
+ {
+ mismatch = false;
+ break;
+ }
+ exp1 += BLOCK_LEN (b1->text_len);
+ exp2 += BLOCK_LEN (b2->text_len);
+ }
+ }
+ else
+ {
+ len1 = canonicalize_text (p1, macro1->exp.text, macro1->count, "e1);
+ len2 = canonicalize_text (p2, macro2->exp.text, macro2->count, "e2);
+ mismatch = (len1 != len2 || memcmp (p1, p2, len1));
+ }
+
+ free (p1);
+ return mismatch;
+}
--- /dev/null
+/* Unicode characters and various properties.
+ Copyright (C) 2003, 2005 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+ Copyright (C) 1991-2005 Unicode, Inc. All rights reserved.
+ Distributed under the Terms of Use in
+ http://www.unicode.org/copyright.html.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of the Unicode data files and any associated
+ documentation (the "Data Files") or Unicode software and any
+ associated documentation (the "Software") to deal in the Data Files
+ or Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, and/or
+ sell copies of the Data Files or Software, and to permit persons to
+ whom the Data Files or Software are furnished to do so, provided
+ that (a) the above copyright notice(s) and this permission notice
+ appear with all copies of the Data Files or Software, (b) both the
+ above copyright notice(s) and this permission notice appear in
+ associated documentation, and (c) there is clear notice in each
+ modified Data File or in the Software as well as in the
+ documentation associated with the Data File(s) or Software that the
+ data or software has been modified.
+
+ THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY
+ OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
+ COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
+ ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ OF THE DATA FILES OR SOFTWARE.
+
+ Except as contained in this notice, the name of a copyright holder
+ shall not be used in advertising or otherwise to promote the sale,
+ use or other dealings in these Data Files or Software without prior
+ written authorization of the copyright holder. */
+
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00a9 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x00aa },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00b4 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x00b5 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00b6 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x00b7 },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x00b9 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x00ba },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00bf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x00d6 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00d7 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x00f6 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x00f7 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0131 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0133 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x013e },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0140 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0148 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0149 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x017e },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x017f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x01c3 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x01cc },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x01f0 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x01f3 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x01f5 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x01f9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0217 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x024f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x02a8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02af },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x02b8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02ba },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x02bb },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02bc },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x02c1 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02cf },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x02d1 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x02df },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x02e4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0379 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x037a },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0383 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0x0384 },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x0385 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0386 },
+{ 0| 0| 0|CID| 0| 0| 0, 0, 0x0387 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x038a },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x038b },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x038c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x038d },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03a1 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03a2 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03ce },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03cf },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x03d6 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03d9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03da },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03db },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03dc },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03dd },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03de },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03df },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03e0 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x03e1 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03ef },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x03f2 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x03f3 },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x0400 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x040c },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x040d },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x040e },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x044f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0450 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x045c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x045d },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0481 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x048f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04c4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04c6 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04c8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04ca },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04cc },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04cf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04eb },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04ed },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04f5 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x04f7 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x04f9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0530 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0556 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0558 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0559 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0560 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0586 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0587 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05af },
+{ C99| 0| 0|CID|NFC|NKC| 0, 10, 0x05b0 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 11, 0x05b1 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 12, 0x05b2 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 13, 0x05b3 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 14, 0x05b4 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 15, 0x05b5 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 16, 0x05b6 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 17, 0x05b7 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 18, 0x05b8 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 19, 0x05b9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05ba },
+{ C99| 0| 0|CID|NFC|NKC| 0, 20, 0x05bb },
+{ C99| 0| 0|CID|NFC|NKC| 0, 21, 0x05bc },
+{ C99| 0| 0|CID|NFC|NKC| 0, 22, 0x05bd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05be },
+{ C99| 0| 0|CID|NFC|NKC| 0, 23, 0x05bf },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05c0 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 24, 0x05c1 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 25, 0x05c2 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05cf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x05ea },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x05ef },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x05f2 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x05f4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0620 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x063a },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x063f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x064a },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 27, 0x064b },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 28, 0x064c },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 29, 0x064d },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 30, 0x064e },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 31, 0x064f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 32, 0x0650 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 33, 0x0651 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 34, 0x0652 },
+{ 0| 0| 0|CID|NFC|NKC|CTX, 0, 0x065f },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0669 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x066f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0674 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0678 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x06b7 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06b9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x06be },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06bf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x06ce },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06cf },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x06d5 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06d6 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06d7 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06d8 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06d9 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06da },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06db },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06dc },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06e4 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x06e6 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 230, 0x06e7 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06e8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06e9 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x06ea },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06eb },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x06ec },
+{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x06ed },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x06ef },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x06f9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0900 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0903 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0904 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0939 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x093c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x094c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x094d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x094f },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0950 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x0951 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0952 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0957 },
+{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x095f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0962 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0963 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0965 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x096f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0980 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0983 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0984 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x098c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x098e },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0990 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0992 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09a8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09a9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09b0 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09b1 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09b2 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09b5 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09b9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09bd },
+{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x09be },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x09c4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09c6 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x09c8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09ca },
+{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x09cb },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x09cc },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x09cd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09db },
+{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x09dd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09de },
+{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x09df },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09e1 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x09e3 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x09e5 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x09ef },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x09f1 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a01 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a02 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a04 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a0a },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a0e },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a10 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a12 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a28 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a29 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a30 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a31 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a32 },
+{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0a33 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a34 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a35 },
+{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0a36 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a37 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a39 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a3d },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a42 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a46 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a48 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a4a },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a4c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0a4d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a58 },
+{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0a5b },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a5c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a5d },
+{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0a5e },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a65 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0a6f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a73 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a74 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a80 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0a83 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a84 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a8b },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a8c },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a8d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a8e },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0a91 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0a92 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0aa8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0aa9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ab0 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ab1 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ab3 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ab4 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ab9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0abc },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ac5 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ac6 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ac9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0aca },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0acc },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0acd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0acf },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ad0 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0adf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ae0 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ae5 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0aef },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b00 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b03 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b04 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b0c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b0e },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b10 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b12 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b28 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b29 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b30 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b31 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b33 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b35 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b39 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b3c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b3d },
+{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x0b3e },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b43 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b46 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b48 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b4a },
+{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x0b4b },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b4c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0b4d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b5b },
+{ C99| 0|CXX|CID| 0| 0| 0, 0, 0x0b5d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b5e },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b61 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b65 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0b6f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b81 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0b83 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b84 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b8a },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b8d },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b90 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b91 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b95 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b98 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b9a },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b9b },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b9c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0b9d },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0b9f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ba2 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ba4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ba7 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0baa },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bad },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0bb5 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bb6 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0bb9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bbd },
+{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x0bbe },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0bc2 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bc5 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0bc8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0bc9 },
+{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x0bcb },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0bcc },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0bcd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0be6 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0bef },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c00 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c03 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c04 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c0c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c0d },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c10 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c11 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c28 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c29 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c33 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c34 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c39 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c3d },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c44 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c45 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c48 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c49 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c4c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0c4d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c5f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c61 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c65 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0c6f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c81 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0c83 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c84 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c8c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c8d },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0c90 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0c91 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ca8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ca9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0cb3 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cb4 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0cb9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cbd },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc1 },
+{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x0cc2 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc5 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc8 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cc9 },
+{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x0cca },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ccc },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0ccd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cdd },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0cde },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0cdf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ce1 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ce5 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0cef },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d01 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0d03 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d04 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d0c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d0d },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d10 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d11 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d28 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d29 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d39 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d3d },
+{ C99| 0| 0|CID|NFC|NKC|CTX, 0, 0x0d3e },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0d43 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d45 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0d48 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d49 },
+{ C99| 0| 0| 0|NFC|NKC| 0, 0, 0x0d4b },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0d4c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0d4d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d5f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0d61 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0d65 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0d6f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e00 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e30 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0e31 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e32 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0e33 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0e37 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 103, 0x0e38 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 103, 0x0e39 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0e3a },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e3f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e46 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0e47 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 107, 0x0e48 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 107, 0x0e49 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e4e },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e4f },
+{ C99|DIG|CXX|CID|NFC|NKC| 0, 0, 0x0e59 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e5b },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e80 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e82 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e83 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e84 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e86 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e88 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e89 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e8a },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e8c },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e8d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e93 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e97 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0e98 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0e9f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ea0 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ea3 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ea4 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ea5 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ea6 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ea7 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ea9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eab },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0eac },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eae },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eaf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eb0 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0eb1 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0eb2 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x0eb3 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0eb7 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 118, 0x0eb8 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 118, 0x0eb9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0eba },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ebc },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ebd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ebf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ec4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ec5 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x0ec6 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ec7 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 122, 0x0ec8 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 122, 0x0ec9 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 122, 0x0eca },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0ecd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0ecf },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0ed9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0edb },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x0edd },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0eff },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f00 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f17 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0f18 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0f19 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f1f },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x0f33 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f34 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0f35 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f36 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 220, 0x0f37 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f38 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 216, 0x0f39 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f3d },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f42 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f43 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f47 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f48 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f4c },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f4d },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f51 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f52 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f56 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f57 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f5b },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f5c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f68 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f69 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f70 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 129, 0x0f71 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f72 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f73 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 132, 0x0f74 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f76 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x0f77 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f78 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x0f79 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f7a },
+{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f7b },
+{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f7c },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f7f },
+{ C99| 0| 0|CID|NFC|NKC| 0, 130, 0x0f80 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f81 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x0f82 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x0f83 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 9, 0x0f84 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f85 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 230, 0x0f86 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f8b },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f8f },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f92 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f93 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f95 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f96 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f97 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0f98 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0f9c },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0f9d },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fa1 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0fa2 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fa6 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0fa7 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fab },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0fac },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fad },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0fb0 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x0fb7 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x0fb8 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x0fb9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x109f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x10c5 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x10cf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x10f6 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x10ff },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x1159 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1160 },
+{ 0| 0|CXX|CID|NFC|NKC|CTX, 0, 0x1175 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x11a2 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x11a7 },
+{ 0| 0|CXX|CID|NFC|NKC|CTX, 0, 0x11c2 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x11f9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1dff },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1e99 },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x1e9a },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x1e9b },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1e9f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ef9 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1eff },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f15 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f17 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f1d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f1f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f45 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f47 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f4d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f4f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f57 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f58 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f59 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f5a },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f5b },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f5c },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f5d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f5e },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f70 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f71 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f72 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f73 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f74 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f75 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f76 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f77 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f78 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f79 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f7a },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f7b },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1f7c },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1f7d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1f7f },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fb4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1fb5 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fba },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fbb },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fbc },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x1fbd },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x1fbe },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x1fc1 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fc4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1fc5 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fc8 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fc9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fca },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fcb },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fcc },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x1fcf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fd2 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fd3 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1fd5 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fda },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fdb },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1fdf },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fe2 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1fe3 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fea },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1feb },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1fec },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x1ff1 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ff4 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x1ff5 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ff8 },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1ff9 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ffa },
+{ C99| 0|CXX| 0| 0| 0| 0, 0, 0x1ffb },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x1ffc },
+{ 0| 0| 0|CID| 0| 0| 0, 0, 0x203e },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x2040 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x207e },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x207f },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x2101 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2102 },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x2106 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2107 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2109 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2113 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2114 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2115 },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x2117 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x2118 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x211d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2123 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2124 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2125 },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x2126 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2127 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2128 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2129 },
+{ C99| 0| 0|CID| 0| 0| 0, 0, 0x212a },
+{ C99| 0| 0| 0| 0| 0| 0, 0, 0x212b },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x212d },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x212e },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2131 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x2132 },
+{ C99| 0| 0|CID|NFC| 0| 0, 0, 0x2138 },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x215f },
+{ C99|DIG| 0|CID|NFC| 0| 0, 0, 0x217f },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x2182 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x3004 },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0x3006 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x3007 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x3020 },
+{ C99|DIG| 0|CID|NFC|NKC| 0, 0, 0x3029 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x3040 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x3093 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x3094 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x309a },
+{ C99| 0|CXX|CID|NFC| 0| 0, 0, 0x309c },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x309e },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x30a0 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x30f6 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x30fa },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x30fc },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0x30fe },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0x3104 },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x312c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0x4dff },
+{ C99| 0|CXX|CID|NFC|NKC| 0, 0, 0x9fa5 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xabff },
+{ C99| 0| 0|CID|NFC|NKC| 0, 0, 0xd7a3 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xf8ff },
+{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa0d },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa0f },
+{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa10 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa11 },
+{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa12 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa14 },
+{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa1e },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa1f },
+{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa20 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa21 },
+{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa22 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa24 },
+{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa26 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfa29 },
+{ 0| 0|CXX| 0| 0| 0| 0, 0, 0xfa2d },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb1e },
+{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb1f },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfb29 },
+{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb36 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb37 },
+{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb3c },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb3d },
+{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb3e },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb3f },
+{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb41 },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfb42 },
+{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb44 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfb45 },
+{ 0| 0|CXX|CID| 0| 0| 0, 0, 0xfb4e },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfbb1 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfbd2 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfd3d },
+{ 0| 0|CXX|CID|NFC|NKC| 0, 0, 0xfd3f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfd4f },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfd8f },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfd91 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfdc7 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfdef },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfdfb },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0xfe6f },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfe72 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfe73 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfe74 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xfe75 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xfefc },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xff20 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xff3a },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0xff40 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xff5a },
+{ 0| 0| 0|CID|NFC| 0| 0, 0, 0xff65 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffbe },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffc1 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffc7 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffc9 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffcf },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffd1 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffd7 },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffd9 },
+{ 0| 0|CXX|CID|NFC| 0| 0, 0, 0xffdc },
+{ 0| 0| 0|CID|NFC|NKC| 0, 0, 0xffff },
--- /dev/null
+/* Implement fopen_unlocked and related functions.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>.
+
+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. */
+
+/*
+
+@deftypefn Extension void unlock_stream (FILE * @var{stream})
+
+If the OS supports it, ensure that the supplied stream is setup to
+avoid any multi-threaded locking. Otherwise leave the @code{FILE}
+pointer unchanged. If the @var{stream} is @code{NULL} do nothing.
+
+@end deftypefn
+
+@deftypefn Extension void unlock_std_streams (void)
+
+If the OS supports it, ensure that the standard I/O streams,
+@code{stdin}, @code{stdout} and @code{stderr} are setup to avoid any
+multi-threaded locking. Otherwise do nothing.
+
+@end deftypefn
+
+@deftypefn Extension {FILE *} fopen_unlocked (const char *@var{path}, const char * @var{mode})
+
+Opens and returns a @code{FILE} pointer via @code{fopen}. If the
+operating system supports it, ensure that the stream is setup to avoid
+any multi-threaded locking. Otherwise return the @code{FILE} pointer
+unchanged.
+
+@end deftypefn
+
+@deftypefn Extension {FILE *} fdopen_unlocked (int @var{fildes}, const char * @var{mode})
+
+Opens and returns a @code{FILE} pointer via @code{fdopen}. If the
+operating system supports it, ensure that the stream is setup to avoid
+any multi-threaded locking. Otherwise return the @code{FILE} pointer
+unchanged.
+
+@end deftypefn
+
+@deftypefn Extension {FILE *} freopen_unlocked (const char * @var{path}, const char * @var{mode}, FILE * @var{stream})
+
+Opens and returns a @code{FILE} pointer via @code{freopen}. If the
+operating system supports it, ensure that the stream is setup to avoid
+any multi-threaded locking. Otherwise return the @code{FILE} pointer
+unchanged.
+
+@end deftypefn
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDIO_EXT_H
+#include <stdio_ext.h>
+#endif
+
+#include "libiberty.h"
+
+/* This is an inline helper function to consolidate attempts to unlock
+ a stream. */
+
+static inline void
+unlock_1 (FILE *const fp ATTRIBUTE_UNUSED)
+{
+#if defined(HAVE___FSETLOCKING) && defined(FSETLOCKING_BYCALLER)
+ if (fp)
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+#endif
+}
+
+void
+unlock_stream (FILE *fp)
+{
+ unlock_1 (fp);
+}
+
+void
+unlock_std_streams (void)
+{
+ unlock_1 (stdin);
+ unlock_1 (stdout);
+ unlock_1 (stderr);
+}
+
+FILE *
+fopen_unlocked (const char *path, const char *mode)
+{
+ FILE *const fp = fopen (path, mode);
+ unlock_1 (fp);
+ return fp;
+}
+
+FILE *
+fdopen_unlocked (int fildes, const char *mode)
+{
+ FILE *const fp = fdopen (fildes, mode);
+ unlock_1 (fp);
+ return fp;
+}
+
+FILE *
+freopen_unlocked (const char *path, const char *mode, FILE *stream)
+{
+ FILE *const fp = freopen (path, mode, stream);
+ unlock_1 (fp);
+ return fp;
+}
--- /dev/null
+/* An expandable hash tables datatype.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+ 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., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, 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
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include <stdio.h>
+
+#include "libiberty.h"
+#include "ansidecl.h"
+#include "hashtab.h"
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+static unsigned int higher_prime_index (unsigned long);
+static hashval_t htab_mod_1 (hashval_t, hashval_t, hashval_t, int);
+static hashval_t htab_mod (hashval_t, htab_t);
+static hashval_t htab_mod_m2 (hashval_t, htab_t);
+static hashval_t hash_pointer (const void *);
+static int eq_pointer (const void *, const void *);
+static int htab_expand (htab_t);
+static PTR *find_empty_slot_for_expand (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;
+
+/* Table of primes and multiplicative inverses.
+
+ Note that these are not minimally reduced inverses. Unlike when generating
+ code to divide by a constant, we want to be able to use the same algorithm
+ all the time. All of these inverses (are implied to) have bit 32 set.
+
+ For the record, here's the function that computed the table; it's a
+ vastly simplified version of the function of the same name from gcc. */
+
+#if 0
+unsigned int
+ceil_log2 (unsigned int x)
+{
+ int i;
+ for (i = 31; i >= 0 ; --i)
+ if (x > (1u << i))
+ return i+1;
+ abort ();
+}
+
+unsigned int
+choose_multiplier (unsigned int d, unsigned int *mlp, unsigned char *shiftp)
+{
+ unsigned long long mhigh;
+ double nx;
+ int lgup, post_shift;
+ int pow, pow2;
+ int n = 32, precision = 32;
+
+ lgup = ceil_log2 (d);
+ pow = n + lgup;
+ pow2 = n + lgup - precision;
+
+ nx = ldexp (1.0, pow) + ldexp (1.0, pow2);
+ mhigh = nx / d;
+
+ *shiftp = lgup - 1;
+ *mlp = mhigh;
+ return mhigh >> 32;
+}
+#endif
+
+struct prime_ent
+{
+ hashval_t prime;
+ hashval_t inv;
+ hashval_t inv_m2; /* inverse of prime-2 */
+ hashval_t shift;
+};
+
+static struct prime_ent const prime_tab[] = {
+ { 7, 0x24924925, 0x9999999b, 2 },
+ { 13, 0x3b13b13c, 0x745d1747, 3 },
+ { 31, 0x08421085, 0x1a7b9612, 4 },
+ { 61, 0x0c9714fc, 0x15b1e5f8, 5 },
+ { 127, 0x02040811, 0x0624dd30, 6 },
+ { 251, 0x05197f7e, 0x073260a5, 7 },
+ { 509, 0x01824366, 0x02864fc8, 8 },
+ { 1021, 0x00c0906d, 0x014191f7, 9 },
+ { 2039, 0x0121456f, 0x0161e69e, 10 },
+ { 4093, 0x00300902, 0x00501908, 11 },
+ { 8191, 0x00080041, 0x00180241, 12 },
+ { 16381, 0x000c0091, 0x00140191, 13 },
+ { 32749, 0x002605a5, 0x002a06e6, 14 },
+ { 65521, 0x000f00e2, 0x00110122, 15 },
+ { 131071, 0x00008001, 0x00018003, 16 },
+ { 262139, 0x00014002, 0x0001c004, 17 },
+ { 524287, 0x00002001, 0x00006001, 18 },
+ { 1048573, 0x00003001, 0x00005001, 19 },
+ { 2097143, 0x00004801, 0x00005801, 20 },
+ { 4194301, 0x00000c01, 0x00001401, 21 },
+ { 8388593, 0x00001e01, 0x00002201, 22 },
+ { 16777213, 0x00000301, 0x00000501, 23 },
+ { 33554393, 0x00001381, 0x00001481, 24 },
+ { 67108859, 0x00000141, 0x000001c1, 25 },
+ { 134217689, 0x000004e1, 0x00000521, 26 },
+ { 268435399, 0x00000391, 0x000003b1, 27 },
+ { 536870909, 0x00000019, 0x00000029, 28 },
+ { 1073741789, 0x0000008d, 0x00000095, 29 },
+ { 2147483647, 0x00000003, 0x00000007, 30 },
+ /* Avoid "decimal constant so large it is unsigned" for 4294967291. */
+ { 0xfffffffb, 0x00000006, 0x00000008, 31 }
+};
+
+/* The following function returns an index into the above table of the
+ nearest prime number which is greater than N, and near a power of two. */
+
+static unsigned int
+higher_prime_index (unsigned long n)
+{
+ unsigned int low = 0;
+ unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]);
+
+ while (low != high)
+ {
+ unsigned int mid = low + (high - low) / 2;
+ if (n > prime_tab[mid].prime)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+ /* If we've run out of primes, abort. */
+ if (n > prime_tab[low].prime)
+ {
+ fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+ abort ();
+ }
+
+ return low;
+}
+
+/* Returns a hash code for P. */
+
+static hashval_t
+hash_pointer (const PTR p)
+{
+ return (hashval_t) ((long)p >> 3);
+}
+
+/* Returns non-zero if P1 and P2 are equal. */
+
+static int
+eq_pointer (const PTR p1, const PTR p2)
+{
+ return p1 == p2;
+}
+
+
+/* The parens around the function names in the next two definitions
+ are essential in order to prevent macro expansions of the name.
+ The bodies, however, are expanded as expected, so they are not
+ recursive definitions. */
+
+/* Return the current size of given hash table. */
+
+#define htab_size(htab) ((htab)->size)
+
+size_t
+(htab_size) (htab_t htab)
+{
+ return htab_size (htab);
+}
+
+/* Return the current number of elements in given hash table. */
+
+#define htab_elements(htab) ((htab)->n_elements - (htab)->n_deleted)
+
+size_t
+(htab_elements) (htab_t htab)
+{
+ return htab_elements (htab);
+}
+
+/* Return X % Y. */
+
+static inline hashval_t
+htab_mod_1 (hashval_t x, hashval_t y, hashval_t inv, int shift)
+{
+ /* The multiplicative inverses computed above are for 32-bit types, and
+ requires that we be able to compute a highpart multiply. */
+#ifdef UNSIGNED_64BIT_TYPE
+ __extension__ typedef UNSIGNED_64BIT_TYPE ull;
+ if (sizeof (hashval_t) * CHAR_BIT <= 32)
+ {
+ hashval_t t1, t2, t3, t4, q, r;
+
+ t1 = ((ull)x * inv) >> 32;
+ t2 = x - t1;
+ t3 = t2 >> 1;
+ t4 = t1 + t3;
+ q = t4 >> shift;
+ r = x - (q * y);
+
+ return r;
+ }
+#endif
+
+ /* Otherwise just use the native division routines. */
+ return x % y;
+}
+
+/* Compute the primary hash for HASH given HTAB's current size. */
+
+static inline hashval_t
+htab_mod (hashval_t hash, htab_t htab)
+{
+ const struct prime_ent *p = &prime_tab[htab->size_prime_index];
+ return htab_mod_1 (hash, p->prime, p->inv, p->shift);
+}
+
+/* Compute the secondary hash for HASH given HTAB's current size. */
+
+static inline hashval_t
+htab_mod_m2 (hashval_t hash, htab_t htab)
+{
+ const struct prime_ent *p = &prime_tab[htab->size_prime_index];
+ return 1 + htab_mod_1 (hash, p->prime - 2, p->inv_m2, p->shift);
+}
+
+/* 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 HTAB_EMPTY_ENTRY). The function returns the
+ created hash table, or NULL if memory allocation fails. */
+
+htab_t
+htab_create_alloc (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;
+ unsigned int size_prime_index;
+
+ size_prime_index = higher_prime_index (size);
+ size = prime_tab[size_prime_index].prime;
+
+ 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->size_prime_index = size_prime_index;
+ 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_t size, htab_hash hash_f, htab_eq eq_f,
+ htab_del del_f, void *alloc_arg,
+ htab_alloc_with_arg alloc_f,
+ htab_free_with_arg free_f)
+{
+ htab_t result;
+ unsigned int size_prime_index;
+
+ size_prime_index = higher_prime_index (size);
+ size = prime_tab[size_prime_index].prime;
+
+ 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->size_prime_index = size_prime_index;
+ 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_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_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_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_t htab)
+{
+ size_t size = htab_size (htab);
+ PTR *entries = htab->entries;
+ int i;
+
+ if (htab->del_f)
+ for (i = size - 1; i >= 0; i--)
+ if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
+ (*htab->del_f) (entries[i]);
+
+ if (htab->free_f != NULL)
+ {
+ (*htab->free_f) (entries);
+ (*htab->free_f) (htab);
+ }
+ else if (htab->free_with_arg_f != NULL)
+ {
+ (*htab->free_with_arg_f) (htab->alloc_arg, entries);
+ (*htab->free_with_arg_f) (htab->alloc_arg, htab);
+ }
+}
+
+/* This function clears all entries in the given hash table. */
+
+void
+htab_empty (htab_t htab)
+{
+ size_t size = htab_size (htab);
+ PTR *entries = htab->entries;
+ int i;
+
+ if (htab->del_f)
+ for (i = size - 1; i >= 0; i--)
+ if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY)
+ (*htab->del_f) (entries[i]);
+
+ memset (entries, 0, 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_t htab, hashval_t hash)
+{
+ hashval_t index = htab_mod (hash, htab);
+ size_t size = htab_size (htab);
+ PTR *slot = htab->entries + index;
+ hashval_t hash2;
+
+ if (*slot == HTAB_EMPTY_ENTRY)
+ return slot;
+ else if (*slot == HTAB_DELETED_ENTRY)
+ abort ();
+
+ hash2 = htab_mod_m2 (hash, htab);
+ for (;;)
+ {
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ slot = htab->entries + index;
+ if (*slot == HTAB_EMPTY_ENTRY)
+ return slot;
+ else if (*slot == HTAB_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_t htab)
+{
+ PTR *oentries;
+ PTR *olimit;
+ PTR *p;
+ PTR *nentries;
+ size_t nsize, osize, elts;
+ unsigned int oindex, nindex;
+
+ oentries = htab->entries;
+ oindex = htab->size_prime_index;
+ osize = htab->size;
+ olimit = oentries + osize;
+ elts = htab_elements (htab);
+
+ /* Resize only when table after removal of unused elements is either
+ too full or too empty. */
+ if (elts * 2 > osize || (elts * 8 < osize && osize > 32))
+ {
+ nindex = higher_prime_index (elts * 2);
+ nsize = prime_tab[nindex].prime;
+ }
+ else
+ {
+ nindex = oindex;
+ nsize = osize;
+ }
+
+ 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->size_prime_index = nindex;
+ htab->n_elements -= htab->n_deleted;
+ htab->n_deleted = 0;
+
+ p = oentries;
+ do
+ {
+ PTR x = *p;
+
+ if (x != HTAB_EMPTY_ENTRY && x != HTAB_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_t htab, const PTR element, hashval_t hash)
+{
+ hashval_t index, hash2;
+ size_t size;
+ PTR entry;
+
+ htab->searches++;
+ size = htab_size (htab);
+ index = htab_mod (hash, htab);
+
+ entry = htab->entries[index];
+ if (entry == HTAB_EMPTY_ENTRY
+ || (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+ return entry;
+
+ hash2 = htab_mod_m2 (hash, htab);
+ for (;;)
+ {
+ htab->collisions++;
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ entry = htab->entries[index];
+ if (entry == HTAB_EMPTY_ENTRY
+ || (entry != HTAB_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_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=NO_INSERT, then call htab_clear_slot on the slot returned
+ (possibly after doing some checks). To insert an entry, call this
+ with insert=INSERT, 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_t htab, const PTR element,
+ hashval_t hash, enum insert_option insert)
+{
+ PTR *first_deleted_slot;
+ hashval_t index, hash2;
+ size_t size;
+ PTR entry;
+
+ size = htab_size (htab);
+ if (insert == INSERT && size * 3 <= htab->n_elements * 4)
+ {
+ if (htab_expand (htab) == 0)
+ return NULL;
+ size = htab_size (htab);
+ }
+
+ index = htab_mod (hash, htab);
+
+ htab->searches++;
+ first_deleted_slot = NULL;
+
+ entry = htab->entries[index];
+ if (entry == HTAB_EMPTY_ENTRY)
+ goto empty_entry;
+ else if (entry == HTAB_DELETED_ENTRY)
+ first_deleted_slot = &htab->entries[index];
+ else if ((*htab->eq_f) (entry, element))
+ return &htab->entries[index];
+
+ hash2 = htab_mod_m2 (hash, htab);
+ for (;;)
+ {
+ htab->collisions++;
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ entry = htab->entries[index];
+ if (entry == HTAB_EMPTY_ENTRY)
+ goto empty_entry;
+ else if (entry == HTAB_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 = HTAB_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_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 (the hash is computed from the element). If there is no matching
+ element in the hash table, this function does nothing. */
+
+void
+htab_remove_elt (htab_t htab, PTR element)
+{
+ htab_remove_elt_with_hash (htab, element, (*htab->hash_f) (element));
+}
+
+
+/* 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_with_hash (htab_t htab, PTR element, hashval_t hash)
+{
+ PTR *slot;
+
+ slot = htab_find_slot_with_hash (htab, element, hash, NO_INSERT);
+ if (*slot == HTAB_EMPTY_ENTRY)
+ return;
+
+ if (htab->del_f)
+ (*htab->del_f) (*slot);
+
+ *slot = HTAB_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_t htab, PTR *slot)
+{
+ if (slot < htab->entries || slot >= htab->entries + htab_size (htab)
+ || *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
+ abort ();
+
+ if (htab->del_f)
+ (*htab->del_f) (*slot);
+
+ *slot = HTAB_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_t htab, htab_trav callback, PTR info)
+{
+ PTR *slot;
+ PTR *limit;
+
+ slot = htab->entries;
+ limit = slot + htab_size (htab);
+
+ do
+ {
+ PTR x = *slot;
+
+ if (x != HTAB_EMPTY_ENTRY && x != HTAB_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_t htab, htab_trav callback, PTR info)
+{
+ if (htab_elements (htab) * 8 < htab_size (htab))
+ htab_expand (htab);
+
+ htab_traverse_noresize (htab, callback, info);
+}
+
+/* Return the fraction of fixed collisions during all work with given
+ hash table. */
+
+double
+htab_collisions (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 (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 (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;
+}
--- /dev/null
+/* An expandable hash tables datatype.
+ Copyright (C) 1999, 2000, 2002, 2003, 2004 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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) (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) (const void *, const void *);
+
+/* Cleanup function called whenever a live element is removed from
+ the hash table. */
+typedef void (*htab_del) (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) (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 void *(*htab_alloc) (size_t, size_t);
+
+/* We also need a free() routine. */
+typedef void (*htab_free) (void *);
+
+/* Memory allocation and deallocation; variants which take an extra
+ argument. */
+typedef void *(*htab_alloc_with_arg) (void *, size_t, size_t);
+typedef void (*htab_free_with_arg) (void *, void *);
+
+/* This macro defines reserved value for empty table entry. */
+
+#define HTAB_EMPTY_ENTRY ((PTR) 0)
+
+/* This macro defines reserved value for table entry which contained
+ a deleted element. */
+
+#define HTAB_DELETED_ENTRY ((PTR) 1)
+
+/* 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. */
+ void ** 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. */
+ void * GTY((skip)) alloc_arg;
+ htab_alloc_with_arg alloc_with_arg_f;
+ htab_free_with_arg free_with_arg_f;
+
+ /* Current size (in entries) of the hash table, as an index into the
+ table of primes. */
+ unsigned int size_prime_index;
+};
+
+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 (size_t, htab_hash,
+ htab_eq, htab_del,
+ htab_alloc, htab_free);
+
+extern htab_t htab_create_alloc_ex (size_t, htab_hash,
+ htab_eq, htab_del,
+ void *, htab_alloc_with_arg,
+ htab_free_with_arg);
+
+/* Backward-compatibility functions. */
+extern htab_t htab_create (size_t, htab_hash, htab_eq, htab_del);
+extern htab_t htab_try_create (size_t, htab_hash, htab_eq, htab_del);
+
+extern void htab_set_functions_ex (htab_t, htab_hash,
+ htab_eq, htab_del,
+ void *, htab_alloc_with_arg,
+ htab_free_with_arg);
+
+extern void htab_delete (htab_t);
+extern void htab_empty (htab_t);
+
+extern void * htab_find (htab_t, const void *);
+extern void ** htab_find_slot (htab_t, const void *, enum insert_option);
+extern void * htab_find_with_hash (htab_t, const void *, hashval_t);
+extern void ** htab_find_slot_with_hash (htab_t, const void *,
+ hashval_t, enum insert_option);
+extern void htab_clear_slot (htab_t, void **);
+extern void htab_remove_elt (htab_t, void *);
+extern void htab_remove_elt_with_hash (htab_t, void *, hashval_t);
+
+extern void htab_traverse (htab_t, htab_trav, void *);
+extern void htab_traverse_noresize (htab_t, htab_trav, void *);
+
+extern size_t htab_size (htab_t);
+extern size_t htab_elements (htab_t);
+extern double htab_collisions (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 (const void *);
+
+/* An iterative hash function for arbitrary data. */
+extern hashval_t iterative_hash (const void *, 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 */
--- /dev/null
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ according to the definition of MD5 in RFC 1321 from April 1992.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ NOTE: This source is derived from an old version taken from the GNU C
+ Library (glibc).
+
+ 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,
+ Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#include "ansidecl.h"
+#include "md5.h"
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define WORDS_BIGENDIAN 1
+# endif
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) \
+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+void
+md5_init_ctx (struct md5_ctx *ctx)
+{
+ ctx->A = (md5_uint32) 0x67452301;
+ ctx->B = (md5_uint32) 0xefcdab89;
+ ctx->C = (md5_uint32) 0x98badcfe;
+ ctx->D = (md5_uint32) 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_read_ctx (const struct md5_ctx *ctx, void *resbuf)
+{
+ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_finish_ctx (struct md5_ctx *ctx, void *resbuf)
+{
+ /* Take yet unprocessed bytes into account. */
+ md5_uint32 bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+ (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+ return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int
+md5_stream (FILE *stream, void *resblock)
+{
+ /* Important: BLOCKSIZE must be a multiple of 64. */
+#define BLOCKSIZE 4096
+ struct md5_ctx ctx;
+ char buffer[BLOCKSIZE + 72];
+ size_t sum;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Iterate over full file contents. */
+ while (1)
+ {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ size_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ do
+ {
+ n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+ sum += n;
+ }
+ while (sum < BLOCKSIZE && n != 0);
+ if (n == 0 && ferror (stream))
+ return 1;
+
+ /* If end of file is reached, end the loop. */
+ if (n == 0)
+ break;
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ md5_process_block (buffer, BLOCKSIZE, &ctx);
+ }
+
+ /* Add the last bytes if necessary. */
+ if (sum > 0)
+ md5_process_bytes (buffer, sum, &ctx);
+
+ /* Construct result in desired memory. */
+ md5_finish_ctx (&ctx, resblock);
+ return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+md5_buffer (const char *buffer, size_t len, void *resblock)
+{
+ struct md5_ctx ctx;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_bytes (buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0)
+ {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy (&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (left_over + add > 64)
+ {
+ md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ (left_over + add) & 63);
+ ctx->buflen = (left_over + add) & 63;
+ }
+
+ buffer = (const void *) ((const char *) buffer + add);
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len > 64)
+ {
+#if !_STRING_ARCH_unaligned
+/* To check alignment gcc has an appropriate operator. Other
+ compilers don't. */
+# if __GNUC__ >= 2
+# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0)
+# else
+# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0)
+# endif
+ if (UNALIGNED_P (buffer))
+ while (len > 64)
+ {
+ md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+ buffer = (const char *) buffer + 64;
+ len -= 64;
+ }
+ else
+#endif
+ md5_process_block (buffer, len & ~63, ctx);
+ buffer = (const void *) ((const char *) buffer + (len & ~63));
+ len &= 63;
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0)
+ {
+ memcpy (ctx->buffer, buffer, len);
+ ctx->buflen = len;
+ }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+
+void
+md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = (const md5_uint32 *) buffer;
+ size_t nwords = len / sizeof (md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp)
+ {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ */
+
+ /* Round 1. */
+ OP (A, B, C, D, 7, (md5_uint32) 0xd76aa478);
+ OP (D, A, B, C, 12, (md5_uint32) 0xe8c7b756);
+ OP (C, D, A, B, 17, (md5_uint32) 0x242070db);
+ OP (B, C, D, A, 22, (md5_uint32) 0xc1bdceee);
+ OP (A, B, C, D, 7, (md5_uint32) 0xf57c0faf);
+ OP (D, A, B, C, 12, (md5_uint32) 0x4787c62a);
+ OP (C, D, A, B, 17, (md5_uint32) 0xa8304613);
+ OP (B, C, D, A, 22, (md5_uint32) 0xfd469501);
+ OP (A, B, C, D, 7, (md5_uint32) 0x698098d8);
+ OP (D, A, B, C, 12, (md5_uint32) 0x8b44f7af);
+ OP (C, D, A, B, 17, (md5_uint32) 0xffff5bb1);
+ OP (B, C, D, A, 22, (md5_uint32) 0x895cd7be);
+ OP (A, B, C, D, 7, (md5_uint32) 0x6b901122);
+ OP (D, A, B, C, 12, (md5_uint32) 0xfd987193);
+ OP (C, D, A, B, 17, (md5_uint32) 0xa679438e);
+ OP (B, C, D, A, 22, (md5_uint32) 0x49b40821);
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += FX (b, c, d) + correct_words[k] + T; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+#define FX(b, c, d) FG (b, c, d)
+
+ /* Round 2. */
+ OP (A, B, C, D, 1, 5, (md5_uint32) 0xf61e2562);
+ OP (D, A, B, C, 6, 9, (md5_uint32) 0xc040b340);
+ OP (C, D, A, B, 11, 14, (md5_uint32) 0x265e5a51);
+ OP (B, C, D, A, 0, 20, (md5_uint32) 0xe9b6c7aa);
+ OP (A, B, C, D, 5, 5, (md5_uint32) 0xd62f105d);
+ OP (D, A, B, C, 10, 9, (md5_uint32) 0x02441453);
+ OP (C, D, A, B, 15, 14, (md5_uint32) 0xd8a1e681);
+ OP (B, C, D, A, 4, 20, (md5_uint32) 0xe7d3fbc8);
+ OP (A, B, C, D, 9, 5, (md5_uint32) 0x21e1cde6);
+ OP (D, A, B, C, 14, 9, (md5_uint32) 0xc33707d6);
+ OP (C, D, A, B, 3, 14, (md5_uint32) 0xf4d50d87);
+ OP (B, C, D, A, 8, 20, (md5_uint32) 0x455a14ed);
+ OP (A, B, C, D, 13, 5, (md5_uint32) 0xa9e3e905);
+ OP (D, A, B, C, 2, 9, (md5_uint32) 0xfcefa3f8);
+ OP (C, D, A, B, 7, 14, (md5_uint32) 0x676f02d9);
+ OP (B, C, D, A, 12, 20, (md5_uint32) 0x8d2a4c8a);
+
+#undef FX
+#define FX(b, c, d) FH (b, c, d)
+
+ /* Round 3. */
+ OP (A, B, C, D, 5, 4, (md5_uint32) 0xfffa3942);
+ OP (D, A, B, C, 8, 11, (md5_uint32) 0x8771f681);
+ OP (C, D, A, B, 11, 16, (md5_uint32) 0x6d9d6122);
+ OP (B, C, D, A, 14, 23, (md5_uint32) 0xfde5380c);
+ OP (A, B, C, D, 1, 4, (md5_uint32) 0xa4beea44);
+ OP (D, A, B, C, 4, 11, (md5_uint32) 0x4bdecfa9);
+ OP (C, D, A, B, 7, 16, (md5_uint32) 0xf6bb4b60);
+ OP (B, C, D, A, 10, 23, (md5_uint32) 0xbebfbc70);
+ OP (A, B, C, D, 13, 4, (md5_uint32) 0x289b7ec6);
+ OP (D, A, B, C, 0, 11, (md5_uint32) 0xeaa127fa);
+ OP (C, D, A, B, 3, 16, (md5_uint32) 0xd4ef3085);
+ OP (B, C, D, A, 6, 23, (md5_uint32) 0x04881d05);
+ OP (A, B, C, D, 9, 4, (md5_uint32) 0xd9d4d039);
+ OP (D, A, B, C, 12, 11, (md5_uint32) 0xe6db99e5);
+ OP (C, D, A, B, 15, 16, (md5_uint32) 0x1fa27cf8);
+ OP (B, C, D, A, 2, 23, (md5_uint32) 0xc4ac5665);
+
+#undef FX
+#define FX(b, c, d) FI (b, c, d)
+
+ /* Round 4. */
+ OP (A, B, C, D, 0, 6, (md5_uint32) 0xf4292244);
+ OP (D, A, B, C, 7, 10, (md5_uint32) 0x432aff97);
+ OP (C, D, A, B, 14, 15, (md5_uint32) 0xab9423a7);
+ OP (B, C, D, A, 5, 21, (md5_uint32) 0xfc93a039);
+ OP (A, B, C, D, 12, 6, (md5_uint32) 0x655b59c3);
+ OP (D, A, B, C, 3, 10, (md5_uint32) 0x8f0ccc92);
+ OP (C, D, A, B, 10, 15, (md5_uint32) 0xffeff47d);
+ OP (B, C, D, A, 1, 21, (md5_uint32) 0x85845dd1);
+ OP (A, B, C, D, 8, 6, (md5_uint32) 0x6fa87e4f);
+ OP (D, A, B, C, 15, 10, (md5_uint32) 0xfe2ce6e0);
+ OP (C, D, A, B, 6, 15, (md5_uint32) 0xa3014314);
+ OP (B, C, D, A, 13, 21, (md5_uint32) 0x4e0811a1);
+ OP (A, B, C, D, 4, 6, (md5_uint32) 0xf7537e82);
+ OP (D, A, B, C, 11, 10, (md5_uint32) 0xbd3af235);
+ OP (C, D, A, B, 2, 15, (md5_uint32) 0x2ad7d2bb);
+ OP (B, C, D, A, 9, 21, (md5_uint32) 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
+++ /dev/null
-/* Map logical line numbers to (source file, line number) pairs.
- Copyright (C) 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
-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 "line-map.h"
-#include "intl.h"
-
-static void trace_include (const struct line_maps *, const struct line_map *);
-
-/* Initialize a line map set. */
-
-void
-linemap_init (struct line_maps *set)
-{
- set->maps = 0;
- set->allocated = 0;
- set->used = 0;
- set->last_listed = -1;
- set->trace_includes = false;
- set->depth = 0;
-}
-
-/* Free a line map set. */
-
-void
-linemap_free (struct line_maps *set)
-{
- if (set->maps)
- {
- struct line_map *map;
-
- /* Depending upon whether we are handling preprocessed input or
- not, this can be a user error or an ICE. */
- for (map = CURRENT_LINE_MAP (set); ! MAIN_FILE_P (map);
- map = INCLUDED_FROM (set, map))
- fprintf (stderr, "line-map.c: file \"%s\" entered but not left\n",
- map->to_file);
-
- free (set->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 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. */
-
-const struct line_map *
-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;
-
- if (set->used && from_line < set->maps[set->used - 1].from_line)
- abort ();
-
- if (set->used == set->allocated)
- {
- set->allocated = 2 * set->allocated + 256;
- 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)
- reason = LC_ENTER;
- else if (reason == LC_LEAVE)
- {
- struct line_map *from;
- bool error;
-
- if (MAIN_FILE_P (map - 1))
- {
- if (to_file == NULL)
- {
- set->depth--;
- set->used--;
- return NULL;
- }
- error = true;
- reason = LC_RENAME;
- from = map - 1;
- }
- else
- {
- from = INCLUDED_FROM (set, map - 1);
- error = to_file && strcmp (from->to_file, to_file);
- }
-
- /* Depending upon whether we are handling preprocessed input or
- not, this can be a user error or an ICE. */
- if (error)
- fprintf (stderr, "line-map.c: file \"%s\" left but not entered\n",
- to_file);
-
- /* A TO_FILE of NULL is special - we use the natural values. */
- if (error || to_file == NULL)
- {
- to_file = from->to_file;
- to_line = LAST_SOURCE_LINE (from) + 1;
- sysp = from->sysp;
- }
- }
-
- map->reason = reason;
- map->sysp = sysp;
- map->from_line = from_line;
- map->to_file = to_file;
- map->to_line = to_line;
-
- if (reason == LC_ENTER)
- {
- map->included_from = set->depth == 0 ? -1 : (int) (set->used - 2);
- set->depth++;
- if (set->trace_includes)
- trace_include (set, map);
- }
- else if (reason == LC_RENAME)
- map->included_from = map[-1].included_from;
- else if (reason == LC_LEAVE)
- {
- set->depth--;
- map->included_from = INCLUDED_FROM (set, map - 1)->included_from;
- }
-
- return map;
-}
-
-/* Given a logical line, returns the map from which the corresponding
- (source file, line) pair can be deduced. Since the set is built
- chronologically, the logical lines are monotonic increasing, and so
- the list is sorted and we can use a binary search. */
-
-const struct line_map *
-linemap_lookup (struct line_maps *set, source_location line)
-{
- unsigned int md, mn = 0, mx = set->used;
-
- if (mx == 0)
- abort ();
-
- while (mx - mn > 1)
- {
- md = (mn + mx) / 2;
- if (set->maps[md].from_line > line)
- mx = md;
- else
- mn = md;
- }
-
- return &set->maps[mn];
-}
-
-/* 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. */
-
-void
-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;
-
- set->last_listed = map->included_from;
- map = INCLUDED_FROM (set, map);
-
- fprintf (stderr, _("In file included from %s:%u"),
- map->to_file, LAST_SOURCE_LINE (map));
-
- while (! MAIN_FILE_P (map))
- {
- map = INCLUDED_FROM (set, map);
- /* Translators note: this message is used in conjunction
- with "In file included from %s:%ld" and some other
- tricks. We want something like this:
-
- | In file included from sys/select.h:123,
- | from sys/types.h:234,
- | from userfile.c:31:
- | bits/select.h:45: <error message here>
-
- with all the "from"s lined up.
- The trailing comma is at the beginning of this message,
- and the trailing colon is not translated. */
- fprintf (stderr, _(",\n from %s:%u"),
- map->to_file, LAST_SOURCE_LINE (map));
- }
-
- fputs (":\n", stderr);
-}
-
-/* Print an include trace, for e.g. the -H option of the preprocessor. */
-
-static void
-trace_include (const struct line_maps *set, const struct line_map *map)
-{
- unsigned int i = set->depth;
-
- while (--i)
- putc ('.', stderr);
- fprintf (stderr, " %s\n", map->to_file);
-}
+++ /dev/null
-/* Map logical line numbers to (source file, line number) pairs.
- Copyright (C) 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
-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! */
-
-#ifndef GCC_LINE_MAP_H
-#define GCC_LINE_MAP_H
-
-/* Reason for adding a line change with add_line_map (). LC_ENTER is
- when including a new file, e.g. a #include directive in C.
- LC_LEAVE is when reaching a file's end. LC_RENAME is when a file
- name or line number changes for neither of the above reasons
- (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
- gives the line mapping at whose end the current one was included.
- File(s) at the bottom of the include stack have this set to -1.
- REASON is the reason for creation of this line map, SYSP is one for
- a system header, two for a C system header file that therefore
- needs to be extern "C" protected in C++, and zero otherwise. */
-struct line_map
-{
- const char *to_file;
- unsigned int to_line;
- source_location from_line;
- int included_from;
- ENUM_BITFIELD (lc_reason) reason : CHAR_BIT;
- unsigned char sysp;
-};
-
-/* A set of chronological line_map structures. */
-struct line_maps
-{
- struct line_map *maps;
- unsigned int allocated;
- unsigned int used;
-
- /* The most recently listed include stack, if any, starts with
- LAST_LISTED as the topmost including file. -1 indicates nothing
- has been listed yet. */
- int last_listed;
-
- /* Depth of the include stack, including the current file. */
- unsigned int depth;
-
- /* If true, prints an include trace a la -H. */
- bool trace_includes;
-};
-
-/* Initialize a line map set. */
-extern void linemap_init (struct line_maps *);
-
-/* Free a line map set. */
-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 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 *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 *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 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)
-
-/* Returns the last source line within a map. This is the (last) line
- of the #include, or other directive, that caused a map change. */
-#define LAST_SOURCE_LINE(MAP) SOURCE_LINE ((MAP), (MAP)[1].from_line - 1)
-
-/* Returns the map a given map was included from. */
-#define INCLUDED_FROM(SET, MAP) (&(SET)->maps[(MAP)->included_from])
-
-/* Nonzero if the map is at the bottom of the include stack. */
-#define MAIN_FILE_P(MAP) ((MAP)->included_from < 0)
-
-/* The current line map. Saves a call to lookup_line if the caller is
- sure he is in the scope of the current map. */
-#define CURRENT_LINE_MAP(MAPS) ((MAPS)->maps + (MAPS)->used - 1)
-
-#endif /* !GCC_LINE_MAP_H */
--- /dev/null
+/* md5.h - Declaration of functions and data types used for MD5 sum
+ computing library functions.
+ Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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,
+ Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* The following contortions are an attempt to use the C preprocessor
+ to determine an unsigned integral type that is 32 bits wide. An
+ alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+ doing that would require that the configure script compile and *run*
+ the resulting executable. Locally running cross-compiled executables
+ is usually not possible. */
+
+#ifdef _LIBC
+# include <sys/types.h>
+typedef u_int32_t md5_uint32;
+typedef uintptr_t md5_uintptr;
+#else
+# define INT_MAX_32_BITS 2147483647
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+ This should be valid for all systems GNU cares about because
+ that doesn't include 16-bit systems, and only modern systems
+ (that certainly have <limits.h>) have 64+-bit integral types. */
+
+# ifndef INT_MAX
+# define INT_MAX INT_MAX_32_BITS
+# endif
+
+# if INT_MAX == INT_MAX_32_BITS
+ typedef unsigned int md5_uint32;
+# else
+# if SHRT_MAX == INT_MAX_32_BITS
+ typedef unsigned short md5_uint32;
+# else
+# if LONG_MAX == INT_MAX_32_BITS
+ typedef unsigned long md5_uint32;
+# else
+ /* The following line is intended to evoke an error.
+ Using #error is not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
+# endif
+# endif
+/* We have to make a guess about the integer type equivalent in size
+ to pointers which should always be correct. */
+typedef unsigned long int md5_uintptr;
+#endif
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128] ATTRIBUTE_ALIGNED_ALIGNOF(md5_uint32);
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+extern void md5_init_ctx (struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void md5_process_block (const void *buffer, size_t len,
+ struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void md5_process_bytes (const void *buffer, size_t len,
+ struct md5_ctx *ctx);
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf);
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf);
+
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+extern int md5_stream (FILE *stream, void *resblock);
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *md5_buffer (const char *buffer, size_t len, void *resblock);
+
+#endif
+++ /dev/null
-/* Dependency generator for Makefile fragments.
- 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
-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 "mkdeps.h"
-#include "cpplib.h"
-#include "cpphash.h"
-
-/* Keep this structure local to this file, so clients don't find it
- easy to start making assumptions. */
-struct deps
-{
- const char **targetv;
- unsigned int ntargets; /* number of slots actually occupied */
- unsigned int targets_size; /* amt of allocated space - in words */
-
- const char **depv;
- unsigned int ndeps;
- unsigned int deps_size;
-};
-
-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
- characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
- 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 (const char *filename)
-{
- int len;
- const char *p, *q;
- char *dst, *buffer;
-
- for (p = filename, len = 0; *p; p++, len++)
- {
- switch (*p)
- {
- case ' ':
- case '\t':
- /* GNU make uses a weird quoting scheme for white space.
- A space or tab preceded by 2N+1 backslashes represents
- N backslashes followed by space; a space or tab
- preceded by 2N backslashes represents N backslashes at
- the end of a file name; and backslashes in other
- contexts should not be doubled. */
- for (q = p - 1; filename <= q && *q == '\\'; q--)
- len++;
- len++;
- break;
-
- case '$':
- /* '$' is quoted by doubling it. */
- len++;
- break;
- }
- }
-
- /* Now we know how big to make the buffer. */
- buffer = xmalloc (len + 1);
-
- for (p = filename, dst = buffer; *p; p++, dst++)
- {
- switch (*p)
- {
- case ' ':
- case '\t':
- for (q = p - 1; filename <= q && *q == '\\'; q--)
- *dst++ = '\\';
- *dst++ = '\\';
- break;
-
- case '$':
- *dst++ = '$';
- break;
-
- default:
- /* nothing */;
- }
- *dst = *p;
- }
-
- *dst = '\0';
- return buffer;
-}
-
-/* Public routines. */
-
-struct deps *
-deps_init (void)
-{
- struct deps *d = xmalloc (sizeof (struct deps));
-
- /* Allocate space for the vectors only if we need it. */
-
- d->targetv = 0;
- d->depv = 0;
-
- d->ntargets = 0;
- d->targets_size = 0;
- d->ndeps = 0;
- d->deps_size = 0;
-
- return d;
-}
-
-void
-deps_free (struct deps *d)
-{
- unsigned int i;
-
- if (d->targetv)
- {
- for (i = 0; i < d->ntargets; i++)
- free ((void *) d->targetv[i]);
- free (d->targetv);
- }
-
- if (d->depv)
- {
- for (i = 0; i < d->ndeps; i++)
- free ((void *) d->depv[i]);
- free (d->depv);
- }
-
- 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 (struct deps *d, const char *t, int quote)
-{
- if (d->ntargets == d->targets_size)
- {
- d->targets_size = d->targets_size * 2 + 4;
- d->targetv = xrealloc (d->targetv,
- d->targets_size * sizeof (const char *));
- }
-
- if (quote)
- t = munge (t); /* Also makes permanent copy. */
- else
- t = xstrdup (t);
-
- d->targetv[d->ntargets++] = t;
-}
-
-/* Sets the default target if none has been given already. An empty
- string as the default target in interpreted as stdin. The string
- is quoted for MAKE. */
-void
-deps_add_default_target (cpp_reader *pfile, const char *tgt)
-{
- struct deps *d = pfile->deps;
-
- /* Only if we have no targets. */
- if (d->ntargets)
- return;
-
- if (tgt[0] == '\0')
- deps_add_target (d, "-", 1);
- else
- {
-#ifndef TARGET_OBJECT_SUFFIX
-# define TARGET_OBJECT_SUFFIX ".o"
-#endif
- const char *start = lbasename (tgt);
- char *o;
- char *suffix;
- const char *obj_ext;
-
- if (NULL == CPP_OPTION (pfile, obj_ext))
- obj_ext = TARGET_OBJECT_SUFFIX;
- else if (CPP_OPTION (pfile, obj_ext)[0] != '.')
- {
- char *t = alloca (strlen (CPP_OPTION (pfile, obj_ext)) + 2);
- t[0] = '.';
- strcpy (&t[1], CPP_OPTION (pfile, obj_ext));
- obj_ext = t;
- }
- else
- obj_ext = CPP_OPTION (pfile, obj_ext);
-
- 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 (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 = xrealloc (d->depv, d->deps_size * sizeof (const char *));
- }
- d->depv[d->ndeps++] = t;
-}
-
-void
-deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
-{
- unsigned int size, i, column;
-
- column = 0;
- if (colmax && colmax < 34)
- colmax = 34;
-
- for (i = 0; i < d->ntargets; i++)
- {
- size = strlen (d->targetv[i]);
- column += size;
- if (colmax && column > colmax)
- {
- fputs (" \\\n ", fp);
- column = 1 + size;
- }
- if (i)
- {
- putc (' ', fp);
- column++;
- }
- fputs (d->targetv[i], fp);
- }
-
- putc (':', fp);
- putc (' ', fp);
- column += 2;
-
- for (i = 0; i < d->ndeps; i++)
- {
- size = strlen (d->depv[i]);
- column += size;
- if (colmax && column > colmax)
- {
- fputs (" \\\n ", fp);
- column = 1 + size;
- }
- if (i)
- {
- putc (' ', fp);
- column++;
- }
- fputs (d->depv[i], fp);
- }
- putc ('\n', fp);
-}
-
-void
-deps_phony_targets (const struct deps *d, FILE *fp)
-{
- unsigned int i;
-
- for (i = 1; i < d->ndeps; i++)
- {
- putc ('\n', fp);
- fputs (d->depv[i], fp);
- putc (':', 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;
-}
+++ /dev/null
-/* Dependency generator for Makefile fragments.
- 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
-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! */
-
-#ifndef GCC_MKDEPS_H
-#define GCC_MKDEPS_H
-
-/* This is the data structure used by all the functions in mkdeps.c.
- It's quite straightforward, but should be treated as opaque. */
-
-struct deps;
-struct cpp_reader;
-
-/* Create a deps buffer. */
-extern struct deps *deps_init (void);
-
-/* Destroy a deps buffer. */
-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 (struct deps *, const char *, int);
-
-/* Sets the default target if none has been given already. An empty
- 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 (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 (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 (const struct deps *, FILE *);
-
-#endif /* ! GCC_MKDEPS_H */
#!/bin/sh
-# Like mv $1 $2, but if the files are the same, just delete $1.
-# Status is 0 if $2 is changed, 1 otherwise.
+
+# Copyright (C) 1996 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 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
if
test -r $2
then
if
-cmp -s $1 $2
+cmp $1 $2 > /dev/null
then
echo $2 is unchanged
rm -f $1
--- /dev/null
+# Copyright (C) 2003,2004 Free Software Foundation, Inc.\r
+# Contributed by Kelley Cook, June 2004.\r
+# Original code from Neil Booth, May 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+\r
+# Some common subroutines for use by opt[ch]-gen.awk.\r
+\r
+# Return nonzero if FLAGS contains a flag matching REGEX.\r
+function flag_set_p(regex, flags)\r
+{\r
+ return (" " flags " ") ~ (" " regex " ")\r
+}\r
+\r
+# Return STRING if FLAGS contains a flag matching regexp REGEX,\r
+# otherwise return the empty string.\r
+function test_flag(regex, flags, string)\r
+{\r
+ if (flag_set_p(regex, flags))\r
+ return string\r
+ return ""\r
+}\r
+\r
+# If FLAGS contains a "NAME(...argument...)" flag, return the value\r
+# of the argument. Return the empty string otherwise.\r
+function opt_args(name, flags)\r
+{\r
+ flags = " " flags\r
+ if (flags !~ " " name "\\(")\r
+ return ""\r
+ sub(".* " name "\\(", "", flags)\r
+ sub("\\).*", "", flags)\r
+\r
+ return flags\r
+}\r
+\r
+# Return the Nth comma-separated element of S. Return the empty string\r
+# if S does not contain N elements.\r
+function nth_arg(n, s)\r
+{\r
+ while (n-- > 0) {\r
+ if (s !~ ",")\r
+ return ""\r
+ sub("[^,]*, *", "", s)\r
+ }\r
+ sub(",.*", "", s)\r
+ return s\r
+}\r
+\r
+# Return a bitmask of CL_* values for option flags FLAGS.\r
+function switch_flags (flags)\r
+{\r
+ result = "0"\r
+ for (j = 0; j < n_langs; j++) {\r
+ regex = langs[j]\r
+ gsub ( "\\+", "\\+", regex )\r
+ result = result test_flag(regex, flags, " | " macros[j])\r
+ }\r
+ result = result \\r
+ test_flag("Common", flags, " | CL_COMMON") \\r
+ test_flag("Target", flags, " | CL_TARGET") \\r
+ test_flag("Joined", flags, " | CL_JOINED") \\r
+ test_flag("JoinedOrMissing", flags, " | CL_JOINED | CL_MISSING_OK") \\r
+ test_flag("Separate", flags, " | CL_SEPARATE") \\r
+ test_flag("RejectNegative", flags, " | CL_REJECT_NEGATIVE") \\r
+ test_flag("UInteger", flags, " | CL_UINTEGER") \\r
+ test_flag("Undocumented", flags, " | CL_UNDOCUMENTED") \\r
+ test_flag("Report", flags, " | CL_REPORT")\r
+ sub( "^0 \\| ", "", result )\r
+ return result\r
+}\r
+\r
+# If FLAGS includes a Var flag, return the name of the variable it specifies.\r
+# Return the empty string otherwise.\r
+function var_name(flags)\r
+{\r
+ return nth_arg(0, opt_args("Var", flags))\r
+}\r
+\r
+# Return true if the option described by FLAGS has a globally-visible state.\r
+function global_state_p(flags)\r
+{\r
+ return (var_name(flags) != "" \\r
+ || opt_args("Mask", flags) != "" \\r
+ || opt_args("InverseMask", flags) != "")\r
+}\r
+\r
+# Return true if the option described by FLAGS must have some state\r
+# associated with it.\r
+function needs_state_p(flags)\r
+{\r
+ return flag_set_p("Target", flags)\r
+}\r
+\r
+# If FLAGS describes an option that needs a static state variable,\r
+# return the name of that variable, otherwise return "". NAME is\r
+# the name of the option.\r
+function static_var(name, flags)\r
+{\r
+ if (global_state_p(flags) || !needs_state_p(flags))\r
+ return ""\r
+ gsub ("[^A-Za-z0-9]", "_", name)\r
+ return "VAR_" name\r
+}\r
+\r
+# Return the type of variable that should be associated with the given flags.\r
+function var_type(flags)\r
+{\r
+ if (!flag_set_p("Joined.*", flags))\r
+ return "int "\r
+ else if (flag_set_p("UInteger", flags))\r
+ return "int "\r
+ else\r
+ return "const char *"\r
+}\r
+\r
+# Given that an option has flags FLAGS, return an initializer for the\r
+# "var_cond" and "var_value" fields of its cl_options[] entry.\r
+function var_set(flags)\r
+{\r
+ s = nth_arg(1, opt_args("Var", flags))\r
+ if (s != "")\r
+ return "CLVC_EQUAL, " s\r
+ s = opt_args("Mask", flags);\r
+ if (s != "") {\r
+ vn = var_name(flags);\r
+ if (vn)\r
+ return "CLVC_BIT_SET, OPTION_MASK_" s\r
+ else\r
+ return "CLVC_BIT_SET, MASK_" s\r
+ }\r
+ s = nth_arg(0, opt_args("InverseMask", flags));\r
+ if (s != "") {\r
+ vn = var_name(flags);\r
+ if (vn)\r
+ return "CLVC_BIT_CLEAR, OPTION_MASK_" s\r
+ else\r
+ return "CLVC_BIT_CLEAR, MASK_" s\r
+ }\r
+ if (var_type(flags) == "const char *")\r
+ return "CLVC_STRING, 0"\r
+ return "CLVC_BOOLEAN, 0"\r
+}\r
+\r
+# Given that an option called NAME has flags FLAGS, return an initializer\r
+# for the "flag_var" field of its cl_options[] entry.\r
+function var_ref(name, flags)\r
+{\r
+ name = var_name(flags) static_var(name, flags)\r
+ if (name != "")\r
+ return "&" name\r
+ if (opt_args("Mask", flags) != "")\r
+ return "&target_flags"\r
+ if (opt_args("InverseMask", flags) != "")\r
+ return "&target_flags"\r
+ return "0"\r
+}\r
--- /dev/null
+# Copyright (C) 2003,2004 Free Software Foundation, Inc.\r
+# Contributed by Kelley Cook, June 2004.\r
+# Original code from Neil Booth, May 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+\r
+# This Awk script takes a list of *.opt files and combines them into \r
+# a three-field sorted list suitable for input into opt[ch]-gen.awk.\r
+#\r
+# Usage: awk -f opt-gather.awk file1.opt [...] > outputfile\r
+\r
+function sort(ARRAY, ELEMENTS)\r
+{\r
+ for (i = 2; i <= ELEMENTS; ++i) {\r
+ for (j = i; ARRAY[j-1] > ARRAY[j]; --j) {\r
+ temp = ARRAY[j]\r
+ ARRAY[j] = ARRAY[j-1]\r
+ ARRAY[j-1] = temp\r
+ }\r
+ }\r
+ return\r
+}\r
+\r
+BEGIN { numrec = 0 }\r
+\r
+# Ignore comments and blank lines\r
+/^[ \t]*(;|$)/ { flag = 0; next }\r
+/^[^ \t]/ { if (flag == 0) {\r
+ record[++numrec] = $0\r
+ flag = 1 }\r
+ else {\r
+ record[numrec] = record[numrec] SUBSEP $0\r
+ }\r
+}\r
+\r
+# Sort it and output it\r
+END {\r
+ sort(record,numrec)\r
+ \r
+ for (i = 1; i <= numrec; i++) {\r
+ print record[i] }\r
+}\r
--- /dev/null
+# Copyright (C) 2003,2004 Free Software Foundation, Inc.\r
+# Contributed by Kelley Cook, June 2004.\r
+# Original code from Neil Booth, May 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+\r
+# This Awk script reads in the option records generated from \r
+# opt-gather.awk, combines the flags of duplicat options and generates a\r
+# C file.\r
+#\r
+# This program uses functions from opt-functions.awk\r
+#\r
+# Usage: awk -f opt-functions.awk -f optc-gen.awk \\r
+# [-v header_name=header.h] < inputfile > options.c\r
+\r
+BEGIN {\r
+ n_opts = 0\r
+ n_langs = 0\r
+ quote = "\042"\r
+ comma = ","\r
+ FS=SUBSEP\r
+ # Default the name of header created from opth-gen.awk to options.h\r
+ if (header_name == "") header_name="options.h"\r
+}\r
+\r
+# Collect the text and flags of each option into an array\r
+ {\r
+ if ($1 == "Language") {\r
+ langs[n_langs] = $2\r
+ n_langs++;\r
+ }\r
+ else {\r
+ name = opt_args("Mask", $1)\r
+ if (name == "") {\r
+ opts[n_opts] = $1\r
+ flags[n_opts] = $2\r
+ help[n_opts] = $3\r
+ n_opts++;\r
+ }\r
+ }\r
+ }\r
+\r
+# Dump that array of options into a C file.\r
+END {\r
+print "/* This file is auto-generated by opts.sh. */"\r
+print ""\r
+n_headers = split(header_name, headers, " ")\r
+for (i = 1; i <= n_headers; i++)\r
+ print "#include " quote headers[i] quote\r
+print "#include " quote "opts.h" quote\r
+print "#include " quote "intl.h" quote\r
+print ""\r
+\r
+for (i = 0; i < n_opts; i++) {\r
+ name = var_name(flags[i]);\r
+ if (name == "")\r
+ continue;\r
+\r
+ if (flag_set_p("VarExists", flags[i]))\r
+ continue;\r
+\r
+ init = opt_args("Init", flags[i])\r
+ if (init != "")\r
+ init = " = " init;\r
+ else if (name in var_seen)\r
+ continue;\r
+\r
+ print "/* Set by -" opts[i] "."\r
+ print " " help[i] " */"\r
+ print var_type(flags[i]) name init ";"\r
+ print ""\r
+\r
+ var_seen[name] = 1;\r
+}\r
+\r
+print ""\r
+print "/* Local state variables. */"\r
+for (i = 0; i < n_opts; i++) {\r
+ name = static_var(opts[i], flags[i]);\r
+ if (name != "")\r
+ print "static " var_type(flags[i]) name ";"\r
+}\r
+print ""\r
+\r
+print "const char * const lang_names[] =\n{"\r
+for (i = 0; i < n_langs; i++) {\r
+ macros[i] = "CL_" langs[i]\r
+ gsub( "[^A-Za-z0-9_]", "X", macros[i] )\r
+ s = substr(" ", length (macros[i]))\r
+ print " " quote langs[i] quote ","\r
+ }\r
+\r
+print " 0\n};\n"\r
+print "const unsigned int cl_options_count = N_OPTS;\n"\r
+\r
+print "const struct cl_option cl_options[] =\n{"\r
+\r
+for (i = 0; i < n_opts; i++)\r
+ back_chain[i] = "N_OPTS";\r
+\r
+for (i = 0; i < n_opts; i++) {\r
+ # Combine the flags of identical switches. Switches\r
+ # appear many times if they are handled by many front\r
+ # ends, for example.\r
+ while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {\r
+ flags[i + 1] = flags[i] " " flags[i + 1];\r
+ i++;\r
+ }\r
+\r
+ len = length (opts[i]);\r
+ enum = "OPT_" opts[i]\r
+ if (opts[i] == "finline-limit=")\r
+ enum = enum "eq"\r
+ gsub ("[^A-Za-z0-9]", "_", enum)\r
+\r
+ # If this switch takes joined arguments, back-chain all\r
+ # subsequent switches to it for which it is a prefix. If\r
+ # a later switch S is a longer prefix of a switch T, T\r
+ # will be back-chained to S in a later iteration of this\r
+ # for() loop, which is what we want.\r
+ if (flag_set_p("Joined.*", flags[i])) {\r
+ for (j = i + 1; j < n_opts; j++) {\r
+ if (substr (opts[j], 1, len) != opts[i])\r
+ break;\r
+ back_chain[j] = enum;\r
+ }\r
+ }\r
+\r
+ s = substr(" ", length (opts[i]))\r
+ if (i + 1 == n_opts)\r
+ comma = ""\r
+\r
+ if (help[i] == "")\r
+ hlp = "0"\r
+ else\r
+ hlp = quote help[i] quote;\r
+\r
+ printf(" { %c-%s%c,\n %s,\n %s, %u,\n",\r
+ quote, opts[i], quote, hlp, back_chain[i], len)\r
+ condition = opt_args("Condition", flags[i])\r
+ cl_flags = switch_flags(flags[i])\r
+ if (condition != "")\r
+ printf("#if %s\n" \\r
+ " %s,\n" \\r
+ "#else\n" \\r
+ " CL_DISABLED,\n" \\r
+ "#endif\n",\r
+ condition, cl_flags, cl_flags)\r
+ else\r
+ printf(" %s,\n", cl_flags)\r
+ printf(" %s, %s }%s\n", var_ref(opts[i], flags[i]),\r
+ var_set(flags[i]), comma)\r
+}\r
+\r
+print "};"\r
+}\r
--- /dev/null
+# Copyright (C) 2003,2004 Free Software Foundation, Inc.\r
+# Contributed by Kelley Cook, June 2004.\r
+# Original code from Neil Booth, May 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
+\r
+# This Awk script reads in the option records generated from \r
+# opt-gather.awk, combines the flags of duplicate options and generates a\r
+# C header file.\r
+#\r
+# This program uses functions from opt-functions.awk\r
+# Usage: awk -f opt-functions.awk -f opth-gen.awk < inputfile > options.h\r
+\r
+BEGIN {\r
+ n_opts = 0\r
+ n_langs = 0\r
+ n_extra_masks = 0\r
+ quote = "\042"\r
+ comma = ","\r
+ FS=SUBSEP\r
+}\r
+\r
+# Collect the text and flags of each option into an array\r
+ {\r
+ if ($1 == "Language") {\r
+ langs[n_langs] = $2\r
+ n_langs++;\r
+ }\r
+ else {\r
+ name = opt_args("Mask", $1)\r
+ if (name == "") {\r
+ opts[n_opts] = $1\r
+ flags[n_opts] = $2\r
+ help[n_opts] = $3\r
+ n_opts++;\r
+ }\r
+ else {\r
+ extra_masks[n_extra_masks++] = name\r
+ }\r
+ }\r
+ }\r
+\r
+# Dump out an enumeration into a .h file.\r
+# Combine the flags of duplicate options.\r
+END {\r
+print "/* This file is auto-generated by opts.sh. */"\r
+print ""\r
+print "#ifndef OPTIONS_H"\r
+print "#define OPTIONS_H"\r
+print ""\r
+print "extern int target_flags;"\r
+print ""\r
+\r
+for (i = 0; i < n_opts; i++) {\r
+ name = var_name(flags[i]);\r
+ if (name == "")\r
+ continue;\r
+\r
+ print "extern " var_type(flags[i]) name ";"\r
+}\r
+print ""\r
+\r
+for (i = 0; i < n_opts; i++) {\r
+ name = opt_args("Mask", flags[i])\r
+ vname = var_name(flags[i])\r
+ mask = "MASK_"\r
+ if (vname != "") {\r
+ mask = "OPTION_MASK_"\r
+ }\r
+ if (name != "" && !flag_set_p("MaskExists", flags[i]))\r
+ print "#define " mask name " (1 << " masknum[vname]++ ")"\r
+}\r
+for (i = 0; i < n_extra_masks; i++) {\r
+ print "#define MASK_" extra_masks[i] " (1 << " masknum[""]++ ")"\r
+}\r
+\r
+for (var in masknum) {\r
+ if (masknum[var] > 31) {\r
+ if (var == "")\r
+ print "#error too many target masks"\r
+ else\r
+ print "#error too many masks for " var\r
+ }\r
+}\r
+print ""\r
+\r
+for (i = 0; i < n_opts; i++) {\r
+ name = opt_args("Mask", flags[i])\r
+ vname = var_name(flags[i])\r
+ macro = "OPTION_"\r
+ mask = "OPTION_MASK_"\r
+ if (vname == "") {\r
+ vname = "target_flags"\r
+ macro = "TARGET_"\r
+ mask = "MASK_"\r
+ }\r
+ if (name != "" && !flag_set_p("MaskExists", flags[i]))\r
+ print "#define " macro name \\r
+ " ((" vname " & " mask name ") != 0)"\r
+}\r
+for (i = 0; i < n_extra_masks; i++) {\r
+ print "#define TARGET_" extra_masks[i] \\r
+ " ((target_flags & MASK_" extra_masks[i] ") != 0)"\r
+}\r
+print ""\r
+\r
+for (i = 0; i < n_opts; i++) {\r
+ opt = opt_args("InverseMask", flags[i])\r
+ if (opt ~ ",")\r
+ print "#define TARGET_" nth_arg(1, opt) \\r
+ " ((target_flags & MASK_" nth_arg(0, opt) ") == 0)"\r
+}\r
+print ""\r
+\r
+for (i = 0; i < n_langs; i++) {\r
+ macros[i] = "CL_" langs[i]\r
+ gsub( "[^A-Za-z0-9_]", "X", macros[i] )\r
+ s = substr(" ", length (macros[i]))\r
+ print "#define " macros[i] s " (1 << " i ")"\r
+ }\r
+\r
+print ""\r
+print "enum opt_code"\r
+print "{"\r
+ \r
+for (i = 0; i < n_opts; i++)\r
+ back_chain[i] = "N_OPTS";\r
+\r
+for (i = 0; i < n_opts; i++) {\r
+ # Combine the flags of identical switches. Switches\r
+ # appear many times if they are handled by many front\r
+ # ends, for example.\r
+ while( i + 1 != n_opts && opts[i] == opts[i + 1] ) {\r
+ flags[i + 1] = flags[i] " " flags[i + 1];\r
+ i++;\r
+ }\r
+\r
+ len = length (opts[i]);\r
+ enum = "OPT_" opts[i]\r
+ if (opts[i] == "finline-limit=")\r
+ enum = enum "eq"\r
+ gsub ("[^A-Za-z0-9]", "_", enum)\r
+\r
+ # If this switch takes joined arguments, back-chain all\r
+ # subsequent switches to it for which it is a prefix. If\r
+ # a later switch S is a longer prefix of a switch T, T\r
+ # will be back-chained to S in a later iteration of this\r
+ # for() loop, which is what we want.\r
+ if (flag_set_p("Joined.*", flags[i])) {\r
+ for (j = i + 1; j < n_opts; j++) {\r
+ if (substr (opts[j], 1, len) != opts[i])\r
+ break;\r
+ back_chain[j] = enum;\r
+ }\r
+ }\r
+\r
+ s = substr(" ", length (opts[i]))\r
+ if (i + 1 == n_opts)\r
+ comma = ""\r
+\r
+ if (help[i] == "")\r
+ hlp = "0"\r
+ else\r
+ hlp = "N_(\"" help[i] "\")";\r
+\r
+ print " " enum "," s "/* -" opts[i] " */"\r
+}\r
+\r
+print " N_OPTS"\r
+print "};"\r
+print ""\r
+print "#endif /* OPTIONS_H */"\r
+}\r
+++ /dev/null
-/* This file is auto-generated by opts.sh. */
-
-#include <intl.h>
-#include "options.h"
-#include "opts.h"
-
-const char * const lang_names[] =
-{
- "SDCPP",
- 0
-};
-
-const unsigned int cl_options_count = N_OPTS;
-
-const struct cl_option cl_options[] =
-{
- { "--help",
- N_("Display this information"),
- N_OPTS, 5, CL_COMMON },
- { "--version",
- N_("Display the compiler's version"),
- N_OPTS, 8, CL_COMMON },
- { "-A",
- N_("-A<question>=<answer> Assert the <answer> to <question>. Putting '-' before <question> disables the <answer> to <question>"),
- N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-C",
- N_("Do not discard comments"),
- N_OPTS, 1, CL_SDCPP },
- { "-CC",
- N_("Do not discard comments in macro expansions"),
- N_OPTS, 2, CL_SDCPP },
- { "-D",
- N_("-D<macro>[=<val>] Define a <macro> with <val> as its value. If just <macro> is given, <val> is taken to be 1"),
- N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-H",
- N_("Print the name of header files as they are used"),
- N_OPTS, 1, CL_SDCPP },
- { "-I",
- N_("-I <dir> Add <dir> to the end of the main include path. -I- gives more include path control; see info documentation"),
- N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-M",
- N_("Generate make dependencies"),
- N_OPTS, 1, CL_SDCPP },
- { "-MD",
- N_("Generate make dependencies and compile"),
- N_OPTS, 2, CL_SDCPP | CL_SEPARATE },
- { "-MF",
- N_("-MF <file> Write dependency output to the given file"),
- N_OPTS, 2, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-MG",
- N_("Treat missing header files as generated files"),
- N_OPTS, 2, CL_SDCPP },
- { "-MM",
- N_("Like -M but ignore system header files"),
- N_OPTS, 2, CL_SDCPP },
- { "-MMD",
- N_("Like -MD but ignore system header files"),
- N_OPTS, 3, CL_SDCPP | CL_SEPARATE },
- { "-MP",
- N_("Generate phony targets for all headers"),
- N_OPTS, 2, CL_SDCPP },
- { "-MQ",
- N_("-MQ <target> Add a MAKE-quoted target"),
- N_OPTS, 2, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-MT",
- N_("-MT <target> Add an unquoted target"),
- N_OPTS, 2, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-P",
- N_("Do not generate #line directives"),
- N_OPTS, 1, CL_SDCPP },
- { "-U",
- N_("-U<macro> Undefine <macro>"),
- N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-Wall",
- N_("Enable most warning messages"),
- N_OPTS, 4, CL_SDCPP },
- { "-Wcomment",
- N_("Warn about possibly nested block comments, and C++ comments spanning more than one physical line"),
- N_OPTS, 8, CL_SDCPP },
- { "-Wcomments",
- N_("Synonym for -Wcomment"),
- N_OPTS, 9, CL_SDCPP },
- { "-Wdeprecated",
- N_("Warn about deprecated compiler features"),
- N_OPTS, 11, CL_SDCPP },
- { "-Wendif-labels",
- N_("Warn about stray tokens after #elif and #endif"),
- N_OPTS, 13, CL_SDCPP },
- { "-Werror",
- N_("Treat all warnings as errors"),
- N_OPTS, 6, CL_SDCPP },
- { "-Wimport",
- N_("Deprecated. This switch has no effect."),
- N_OPTS, 7, CL_SDCPP },
- { "-Wsystem-headers",
- N_("Do not suppress warnings from system headers"),
- N_OPTS, 15, CL_SDCPP },
- { "-Wtrigraphs",
- N_("Warn if trigraphs are encountered that might affect the meaning of the program"),
- N_OPTS, 10, CL_SDCPP },
- { "-Wundef",
- N_("Warn if an undefined macro is used in an #if directive"),
- N_OPTS, 6, CL_SDCPP },
- { "-Wunused-macros",
- N_("Warn about macros defined in the main file that are not used"),
- N_OPTS, 14, CL_SDCPP },
- { "-ansi",
- N_("A synonym for -std=c89."),
- N_OPTS, 4, CL_SDCPP },
- { "-d",
- N_("-d<letters> Enable dumps from specific passes of the compiler"),
- N_OPTS, 1, CL_SDCPP | CL_JOINED },
- { "-fdollars-in-identifiers",
- N_("Permit '$' as an identifier character"),
- N_OPTS, 23, CL_SDCPP },
- { "-fexec-charset=",
- N_("-fexec-charset=<cset> Convert all strings and character constants to character set <cset>"),
- N_OPTS, 14, CL_SDCPP | CL_JOINED | CL_REJECT_NEGATIVE },
- { "-finput-charset=",
- N_("-finput-charset=<cset> Specify the default character set for source files."),
- N_OPTS, 15, CL_SDCPP | CL_JOINED | CL_REJECT_NEGATIVE },
- { "-fpreprocessed",
- N_("Treat the input file as already preprocessed"),
- N_OPTS, 13, CL_SDCPP },
- { "-fshow-column",
- 0,
- N_OPTS, 12, CL_SDCPP },
- { "-fsigned-char",
- N_("Make \"char\" signed by default"),
- N_OPTS, 12, CL_SDCPP },
- { "-ftabstop=",
- N_("-ftabstop=<number> Distance between tab stops for column reporting"),
- N_OPTS, 9, CL_SDCPP | CL_JOINED | CL_REJECT_NEGATIVE | CL_UINTEGER },
- { "-funsigned-char",
- N_("Make \"char\" unsigned by default"),
- N_OPTS, 14, CL_SDCPP },
- { "-fwide-exec-charset=",
- N_("-fwide-exec-charset=<cset> Convert all wide strings and character constants to character set <cset>"),
- N_OPTS, 19, CL_SDCPP | CL_JOINED | CL_REJECT_NEGATIVE },
- { "-fworking-directory",
- N_("Generate a #line directive pointing at the current working directory"),
- N_OPTS, 18, CL_SDCPP },
- { "-idirafter",
- N_("-idirafter <dir> Add <dir> to the end of the system include path"),
- N_OPTS, 9, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-imacros",
- N_("-imacros <file> Accept definition of macros in <file>"),
- N_OPTS, 7, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-include",
- N_("-include <file> Include the contents of <file> before other files"),
- N_OPTS, 7, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-iprefix",
- N_("-iprefix <path> Specify <path> as a prefix for next two options"),
- N_OPTS, 7, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-isysroot",
- N_("-isysroot <dir> Set <dir> to be the system root directory"),
- N_OPTS, 8, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-isystem",
- N_("-isystem <dir> Add <dir> to the start of the system include path"),
- N_OPTS, 7, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-iwithprefix",
- N_("-iwithprefix <dir> Add <dir> to the end of the system include path"),
- N_OPTS, 11, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-iwithprefixbefore",
- N_("-iwithprefixbefore <dir> Add <dir> to the end of the main include path"),
- OPT_iwithprefix, 17, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-lang-asm",
- 0,
- N_OPTS, 8, CL_UNDOCUMENTED },
- { "-lang-objc",
- 0,
- N_OPTS, 9, CL_SDCPP | CL_UNDOCUMENTED },
- { "-nostdinc",
- N_("Do not search standard system include directories (those specified with -isystem will still be used)"),
- N_OPTS, 8, CL_SDCPP },
- { "-o",
- N_("-o <file> Place output into <file>"),
- N_OPTS, 1, CL_SDCPP | CL_JOINED | CL_SEPARATE },
- { "-obj-ext=",
- N_("-obj-ext=<extension> Define object file extension, used for generation of make dependencies"),
- OPT_o, 8, CL_SDCPP | CL_JOINED },
- { "-pedantic",
- N_("Issue warnings needed for strict compliance to the standard"),
- N_OPTS, 8, CL_SDCPP },
- { "-pedantic-errors",
- N_("Like -pedantic but issue them as errors"),
- N_OPTS, 15, CL_SDCPP },
- { "-pedantic-parse-number",
- N_("Pedantic parse number"),
- N_OPTS, 21, CL_SDCPP },
- { "-remap",
- N_("Remap file names when including files"),
- N_OPTS, 5, CL_SDCPP },
- { "-std=c89",
- N_("Conform to the ISO 1990 C standard"),
- N_OPTS, 7, CL_SDCPP },
- { "-std=c99",
- N_("Conform to the ISO 1999 C standard"),
- N_OPTS, 7, CL_SDCPP },
- { "-std=iso9899:1990",
- N_("Conform to the ISO 1990 C standard"),
- N_OPTS, 16, 0 },
- { "-std=iso9899:199409",
- N_("Conform to the ISO 1990 C standard as amended in 1994"),
- N_OPTS, 18, CL_SDCPP },
- { "-std=iso9899:1999",
- N_("Conform to the ISO 1999 C standard"),
- N_OPTS, 16, 0 },
- { "-traditional-cpp",
- N_("Enable traditional preprocessing"),
- N_OPTS, 15, CL_SDCPP },
- { "-trigraphs",
- N_("-trigraphs Support ISO C trigraphs"),
- N_OPTS, 9, CL_SDCPP },
- { "-v",
- N_("Enable verbose output"),
- N_OPTS, 1, CL_SDCPP },
- { "-w",
- N_("Suppress warnings"),
- N_OPTS, 1, CL_SDCPP }
-};
+++ /dev/null
-/* This file is auto-generated by opts.sh. */
-
-#define CL_SDCPP (1 << 0)
-
-enum opt_code
-{
- OPT__help, /* --help */
- OPT__version, /* --version */
- OPT_A, /* -A */
- OPT_C, /* -C */
- OPT_CC, /* -CC */
- OPT_D, /* -D */
- OPT_H, /* -H */
- OPT_I, /* -I */
- OPT_M, /* -M */
- OPT_MD, /* -MD */
- OPT_MF, /* -MF */
- OPT_MG, /* -MG */
- OPT_MM, /* -MM */
- OPT_MMD, /* -MMD */
- OPT_MP, /* -MP */
- OPT_MQ, /* -MQ */
- OPT_MT, /* -MT */
- OPT_P, /* -P */
- OPT_U, /* -U */
- OPT_Wall, /* -Wall */
- OPT_Wcomment, /* -Wcomment */
- OPT_Wcomments, /* -Wcomments */
- OPT_Wdeprecated, /* -Wdeprecated */
- OPT_Wendif_labels, /* -Wendif-labels */
- OPT_Werror, /* -Werror */
- OPT_Wimport, /* -Wimport */
- OPT_Wsystem_headers, /* -Wsystem-headers */
- OPT_Wtrigraphs, /* -Wtrigraphs */
- OPT_Wundef, /* -Wundef */
- OPT_Wunused_macros, /* -Wunused-macros */
- OPT_ansi, /* -ansi */
- OPT_d, /* -d */
- OPT_fdollars_in_identifiers, /* -fdollars-in-identifiers */
- OPT_fexec_charset_, /* -fexec-charset= */
- OPT_finput_charset_, /* -finput-charset= */
- OPT_fpreprocessed, /* -fpreprocessed */
- OPT_fshow_column, /* -fshow-column */
- OPT_fsigned_char, /* -fsigned-char */
- OPT_ftabstop_, /* -ftabstop= */
- OPT_funsigned_char, /* -funsigned-char */
- OPT_fwide_exec_charset_, /* -fwide-exec-charset= */
- OPT_fworking_directory, /* -fworking-directory */
- OPT_idirafter, /* -idirafter */
- OPT_imacros, /* -imacros */
- OPT_include, /* -include */
- OPT_iprefix, /* -iprefix */
- OPT_isysroot, /* -isysroot */
- OPT_isystem, /* -isystem */
- OPT_iwithprefix, /* -iwithprefix */
- OPT_iwithprefixbefore, /* -iwithprefixbefore */
- OPT_lang_asm, /* -lang-asm */
- OPT_lang_objc, /* -lang-objc */
- OPT_nostdinc, /* -nostdinc */
- OPT_o, /* -o */
- OPT_obj_ext_, /* -obj-ext= */
- OPT_pedantic, /* -pedantic */
- OPT_pedantic_errors, /* -pedantic-errors */
- OPT_pedantic_parse_number, /* -pedantic-parse-number */
- OPT_remap, /* -remap */
- OPT_std_c89, /* -std=c89 */
- OPT_std_c99, /* -std=c99 */
- OPT_std_iso9899_1990, /* -std=iso9899:1990 */
- OPT_std_iso9899_199409, /* -std=iso9899:199409 */
- OPT_std_iso9899_1999, /* -std=iso9899:1999 */
- OPT_traditional_cpp, /* -traditional-cpp */
- OPT_trigraphs, /* -trigraphs */
- OPT_v, /* -v */
- OPT_w, /* -w */
- N_OPTS
-};
/* 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;
{
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))
+ /* Is the input either an exact match or a prefix that takes a
+ joined argument? */
+ if (!strncmp (input, opt->opt_text + 1, opt->opt_len)
+ && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED)))
{
- /* 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 language is OK, return it. */
+ if (opt->flags & lang_mask)
+
/* If we haven't remembered a prior match, remember this
one. Any prior match is necessarily better. */
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",
+ warning (0, "command line option \"%s\" is valid for %s but not for %s",
text, ok_langs, bad_lang);
free (ok_langs);
opt = argv[0];
- /* Drop the "no-" from negative switches. */
- if ((opt[1] == 'W' || opt[1] == 'f')
+ opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
+ if (opt_index == cl_options_count
+ && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm')
&& opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
{
+ /* Drop the "no-" from negative switches. */
size_t len = strlen (opt) - 3;
dup = xmalloc (len + 1);
memcpy (dup + 2, opt + 5, len - 2 + 1);
opt = dup;
value = 0;
+ opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET);
}
- opt_index = find_opt (opt + 1, lang_mask | CL_COMMON);
if (opt_index == cl_options_count)
goto done;
/* We've recognized this switch. */
result = 1;
+ /* Check to see if the option is disabled for this configuration. */
+ if (option->flags & CL_DISABLED)
+ {
+ error ("command line option %qs"
+ " is not supported by this configuration", opt);
+ goto done;
+ }
+
/* Sort out any argument the switch takes. */
if (option->flags & CL_JOINED)
{
/* 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)))
+ if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET)))
{
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))
+ if (!lang_hooks.missing_argument (opt, opt_index))
error ("missing argument to \"%s\"", opt);
goto done;
}
}
}
+ if (option->flag_var)
+ switch (option->var_type)
+ {
+ case CLVC_BOOLEAN:
+ *(int *) option->flag_var = value;
+ break;
+
+ case CLVC_EQUAL:
+ *(int *) option->flag_var = (value
+ ? option->var_value
+ : !option->var_value);
+ break;
+
+ case CLVC_BIT_CLEAR:
+ case CLVC_BIT_SET:
+ if ((value != 0) == (option->var_type == CLVC_BIT_SET))
+ *(int *) option->flag_var |= option->var_value;
+ else
+ *(int *) option->flag_var &= ~option->var_value;
+ ////if (option->flag_var == &target_flags)
+ //// target_flags_explicit |= option->var_value;
+ break;
+
+ case CLVC_STRING:
+ *(const char **) option->flag_var = arg;
+ break;
+ }
+
if (option->flags & lang_mask)
if ((*lang_hooks.handle_option) (opt_index, arg, value) == 0)
result = 0;
if (common_handle_option (opt_index, arg, value) == 0)
result = 0;
+ ////if (result && (option->flags & CL_TARGET))
+ //// if (!targetm.handle_option (opt_index, arg, value))
+ //// result = 0;
+
done:
if (dup)
free (dup);
return result;
}
+/* 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;
+}
+
/* Decode and handle the vector of command line options. LANG_MASK
contains has a single bit set representing the current
language. */
}
}
-/* 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
unsigned int lang_mask;
/* Perform language-specific options initialization. */
- lang_mask = (*lang_hooks.init_options) (argc, argv);
+ lang_mask = lang_hooks.init_options (argc, argv);
lang_hooks.initialize_diagnostics (global_dc);
}
/* Handle target- and language-independent options. Return zero to
- generate an "unknown option" message. */
+ generate an "unknown option" message. Only options that need
+ extra handling need to be listed here; if you simply want
+ VALUE assigned to a variable, it happens automatically. */
+
static int
common_handle_option (size_t scode, const char *arg,
int value ATTRIBUTE_UNUSED)
const char *help, *opt, *tab;
static char *printed;
- if (flag == CL_COMMON)
+ if (flag == CL_COMMON || flag == CL_TARGET)
{
filter = flag;
if (!printed)
}
while (remaining);
}
+
+/* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't
+ a simple on-off switch. */
+
+int
+option_enabled (int opt_idx)
+{
+ const struct cl_option *option = &(cl_options[opt_idx]);
+ if (option->flag_var)
+ switch (option->var_type)
+ {
+ case CLVC_BOOLEAN:
+ return *(int *) option->flag_var != 0;
+
+ case CLVC_EQUAL:
+ return *(int *) option->flag_var == option->var_value;
+
+ case CLVC_BIT_CLEAR:
+ return (*(int *) option->flag_var & option->var_value) == 0;
+
+ case CLVC_BIT_SET:
+ return (*(int *) option->flag_var & option->var_value) != 0;
+
+ case CLVC_STRING:
+ break;
+ }
+ return -1;
+}
+
+/* Fill STATE with the current state of option OPTION. Return true if
+ there is some state to store. */
+
+bool
+get_option_state (int option, struct cl_option_state *state)
+{
+ if (cl_options[option].flag_var == 0)
+ return false;
+
+ switch (cl_options[option].var_type)
+ {
+ case CLVC_BOOLEAN:
+ case CLVC_EQUAL:
+ state->data = cl_options[option].flag_var;
+ state->size = sizeof (int);
+ break;
+
+ case CLVC_BIT_CLEAR:
+ case CLVC_BIT_SET:
+ state->ch = option_enabled (option);
+ state->data = &state->ch;
+ state->size = 1;
+ break;
+
+ case CLVC_STRING:
+ state->data = *(const char **) cl_options[option].flag_var;
+ if (state->data == 0)
+ state->data = "";
+ state->size = strlen (state->data) + 1;
+ break;
+ }
+ return true;
+}
/* Command line option handling.
- Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, 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);
+/* Specifies how a switch's VAR_VALUE relates to its FLAG_VAR. */
+enum cl_var_type {
+ /* The switch is enabled when FLAG_VAR is nonzero. */
+ CLVC_BOOLEAN,
+
+ /* The switch is enabled when FLAG_VAR == VAR_VALUE. */
+ CLVC_EQUAL,
+
+ /* The switch is enabled when VAR_VALUE is not set in FLAG_VAR. */
+ CLVC_BIT_CLEAR,
+
+ /* The switch is enabled when VAR_VALUE is set in FLAG_VAR. */
+ CLVC_BIT_SET,
+
+ /* The switch takes a string argument and FLAG_VAR points to that
+ argument. */
+ CLVC_STRING
+};
struct cl_option
{
unsigned short back_chain;
unsigned char opt_len;
unsigned int flags;
+ void *flag_var;
+ enum cl_var_type var_type;
+ int var_value;
+};
+
+/* Records that the state of an option consists of SIZE bytes starting
+ at DATA. DATA might point to CH in some cases. */
+struct cl_option_state {
+ const void *data;
+ size_t size;
+ char ch;
};
extern const struct cl_option cl_options[];
extern const unsigned int cl_options_count;
extern const char *const lang_names[];
+#define CL_DISABLED (1 << 21) /* Disabled in this configuration. */
+#define CL_TARGET (1 << 22) /* Target-specific option. */
+#define CL_REPORT (1 << 23) /* Report argument with -fverbose-asm */
#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. */
extern unsigned num_in_fnames;
+extern void decode_options (unsigned int argc, const char **argv);
+extern int option_enabled (int opt_idx);
+extern bool get_option_state (int, struct cl_option_state *);
+
#endif
+++ /dev/null
-#!/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}
/* 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, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#ifndef GCC_OUTPUT_H
#define GCC_OUTPUT_H
get its actual length. Otherwise, get its maximum length. */
extern int get_attr_length (rtx);
+/* Obtain the current length of an insn. If branch shortening has been done,
+ get its actual length. Otherwise, get its minimum length. */
+extern int get_attr_min_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 (rtx);
extern void final_end_function (void);
/* Output assembler code for some insns: all or part of a function. */
-extern void final (rtx, FILE *, int, int);
+extern void final (rtx, FILE *, 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 (rtx, FILE *, int, int, int, int *);
+extern rtx final_scan_insn (rtx, FILE *, int, int, int *);
/* Replace a SUBREG with a REG or a MEM, based on the thing it is a
subreg of. */
/* Locate the proper template for the given insn-code. */
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 (tree, const char *, const char *);
-
/* Functions in flow.c */
-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 (void);
+/* Tell assembler to switch to unlikely-to-be-executed text section. */
+extern void unlikely_text_section (void);
+
/* Tell assembler to switch to data section. */
extern void data_section (void);
/* Determine if we're in the text section. */
extern int in_text_section (void);
+/* Determine if we're in the unlikely-to-be-executed text section. */
+extern int in_unlikely_text_section (void);
+
#ifdef CTORS_SECTION_ASM_OP
extern void ctors_section (void);
#endif
/* Tell assembler to switch to the section for function DECL. */
extern void function_section (tree);
+/* Tell assembler to switch to the most recently used text section. */
+extern void current_function_section (tree);
+
/* Tell assembler to switch to the section for string merging. */
extern void mergeable_string_section (tree, unsigned HOST_WIDE_INT,
unsigned int);
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
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 (const char *, int);
/* Assemble a label named NAME. */
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. */
+/* Output to FILE (an assembly file) a reference to NAME. If NAME
+ starts with a *, the rest of NAME is output verbatim. Otherwise
+ NAME is transformed in a target-specific way (usually by the
+ addition of an underscore). */
+extern void assemble_name_raw (FILE *, const char *);
+
+/* Like assemble_name_raw, but should be used when NAME might refer to
+ an entity that is also represented as a tree (like a function or
+ variable). If NAME does refer to such an entity, that entity will
+ be marked as referenced. */
extern void assemble_name (FILE *, const char *);
/* Return the assembler directive for creating a given kind of integer
/* 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. */
+ the constant, otherwise 0. If FORCE is nonzero the constant must
+ be outputable. */
extern bool assemble_integer (rtx, unsigned, unsigned, int);
/* An interface to assemble_integer for the common case in which a value is
extern int current_function_is_leaf;
-/* Nonzero if function being compiled doesn't contain any instructions
- that can throw an exception. This is set prior to final. */
-
-extern int current_function_nothrow;
-
/* Nonzero if function being compiled doesn't modify the stack pointer
(ignoring the prologue and epilogue). This is only valid after
life_analysis has run. */
/* Default file in which to dump debug output. */
#ifdef BUFSIZ
-extern FILE *rtl_dump_file;
+extern FILE *dump_file;
#endif
/* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */
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.
+ This means that inconsistencies are the user's fault, so don't die.
The precise value is the insn being output, to pass to error_for_asm. */
extern rtx this_is_asm_operands;
+/* Carry information from ASM_DECLARE_OBJECT_NAME
+ to ASM_FINISH_DECLARE_OBJECT. */
+extern int size_directive_output;
+extern tree last_assemble_variable_decl;
+
+enum in_section { no_section, in_text, in_unlikely_executed_text, in_data,
+ in_named
+#ifdef BSS_SECTION_ASM_OP
+ , in_bss
+#endif
+#ifdef CTORS_SECTION_ASM_OP
+ , in_ctors
+#endif
+#ifdef DTORS_SECTION_ASM_OP
+ , in_dtors
+#endif
+#ifdef READONLY_DATA_SECTION_ASM_OP
+ , in_readonly_data
+#endif
+#ifdef EXTRA_SECTIONS
+ , EXTRA_SECTIONS
+#endif
+};
+
+extern const char *last_text_section_name;
+extern enum in_section last_text_section;
+extern bool first_function_block_is_cold;
+
/* Decide whether DECL needs to be in a writable section.
RELOC is the same as for SELECT_SECTION. */
extern bool decl_readonly_section (tree, int);
#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 (const char *);
+/* A helper function for default_elf_select_section and
+ default_elf_unique_section. Categorizes the DECL. */
+
+enum section_category
+{
+ SECCAT_TEXT,
+
+ SECCAT_RODATA,
+ SECCAT_RODATA_MERGE_STR,
+ SECCAT_RODATA_MERGE_STR_INIT,
+ SECCAT_RODATA_MERGE_CONST,
+ SECCAT_SRODATA,
+
+ SECCAT_DATA,
+
+ /* To optimize loading of shared programs, define following subsections
+ of data section:
+ _REL Contains data that has relocations, so they get grouped
+ together and dynamic linker will visit fewer pages in memory.
+ _RO Contains data that is otherwise read-only. This is useful
+ with prelinking as most relocations won't be dynamically
+ linked and thus stay read only.
+ _LOCAL Marks data containing relocations only to local objects.
+ These relocations will get fully resolved by prelinking. */
+ SECCAT_DATA_REL,
+ SECCAT_DATA_REL_LOCAL,
+ SECCAT_DATA_REL_RO,
+ SECCAT_DATA_REL_RO_LOCAL,
+
+ SECCAT_SDATA,
+ SECCAT_TDATA,
+
+ SECCAT_BSS,
+ SECCAT_SBSS,
+ SECCAT_TBSS
+};
+
+
extern bool set_named_section_flags (const char *, unsigned int);
-extern void named_section_flags (const char *, unsigned int);
+#define named_section_flags(NAME, FLAGS) \
+ named_section_real((NAME), (FLAGS), /*decl=*/NULL_TREE)
+extern void named_section_real (const char *, unsigned int, tree);
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_no_named_section (const char *, unsigned int, tree);
+extern void default_elf_asm_named_section (const char *, unsigned int, tree);
+extern enum section_category categorize_decl_for_section (tree, int, int);
+extern void default_coff_asm_named_section (const char *, unsigned int, tree);
+extern void default_pe_asm_named_section (const char *, unsigned int, tree);
extern void default_stabs_asm_out_destructor (rtx, int);
extern void default_named_section_asm_out_destructor (rtx, 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_function_rodata_section (tree);
+extern void default_no_function_rodata_section (tree);
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,
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_emit_unwind_label (FILE *, tree, int, int);
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 int default_address_cost (rtx);
+/* dbxout helper functions */
+#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO
+
+extern void dbxout_int (int);
+extern void dbxout_stabd (int, int);
+extern void dbxout_begin_stabn (int);
+extern void dbxout_begin_stabn_sline (int);
+extern void dbxout_begin_empty_stabs (int);
+extern void dbxout_begin_simple_stabs (const char *, int);
+extern void dbxout_begin_simple_stabs_desc (const char *, int, int);
+
+extern void dbxout_stab_value_zero (void);
+extern void dbxout_stab_value_label (const char *);
+extern void dbxout_stab_value_label_diff (const char *, const char *);
+extern void dbxout_stab_value_internal_label (const char *, int *);
+extern void dbxout_stab_value_internal_label_diff (const char *, int *,
+ const char *);
+
+#endif
+
#endif /* ! GCC_OUTPUT_H */
/* Utility to update paths from internal to external forms.
- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU Library General Public
License along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* This file contains routines to update a path, both to canonicalize
the directory format and to handle any prefix translation.
#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
+#ifndef WIN32_REGISTRY_KEY
+# define WIN32_REGISTRY_KEY BASEVER
+#endif
+
/* Look up "key" in the registry, as above. */
static char *
size = 32;
dst = xmalloc (size);
- res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
+ res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
if (res == ERROR_MORE_DATA && type == REG_SZ)
{
dst = xrealloc (dst, size);
- res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
+ res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
}
if (type != REG_SZ || res != ERROR_SUCCESS)
while (*string++);
}
-/* Update PATH using KEY if PATH starts with PREFIX. The returned
- string is always malloc-ed, and the caller is responsible for
- freeing it. */
+/* Update PATH using KEY if PATH starts with PREFIX as a directory.
+ The returned string is always malloc-ed, and the caller is
+ responsible for freeing it. */
char *
update_path (const char *path, const char *key)
{
char *result, *p;
+ const int len = strlen (std_prefix);
- if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0)
+ if (! strncmp (path, std_prefix, len)
+ && (IS_DIR_SEPARATOR(path[len])
+ || path[len] == '\0')
+ && key != 0)
{
bool free_key = false;
free_key = true;
}
- result = concat (key, &path[strlen (std_prefix)], NULL);
+ result = concat (key, &path[len], NULL);
if (free_key)
free ((char *) key);
result = translate_name (result);
You should have received a copy of the GNU Library General Public
License along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#ifndef GCC_PREFIX_H
/* Various declarations for language-independent pretty-print subroutines.
- Copyright (C) 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, 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 "intl.h"
#include "pretty-print.h"
#define obstack_chunk_alloc xmalloc
/* A pointer to the formatted diagnostic message. */
#define pp_formatted_text_data(PP) \
- ((const char *) obstack_base (&pp_base (PP)->buffer->obstack))
+ ((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
}
/* Flush the formatted text of PRETTY-PRINTER onto the attached stream. */
-static inline void
+void
pp_write_text_to_stream (pretty_printer *pp)
{
const char *text = pp_formatted_text (pp);
static inline void
pp_append_r (pretty_printer *pp, const char *start, int length)
{
- obstack_grow (&pp->buffer->obstack, start, length);
+ obstack_grow (pp->buffer->obstack, start, length);
pp->buffer->line_length += length;
}
pp_space (pp);
}
-/* Format a message pointed to by TEXT. The following format specifiers are
- recognized as being client independent:
+/* 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.
%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. */
+ %%: '%'.
+ %<: opening quote.
+ %>: closing quote.
+ %': apostrophe (should only be used in untranslated messages;
+ translations should use appropriate punctuation directly).
+ %.*s: a substring the length of which is specified by an argument
+ integer.
+ %Ns: likewise, but length specified as constant in the format string.
+ %H: location_t.
+ %J: a decl tree, from which DECL_SOURCE_LOCATION will be recorded.
+ Flag 'q': quote formatted text (must come immediately after '%').
+
+ Arguments can be used sequentially, or through %N$ resp. *N$
+ notation Nth argument after the format string. If %N$ / *N$
+ notation is used, it must be used for all arguments, except %m, %%,
+ %<, %> and %', which may not have a number, as they do not consume
+ an argument. When %M$.*N$s is used, M must be N + 1. (This may
+ also be written %M$.*s, provided N is not otherwise used.) The
+ format string must have conversion specifiers with argument numbers
+ 1 up to highest argument; each argument may only be used once.
+ A format string can have at most 30 arguments. */
+
+/* Formatting phases 1 and 2: render TEXT->format_spec plus
+ TEXT->args_ptr into a series of chunks in PP->buffer->args[].
+ Phase 3 is in pp_base_format_text. */
+
void
-pp_base_format_text (pretty_printer *pp, text_info *text)
+pp_base_format (pretty_printer *pp, text_info *text)
{
- for (; *text->format_spec; ++text->format_spec)
+ output_buffer *buffer = pp->buffer;
+ const char *p;
+ const char **args;
+ struct chunk_info *new_chunk_array;
+
+ unsigned int curarg = 0, chunk = 0, argno;
+ pp_wrapping_mode_t old_wrapping_mode;
+ bool any_unnumbered = false, any_numbered = false;
+ const char **formatters[PP_NL_ARGMAX];
+
+ /* Allocate a new chunk structure. */
+ new_chunk_array = XOBNEW (&buffer->chunk_obstack, struct chunk_info);
+ new_chunk_array->prev = buffer->cur_chunk_array;
+ buffer->cur_chunk_array = new_chunk_array;
+ args = new_chunk_array->args;
+
+ /* Formatting phase 1: split up TEXT->format_spec into chunks in
+ PP->buffer->args[]. Even-numbered chunks are to be output
+ verbatim, odd-numbered chunks are format specifiers.
+ %m, %%, %<, %>, and %' are replaced with the appropriate text at
+ this point. */
+
+ memset (formatters, 0, sizeof formatters);
+
+ for (p = text->format_spec; *p; )
+ {
+ while (*p != '\0' && *p != '%')
+ {
+ obstack_1grow (&buffer->chunk_obstack, *p);
+ p++;
+ }
+
+ if (*p == '\0')
+ break;
+
+ switch (*++p)
+ {
+ case '\0':
+ gcc_unreachable ();
+
+ case '%':
+ obstack_1grow (&buffer->chunk_obstack, '%');
+ p++;
+ continue;
+
+ case '<':
+ obstack_grow (&buffer->chunk_obstack,
+ open_quote, strlen (open_quote));
+ p++;
+ continue;
+
+ case '>':
+ case '\'':
+ obstack_grow (&buffer->chunk_obstack,
+ close_quote, strlen (close_quote));
+ p++;
+ continue;
+
+ case 'm':
+ {
+ const char *errstr = xstrerror (text->err_no);
+ obstack_grow (&buffer->chunk_obstack, errstr, strlen (errstr));
+ }
+ p++;
+ continue;
+
+ default:
+ /* Handled in phase 2. Terminate the plain chunk here. */
+ obstack_1grow (&buffer->chunk_obstack, '\0');
+ gcc_assert (chunk < PP_NL_ARGMAX * 2);
+ args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
+ break;
+ }
+
+ if (ISDIGIT (*p))
+ {
+ char *end;
+ argno = strtoul (p, &end, 10) - 1;
+ p = end;
+ gcc_assert (*p == '$');
+ p++;
+
+ any_numbered = true;
+ gcc_assert (!any_unnumbered);
+ }
+ else
+ {
+ argno = curarg++;
+ any_unnumbered = true;
+ gcc_assert (!any_numbered);
+ }
+ gcc_assert (argno < PP_NL_ARGMAX);
+ gcc_assert (!formatters[argno]);
+ formatters[argno] = &args[chunk];
+ do
+ {
+ obstack_1grow (&buffer->chunk_obstack, *p);
+ p++;
+ }
+ while (strchr ("qwl+#", p[-1]));
+
+ if (p[-1] == '.')
+ {
+ /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
+ (where M == N + 1). */
+ if (ISDIGIT (*p))
+ {
+ do
+ {
+ obstack_1grow (&buffer->chunk_obstack, *p);
+ p++;
+ }
+ while (ISDIGIT (p[-1]));
+ gcc_assert (p[-1] == 's');
+ }
+ else
+ {
+ gcc_assert (*p == '*');
+ obstack_1grow (&buffer->chunk_obstack, '*');
+ p++;
+
+ if (ISDIGIT (*p))
+ {
+ char *end;
+ unsigned int argno2 = strtoul (p, &end, 10) - 1;
+ p = end;
+ gcc_assert (argno2 == argno - 1);
+ gcc_assert (!any_unnumbered);
+ gcc_assert (*p == '$');
+
+ p++;
+ formatters[argno2] = formatters[argno];
+ }
+ else
+ {
+ gcc_assert (!any_numbered);
+ formatters[argno+1] = formatters[argno];
+ curarg++;
+ }
+ gcc_assert (*p == 's');
+ obstack_1grow (&buffer->chunk_obstack, 's');
+ p++;
+ }
+ }
+ if (*p == '\0')
+ break;
+
+ obstack_1grow (&buffer->chunk_obstack, '\0');
+ gcc_assert (chunk < PP_NL_ARGMAX * 2);
+ args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
+ }
+
+ obstack_1grow (&buffer->chunk_obstack, '\0');
+ gcc_assert (chunk < PP_NL_ARGMAX * 2);
+ args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
+ args[chunk] = 0;
+
+ /* Set output to the argument obstack, and switch line-wrapping and
+ prefixing off. */
+ buffer->obstack = &buffer->chunk_obstack;
+ old_wrapping_mode = pp_set_verbatim_wrapping (pp);
+
+ /* Second phase. Replace each formatter with the formatted text it
+ corresponds to. */
+
+ for (argno = 0; formatters[argno]; argno++)
{
int precision = 0;
bool wide = false;
+ bool plus = false;
+ bool hash = false;
+ bool quote = 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;
- }
+ /* We do not attempt to enforce any ordering on the modifier
+ characters. */
- if (*text->format_spec == '\0')
- break;
+ for (p = *formatters[argno];; p++)
+ {
+ switch (*p)
+ {
+ case 'q':
+ gcc_assert (!quote);
+ quote = true;
+ continue;
+
+ case '+':
+ gcc_assert (!plus);
+ plus = true;
+ continue;
+
+ case '#':
+ gcc_assert (!hash);
+ hash = true;
+ continue;
+
+ case 'w':
+ gcc_assert (!wide);
+ wide = true;
+ continue;
+
+ case 'l':
+ /* We don't support precision beyond that of "long long". */
+ gcc_assert (precision < 2);
+ precision++;
+ continue;
+ }
+ break;
+ }
+
+ gcc_assert (!wide || precision == 0);
- /* 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)
+ if (quote)
+ pp_string (pp, open_quote);
+
+ switch (*p)
{
case 'c':
pp_character (pp, va_arg (*text->args_ptr, int));
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");
+ 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");
+ 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, "o");
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 '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");
+ 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");
+ 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));
+ case 'H':
+ {
+ location_t *locus = va_arg (*text->args_ptr, location_t *);
+ gcc_assert (text->locus != NULL);
+ *text->locus = *locus;
+ }
break;
- case '%':
- pp_character (pp, '%');
+ case 'J':
+ {
+ tree t = va_arg (*text->args_ptr, tree);
+ gcc_assert (text->locus != NULL);
+ *text->locus = DECL_SOURCE_LOCATION (t);
+ }
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);
+
+ /* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
+ (where M == N + 1). The format string should be verified
+ already from the first phase. */
+ p++;
+ if (ISDIGIT (*p))
+ {
+ char *end;
+ n = strtoul (p, &end, 10);
+ p = end;
+ gcc_assert (*p == 's');
+ }
+ else
+ {
+ gcc_assert (*p == '*');
+ p++;
+ gcc_assert (*p == 's');
+ n = va_arg (*text->args_ptr, int);
+
+ /* This consumes a second entry in the formatters array. */
+ gcc_assert (formatters[argno] == formatters[argno+1]);
+ argno++;
+ }
+
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 ();
- }
+ {
+ bool ok;
+
+ gcc_assert (pp_format_decoder (pp));
+ ok = pp_format_decoder (pp) (pp, text, p,
+ precision, wide, plus, hash);
+ gcc_assert (ok);
+ }
}
+
+ if (quote)
+ pp_string (pp, close_quote);
+
+ obstack_1grow (&buffer->chunk_obstack, '\0');
+ *formatters[argno] = XOBFINISH (&buffer->chunk_obstack, const char *);
}
+
+#ifdef ENABLE_CHECKING
+ for (; argno < PP_NL_ARGMAX; argno++)
+ gcc_assert (!formatters[argno]);
+#endif
+
+ /* Revert to normal obstack and wrapping mode. */
+ buffer->obstack = &buffer->formatted_obstack;
+ buffer->line_length = 0;
+ pp_wrapping_mode (pp) = old_wrapping_mode;
+ pp_clear_state (pp);
+}
+
+/* Format of a message pointed to by TEXT. */
+void
+pp_base_output_formatted_text (pretty_printer *pp)
+{
+ unsigned int chunk;
+ output_buffer *buffer = pp_buffer (pp);
+ struct chunk_info *chunk_array = buffer->cur_chunk_array;
+ const char **args = chunk_array->args;
+
+ gcc_assert (buffer->obstack == &buffer->formatted_obstack);
+ gcc_assert (buffer->line_length == 0);
+
+ /* This is a third phase, first 2 phases done in pp_base_format_args.
+ Now we actually print it. */
+ for (chunk = 0; args[chunk]; chunk++)
+ pp_string (pp, args[chunk]);
+
+ /* Deallocate the chunk structure and everything after it (i.e. the
+ associated series of formatted strings). */
+ buffer->cur_chunk_array = chunk_array->prev;
+ obstack_free (&buffer->chunk_obstack, chunk_array);
}
/* Helper subroutine of output_verbatim and verbatim. Do the appropriate
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;
+ pp_wrapping_mode_t oldmode = pp_set_verbatim_wrapping (pp);
+
/* Do the actual formatting. */
- pp_format_text (pp, text);
+ pp_format (pp, text);
+ pp_output_formatted_text (pp);
+
/* Restore previous settings. */
- pp_prefixing_rule (pp) = rule;
- pp_line_cutoff (pp) = line_cutoff;
+ pp_wrapping_mode (pp) = oldmode;
}
/* Flush the content of BUFFER onto the attached stream. */
void
pp_base_clear_output_area (pretty_printer *pp)
{
- obstack_free (&pp->buffer->obstack, obstack_base (&pp->buffer->obstack));
+ obstack_free (pp->buffer->obstack, obstack_base (pp->buffer->obstack));
pp->buffer->line_length = 0;
}
{
memset (pp, 0, sizeof (pretty_printer));
pp->buffer = xcalloc (1, sizeof (output_buffer));
- obstack_init (&pp->buffer->obstack);
+ obstack_init (&pp->buffer->chunk_obstack);
+ obstack_init (&pp->buffer->formatted_obstack);
+ pp->buffer->obstack = &pp->buffer->formatted_obstack;
pp->buffer->stream = stderr;
pp_line_cutoff (pp) = maximum_length;
pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
const char *
pp_base_formatted_text (pretty_printer *pp)
{
- obstack_1grow (&pp->buffer->obstack, '\0');
+ obstack_1grow (pp->buffer->obstack, '\0');
return pp_formatted_text_data (pp);
}
pp_base_last_position_in_text (const pretty_printer *pp)
{
const char *p = NULL;
- struct obstack *text = &pp->buffer->obstack;
+ struct obstack *text = pp->buffer->obstack;
if (obstack_base (text) != obstack_next_free (text))
p = ((const char *) obstack_next_free (text)) - 1;
text.err_no = errno;
text.args_ptr = ≈
text.format_spec = msg;
- pp_format_text (pp, &text);
+ text.locus = NULL;
+ pp_format (pp, &text);
+ pp_output_formatted_text (pp);
va_end (ap);
}
text.err_no = errno;
text.args_ptr = ≈
text.format_spec = msg;
+ text.locus = NULL;
pp_format_verbatim (pp, &text);
va_end (ap);
}
void
pp_base_newline (pretty_printer *pp)
{
- obstack_1grow (&pp->buffer->obstack, '\n');
+ obstack_1grow (pp->buffer->obstack, '\n');
pp->buffer->line_length = 0;
}
if (ISSPACE (c))
return;
}
- obstack_1grow (&pp->buffer->obstack, c);
+ obstack_1grow (pp->buffer->obstack, c);
++pp->buffer->line_length;
}
pp_maybe_wrap_text (pp, str, str + (str ? strlen (str) : 0));
}
+/* Maybe print out a whitespace if needed. */
+void
+pp_base_maybe_space (pretty_printer *pp)
+{
+ if (pp_base (pp)->padding != pp_none)
+ {
+ pp_space (pp);
+ pp_base (pp)->padding = pp_none;
+ }
+}
/* Various declarations for language-independent pretty-print subroutines.
- Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#ifndef GCC_PRETTY_PRINT_H
#define GCC_PRETTY_PRINT_H
#include "obstack.h"
#include "input.h"
+/* Maximum number of format string arguments. */
+#define PP_NL_ARGMAX 30
+
/* 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 */
+ location_t *locus;
} text_info;
/* How often diagnostics are prefixed by their locations:
DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE = 0x2
} diagnostic_prefixing_rule_t;
+/* The chunk_info data structure forms a stack of the results from the
+ first phase of formatting (pp_base_format) which have not yet been
+ output (pp_base_output_formatted_text). A stack is necessary because
+ the diagnostic starter may decide to generate its own output by way
+ of the formatter. */
+struct chunk_info
+{
+ /* Pointer to previous chunk on the stack. */
+ struct chunk_info *prev;
+
+ /* Array of chunks to output. Each chunk is a NUL-terminated string.
+ In the first phase of formatting, even-numbered chunks are
+ to be output verbatim, odd-numbered chunks are format specifiers.
+ The second phase replaces all odd-numbered chunks with formatted
+ text, and the third phase simply emits all the chunks in sequence
+ with appropriate line-wrapping. */
+ const char *args[PP_NL_ARGMAX * 2];
+};
+
/* 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;
+ /* Obstack where the text is built up. */
+ struct obstack formatted_obstack;
+
+ /* Obstack containing a chunked representation of the format
+ specification plus arguments. */
+ struct obstack chunk_obstack;
+
+ /* Currently active obstack: one of the above two. This is used so
+ that the text formatters don't need to know which phase we're in. */
+ struct obstack *obstack;
+
+ /* Stack of chunk arrays. These come from the chunk_obstack. */
+ struct chunk_info *cur_chunk_array;
/* Where to output formatted text. */
FILE *stream;
pp_none, pp_before, pp_after
} pp_padding;
+/* Structure for switching in and out of verbatim mode in a convenient
+ manner. */
+typedef struct
+{
+ /* Current prefixing rule. */
+ diagnostic_prefixing_rule_t rule;
+
+ /* The ideal upper bound of number of characters per line, as suggested
+ by front-end. */
+ int line_cutoff;
+} pp_wrapping_mode_t;
+
+/* Maximum characters per line in automatic line wrapping mode.
+ Zero means don't wrap lines. */
+#define pp_line_cutoff(PP) pp_base (PP)->wrapping.line_cutoff
+
+/* Prefixing rule used in formatting a diagnostic message. */
+#define pp_prefixing_rule(PP) pp_base (PP)->wrapping.rule
+
+/* Get or set the wrapping mode as a single entity. */
+#define pp_wrapping_mode(PP) pp_base (PP)->wrapping
+
/* 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 *);
+typedef bool (*printer_fn) (pretty_printer *, text_info *, const char *,
+ int, bool, bool, bool);
/* Client supplied function used to decode formats. */
#define pp_format_decoder(PP) pp_base (PP)->format_decoder
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
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;
+ /* Current wrapping mode. */
+ pp_wrapping_mode_t wrapping;
/* 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
#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(PP, TI) pp_base_format (pp_base (PP), TI)
+#define pp_output_formatted_text(PP) \
+ pp_base_output_formatted_text (pp_base (PP))
#define pp_format_verbatim(PP, TI) \
pp_base_format_verbatim (pp_base (PP), TI)
} while (0)
#define pp_maybe_newline_and_indent(PP, N) \
if (pp_needs_newline (PP)) pp_newline_and_indent (PP, N)
+#define pp_maybe_space(PP) pp_base_maybe_space (pp_base (PP))
#define pp_separate_with(PP, C) \
do { \
pp_character (PP, C); \
#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_widest_integer(PP, I) \
+ pp_scalar (PP, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) I)
#define pp_pointer(PP, P) pp_scalar (PP, "%p", P)
#define pp_identifier(PP, ID) pp_string (PP, ID)
IDENTIFIER_POINTER (T) + IDENTIFIER_LENGTH (T))
#define pp_unsupported_tree(PP, T) \
- pp_verbatim (pp_base (PP), "#`%s' not supported by %s#", \
+ pp_verbatim (pp_base (PP), "#%qs not supported by %s#", \
tree_code_name[(int) TREE_CODE (T)], __FUNCTION__)
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 *, ...);
+
+/* This header may be included before toplev.h, hence the duplicate
+ definitions to allow for GCC-specific formats. */
+#if GCC_VERSION >= 3005
+#define ATTRIBUTE_GCC_PPDIAG(m, n) __attribute__ ((__format__ (__gcc_diag__, m ,n))) ATTRIBUTE_NONNULL(m)
+#else
+#define ATTRIBUTE_GCC_PPDIAG(m, n) ATTRIBUTE_NONNULL(m)
+#endif
+extern void pp_printf (pretty_printer *, const char *, ...)
+ ATTRIBUTE_GCC_PPDIAG(2,3);
+
+extern void pp_verbatim (pretty_printer *, const char *, ...)
+ ATTRIBUTE_GCC_PPDIAG(2,3);
extern void pp_base_flush (pretty_printer *);
-extern void pp_base_format_text (pretty_printer *, text_info *);
+extern void pp_base_format (pretty_printer *, text_info *);
+extern void pp_base_output_formatted_text (pretty_printer *);
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 *);
+extern void pp_write_text_to_stream (pretty_printer *pp);
+extern void pp_base_maybe_space (pretty_printer *);
+
+/* Switch into verbatim mode and return the old mode. */
+static inline pp_wrapping_mode_t
+pp_set_verbatim_wrapping_ (pretty_printer *pp)
+{
+ pp_wrapping_mode_t oldmode = pp_wrapping_mode (pp);
+ pp_line_cutoff (pp) = 0;
+ pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_NEVER;
+ return oldmode;
+}
+#define pp_set_verbatim_wrapping(PP) pp_set_verbatim_wrapping_ (pp_base (PP))
#endif /* GCC_PRETTY_PRINT_H */
/* C/ObjC/C++ command line option handling.
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by Neil Booth.
This file is part of GCC.
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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "c-incpath.h"
#include "opts.h"
#include "options.h"
+#include "mkdeps.h"
#ifndef DOLLARS_IN_IDENTIFIERS
# define DOLLARS_IN_IDENTIFIERS true
/* If -Wunused-macros. */
static bool warn_unused_macros;
+/* If -Wvariadic-macros. */
+static bool warn_variadic_macros = true;
+
/* Number of deferred options. */
static size_t deferred_count;
case OPT_idirafter:
case OPT_isysroot:
case OPT_isystem:
+ case OPT_iquote:
error ("missing path after \"%s\"", opt);
break;
unsigned int
sdcpp_common_init_options (unsigned int argc, const char **argv ATTRIBUTE_UNUSED)
{
- parse_in = cpp_create_reader (CLK_GNUC89, NULL);
+ parse_in = cpp_create_reader (CLK_GNUC89, NULL, &line_table);
cpp_opts = cpp_get_options (parse_in);
cpp_opts->dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
before passing on command-line options to cpplib. */
cpp_opts->warn_dollars = 0;
- deferred_opts = xmalloc (argc * sizeof (struct deferred_opt));
+ deferred_opts = XNEWVEC (struct deferred_opt, argc);
return CL_SDCPP;
}
case OPT_I:
if (strcmp (arg, "-"))
- add_path (xstrdup (arg), BRACKET, 0);
+ add_path (xstrdup (arg), BRACKET, 0, true);
else
{
if (quote_chain_split)
error ("-I- specified twice");
quote_chain_split = true;
split_quote_chain ();
+ inform ("obsolete option -I- used, please use -iquote instead");
}
break;
case OPT_Werror:
cpp_opts->warnings_are_errors = value;
+ global_dc->warning_as_error_requested = value;
break;
case OPT_Wimport:
cpp_opts->warn_system_headers = value;
break;
+ case OPT_Wtraditional:
+ cpp_opts->warn_traditional = value;
+ break;
+
case OPT_Wtrigraphs:
cpp_opts->warn_trigraphs = value;
break;
warn_unused_macros = value;
break;
+ case OPT_Wvariadic_macros:
+ warn_variadic_macros = value;
+ break;
+
case OPT_ansi:
set_std_c89 (false, true);
break;
case OPT_fpch_deps:
cpp_opts->restore_pch_deps = value;
break;
+
+ case OPT_fpch_preprocess:
+ flag_pch_preprocess = value;
+ break;
#endif
case OPT_fpreprocessed:
break;
case OPT_idirafter:
- add_path (xstrdup (arg), AFTER, 0);
+ add_path (xstrdup (arg), AFTER, 0, true);
break;
case OPT_imacros:
iprefix = arg;
break;
+ case OPT_iquote:
+ add_path (xstrdup (arg), QUOTE, 0, true);
+ break;
+
case OPT_isysroot:
sysroot = arg;
break;
case OPT_isystem:
- add_path (xstrdup (arg), SYSTEM, 0);
+ add_path (xstrdup (arg), SYSTEM, 0, true);
break;
case OPT_iwithprefix:
cpp_opts->pedantic_parse_number = 1;
break;
+#if 0 // pch not supported by sdcpp
+ case OPT_print_pch_checksum:
+ c_common_print_pch_checksum (stdout);
+ exit_after_options = true;
+ break;
+#endif
+
case OPT_remap:
cpp_opts->remap = 1;
break;
/* Canonicalize the input and output filenames. */
if (in_fnames == NULL)
{
- in_fnames = xmalloc (sizeof (in_fnames[0]));
+ in_fnames = XNEWVEC (const char *, 1);
in_fnames[0] = "";
}
else if (strcmp (in_fnames[0], "-") == 0)
cb->dir_change = cb_dir_change;
cpp_post_options (parse_in);
- saved_lineno = input_line;
- input_line = 0;
+ input_location = UNKNOWN_LOCATION;
/* If an error has occurred in cpplib, note it so we fail
immediately. */
return false;
}
- if (flag_working_directory && ! flag_no_line_commands)
+ if (flag_working_directory && !flag_no_line_commands)
pp_dir_change (parse_in, get_src_pwd ());
return 1;
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);
are known. */
cpp_init_iconv (parse_in);
+#if 0
+ if (version_flag)
+ c_common_print_pch_checksum (stderr);
+#endif
+
finish_options ();
preprocess_file (parse_in);
return false;
deps_file = spec;
deps_append = 1;
+ deps_seen = true;
}
}
handle_deferred_opts (void)
{
size_t i;
+ struct deps *deps;
+
+ /* Avoid allocating the deps buffer if we don't need it.
+ (This flag may be true without there having been -MT or -MQ
+ options, but we'll still need the deps buffer.) */
+ if (!deps_seen)
+ return;
+
+ deps = cpp_get_deps (parse_in);
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);
+ deps_add_target (deps, opt->arg, opt->code == OPT_MQ);
}
}
cpp_opts->unsigned_char = !flag_signed_char;
cpp_opts->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS;
+ /* Similarly with -Wno-variadic-macros. No check for c99 here, since
+ this also turns off warnings about GCCs extension. */
+ cpp_opts->warn_variadic_macros
+ = warn_variadic_macros && (pedantic || warn_traditional);
+
/* If we're generating preprocessor output, emit current directory
if explicitly requested */
if (flag_working_directory == -1)
prefix = iprefix ? iprefix : cpp_GCC_INCLUDE_DIR;
prefix_len = iprefix ? strlen (iprefix) : cpp_GCC_INCLUDE_DIR_len;
- path = xmalloc (prefix_len + suffix_len + 1);
+ path = (char *) 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);
+ add_path (path, chain, 0, false);
}
/* Handle -D, -U, -A, -imacros, and the first -include. */
{
size_t i;
- cpp_change_file (parse_in, LC_RENAME, _("<built-in>"));
+ cb_file_change (parse_in,
+ linemap_add (&line_table, LC_RENAME, 0,
+ _("<built-in>"), 0));
+
cpp_init_builtins (parse_in, 0 /*flag_hosted*/);
/* We're about to send user input to cpplib, so make it warn for
{
struct deferred_opt *opt = &deferred_opts[include_cursor++];
- if (! cpp_opts->preprocessed && opt->code == OPT_include
+ if (!cpp_opts->preprocessed && opt->code == OPT_include
&& cpp_push_include (parse_in, opt->arg))
return;
}
/* -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);
+ if (!cpp_opts->preprocessed)
+ cpp_change_file (parse_in, LC_RENAME, this_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;
+ line_table.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,
+cb_file_change (cpp_reader * ARG_UNUSED (pfile),
const struct line_map *new_map)
{
pp_file_change (new_map);
}
void
-cb_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir)
+cb_dir_change (cpp_reader * ARG_UNUSED (pfile), const char *dir)
{
- if (! set_src_pwd (dir))
- warning ("too late for # directive to set debug directory");
+ if (!set_src_pwd (dir))
+ warning (0, "too late for # directive to set debug directory");
}
/* Set the C 89 standard (with 1994 amendments if C94, without GNU
#include "config.h"
#include "system.h"
#include "cpplib.h"
-#include "cpphash.h"
+#include "internal.h"
#include "version.h"
#include "mkdeps.h"
#include "opts.h"
const char *main_input_filename;
+#ifndef USE_MAPPED_LOCATION
+location_t unknown_location = { NULL, 0 };
+#endif
+
/* Current position in real source file. */
location_t input_location;
+struct line_maps line_table;
+
/* Stack of currently pending input files. */
struct file_stack *input_file_stack;
be called with a NULL argument to test whether src_pwd has NOT been
initialized yet. */
+/* From intl.c */
+/* Opening quotation mark for diagnostics. */
+const char *open_quote = "'";
+
+/* Closing quotation mark for diagnostics. */
+const char *close_quote = "'";
+/* ----------- */
+
bool
set_src_pwd (const char *pwd)
{
break;
default:
- warning ("unrecognized gcc debugging option: %c", c);
+ warning (0, "unrecognized gcc debugging option: %c", c);
break;
}
}
# 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" /I ".\win32" /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" /I ".\sdcpp" /I ".\sdcpp\include" /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
# 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" /I ".\win32" /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" /I ".\sdcpp" /I ".\sdcpp\include" /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
# Name "sdcpp - Win32 Release"\r
# Begin Group "Source Files"\r
\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Group "libcpp"\r
+\r
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
# Begin Source File\r
\r
-SOURCE=".\c-incpath.c"\r
+SOURCE=.\libcpp\charset.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=".\c-ppoutput.c"\r
+SOURCE=.\libcpp\directives.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\concat.c\r
+SOURCE=.\libcpp\errors.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cppcharset.c\r
+SOURCE=.\libcpp\expr.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cppdefault.c\r
+SOURCE=.\libcpp\files.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cpperror.c\r
+SOURCE=.\libcpp\identifiers.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cppexp.c\r
+SOURCE=.\libcpp\init.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cppfiles.c\r
+SOURCE=.\libcpp\internal.h\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cpphash.c\r
+SOURCE=.\libcpp\lex.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cppinit.c\r
+SOURCE=".\libcpp\line-map.c"\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cpplex.c\r
+SOURCE=.\libcpp\macro.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cpplib.c\r
+SOURCE=.\libcpp\makeucnid.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cppmacro.c\r
+SOURCE=.\libcpp\mkdeps.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\cpptrad.c\r
+SOURCE=.\libcpp\symtab.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\diagnostic.c\r
+SOURCE=.\libcpp\system.h\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\win32\dirent.c\r
+SOURCE=.\libcpp\traditional.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\getpwd.c\r
+SOURCE=.\libcpp\ucnid.h\r
# End Source File\r
+# End Group\r
+# Begin Group "libiberty"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
# Begin Source File\r
\r
-SOURCE=.\hashtab.c\r
+SOURCE=.\libiberty\concat.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\hashtable.c\r
+SOURCE=.\libiberty\getpwd.c\r
# End Source File\r
# Begin Source File\r
\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=".\line-map.c"\r
+SOURCE=.\libiberty\obstack.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\mkdeps.c\r
+SOURCE=".\libiberty\safe-ctype.c"\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\obstack.c\r
+SOURCE=".\libiberty\splay-tree.c"\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\options.c\r
+SOURCE=.\libiberty\vasprintf.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\opts.c\r
+SOURCE=.\libiberty\xexit.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\prefix.c\r
+SOURCE=.\libiberty\xmalloc.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=".\pretty-print.c"\r
+SOURCE=.\libiberty\xmemdup.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=".\libiberty\safe-ctype.c"\r
+SOURCE=.\libiberty\xstrdup.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=".\sdcpp-opts.c"\r
+SOURCE=.\libiberty\xstrerror.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "win32"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\win32\dirent.c\r
# End Source File\r
+# End Group\r
# Begin Source File\r
\r
-SOURCE=.\sdcpp.c\r
+SOURCE=".\c-incpath.c"\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=".\libiberty\splay-tree.c"\r
+SOURCE=".\c-ppoutput.c"\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\vasprintf.c\r
+SOURCE=.\cppdefault.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\version.c\r
+SOURCE=.\diagnostic.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\xexit.c\r
+SOURCE=.\options.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\xmalloc.c\r
+SOURCE=.\opts.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\xmemdup.c\r
+SOURCE=.\prefix.c\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\xstrdup.c\r
+SOURCE=".\pretty-print.c"\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\libiberty\xstrerror.c\r
+SOURCE=".\sdcpp-opts.c"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\sdcpp.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\version.c\r
# End Source File\r
# End Group\r
# Begin Group "Header Files"\r
#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. */
#else
#define ATTRIBUTE_GCC_DIAG(m, n) ATTRIBUTE_NONNULL(m)
#endif
-extern void warning (const char *, ...);
-extern void error (const char *, ...);
+/* 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 >= 4001
+#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 internal_error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2)
+ ATTRIBUTE_NORETURN;
+extern void warning0 (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
+/* Pass one of the OPT_W* from options.h as the first parameter. */
+extern void warning (int, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
+extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
extern void fatal_error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2)
ATTRIBUTE_NORETURN;
+extern void pedwarn (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
+extern void sorry (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
+extern void inform (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
+extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
#ifdef BUFSIZ
/* N.B. Unlike all the others, fnotice is just gettext+fprintf, and
extern int flag_pedantic_errors;
-/* Don't print warning messages. -w. */
-
-extern bool inhibit_warnings;
-
/*
* From c-common.h
*/
+#include "hwint.h"
#include "cpplib.h"
/* Nonzero means don't output line number information. */
; Options for the SDCPP front end.
-; Copyright (C) 2003 Free Software Foundation, Inc.
+; Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
;
; This file is part of GCC.
;
;
; 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 is processed by the script opts.sh. It is a database of
-; command line options, with each record separated by a blank line,
-; and each field appearing on its own line. The first field is the
-; command-line switch with the leading "-" removed. All options
-; beginning with "f" or "W" are implicitly assumed to take a "no-"
-; form; this form should not be listed. If you do not want this
-; negative form and you want it to be automatically rejected, add
-; RejectNegative to the second field.
-
-; The second field is a space-separated list of which parts of the
-; compiler recognize the switch, as declared by "Language" entries.
-; If the switch takes an argument, then you should also specify
-; "Joined" and/or "Separate" to indicate where the argument can
-; appear. If a Joined argument can legitimately be omitted, specify
-; "JoinedOrMissing" instead of "Joined". If the argument to a switch
-; is a non-negative integer, you can specify "UInteger" and the switch
-; decoder will convert the argument for you, or complain to the user
-; if the argument is invalid.
-
-; The third field is the help text to output with --help. This is
-; automatically line-wrapped on output. Normally the switch is output
-; automatically, with the help text on the right hand side of the
-; output. However, if the help text contains a tab character, the
-; text to the left of the tab is output instead of the switch, and the
-; text to its right forms the help. This is useful for elaborating on
-; what type of argument a switch takes, for example. If the second
-; field contains "Undocumented" then nothing is output with --help.
-; Only do this with good reason like the switch being internal between
-; the driver and the front end - it is not an excuse to leave a switch
-; undocumented.
-
-; Comments can appear on their own line anwhere in the file, preceded
-; by a semicolon. Whitespace is permitted before the semicolon.
-
-; For each switch XXX below, an enumeration constant is created by the
-; script opts.sh spelt OPT_XXX, but with all non-alphanumeric
-; characters replaced with an underscore.
+; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA.
+
+; See the GCC internals manual for a description of this file's format.
; Please try to keep this file in ASCII collating order.
SDCPP
Treat all warnings as errors
+Wfatal-errors
+SDCPP Var(flag_fatal_errors)
+Exit on the first error occurred
+
Wimport
SDCPP
Deprecated. This switch has no effect.
SDCPP
Do not suppress warnings from system headers
+Wtraditional
+SDCPP Var(warn_traditional)
+Warn about features not present in traditional C
+
Wtrigraphs
SDCPP
Warn if trigraphs are encountered that might affect the meaning of the program
SDCPP
Warn about macros defined in the main file that are not used
+Wvariadic-macros
+SDCPP
+Do not warn about using variadic macros when -pedantic
+
ansi
SDCPP
A synonym for -std=c89.
SDCPP Joined Separate
-isystem <dir> Add <dir> to the start of the system include path
+iquote
+SDCPP Joined Separate
+-iquote <dir> Add <dir> to the end of the quote include path
+
iwithprefix
SDCPP Joined Separate
-iwithprefix <dir> Add <dir> to the end of the system include path
-obj-ext=<extension> Define object file extension, used for generation of make dependencies
pedantic
-SDCPP
+SDCPP Var(pedantic)
Issue warnings needed for strict compliance to the standard
pedantic-errors
SDCPP
Enable verbose output
+;***version
+;***SDCPP Var(version_flag)
+;***Display the compiler's version
+
w
-SDCPP
+SDCPP Var(inhibit_warnings)
Suppress warnings
; This comment is to ensure we retain the blank line above.
!IF "$(CFG)" == "sdcppa - Win32 Release"\r
\r
# Begin Custom Build\r
-InputPath=.\auto-host_vc_in.h\r
+InputPath=".\auto-host_vc_in.h"\r
\r
"auto-host.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
copy auto-host_vc_in.h auto-host.h > nul\r
!ELSEIF "$(CFG)" == "sdcppa - Win32 Debug"\r
\r
# Begin Custom Build\r
-InputPath=.\auto-host_vc_in.h\r
+InputPath=".\auto-host_vc_in.h"\r
\r
"auto-host.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
copy auto-host_vc_in.h auto-host.h > nul\r
# End Source File\r
# Begin Source File\r
\r
-SOURCE=.\options_vc_in.c\r
+SOURCE=.\sdcpp.opt\r
\r
!IF "$(CFG)" == "sdcppa - Win32 Release"\r
\r
# Begin Custom Build\r
-InputPath=.\options_vc_in.c\r
+InputPath=.\sdcpp.opt\r
\r
-"options.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
- copy options_vc_in.c options.c > nul\r
-\r
-# End Custom Build\r
-\r
-!ELSEIF "$(CFG)" == "sdcppa - Win32 Debug"\r
-\r
-# Begin Custom Build\r
-InputPath=.\options_vc_in.c\r
+BuildCmds= \\r
+ gawk -f opt-gather.awk sdcpp.opt | gawk -f opt-functions.awk -f optc-gen.awk -v header_name="config.h system.h options.h" > options.c \\r
+ gawk -f opt-gather.awk sdcpp.opt | gawk -f opt-functions.awk -f opth-gen.awk > options.h \\r
+ \r
\r
"options.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
- copy options_vc_in.c options.c > nul\r
-\r
-# End Custom Build\r
-\r
-!ENDIF \r
-\r
-# End Source File\r
-# Begin Source File\r
-\r
-SOURCE=.\options_vc_in.h\r
-\r
-!IF "$(CFG)" == "sdcppa - Win32 Release"\r
-\r
-# Begin Custom Build\r
-InputPath=.\options_vc_in.h\r
+ $(BuildCmds)\r
\r
"options.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
- copy options_vc_in.h options.h > nul\r
-\r
+ $(BuildCmds)\r
# End Custom Build\r
\r
!ELSEIF "$(CFG)" == "sdcppa - Win32 Debug"\r
\r
# Begin Custom Build\r
-InputPath=.\options_vc_in.h\r
+InputPath=.\sdcpp.opt\r
\r
-"options.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
- copy options_vc_in.h options.h > nul\r
+BuildCmds= \\r
+ gawk -f opt-gather.awk sdcpp.opt | gawk -f opt-functions.awk -f optc-gen.awk -v header_name="config.h system.h options.h" > options.c \\r
+ gawk -f opt-gather.awk sdcpp.opt | gawk -f opt-functions.awk -f opth-gen.awk > options.h \\r
+ \r
\r
+"options.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+ $(BuildCmds)\r
+\r
+"options.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"\r
+ $(BuildCmds)\r
# End Custom Build\r
\r
!ENDIF \r
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. */
+ 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
#ifndef SYM_CAT_H
#define SYM_CAT_H
+++ /dev/null
-/* Get common system includes and various definitions and declarations based
- on autoconf macros.
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
- 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_SYSTEM_H
-#define GCC_SYSTEM_H
-
-/* We must include stdarg.h before stdio.h. */
-#include <stdarg.h>
-
-#ifndef va_copy
-# ifdef __va_copy
-# define va_copy(d,s) __va_copy((d),(s))
-# else
-# define va_copy(d,s) ((d) = (s))
-# endif
-#endif
-
-#ifdef HAVE_STDDEF_H
-# include <stddef.h>
-#endif
-
-#include <stdio.h>
-
-/* 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. */
-#if defined(__APPLE__) && defined(__MACH__)
-#include <libiberty/safe-ctype.h>
-#else
-#include <safe-ctype.h>
-#endif
-
-#include <sys/types.h>
-
-#include <errno.h>
-
-#if !defined (errno) && defined (HAVE_DECL_ERRNO) && !HAVE_DECL_ERRNO
-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>
-#else
-# ifdef HAVE_STRING_H
-# include <string.h>
-# else
-# ifdef HAVE_STRINGS_H
-# include <strings.h>
-# endif
-# endif
-#endif
-
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-
-/* If we don't have an overriding definition, set SUCCESS_EXIT_CODE and
- FATAL_EXIT_CODE to EXIT_SUCCESS and EXIT_FAILURE respectively,
- or 0 and 1 if those macros are not defined. */
-#ifndef SUCCESS_EXIT_CODE
-# ifdef EXIT_SUCCESS
-# define SUCCESS_EXIT_CODE EXIT_SUCCESS
-# else
-# define SUCCESS_EXIT_CODE 0
-# endif
-#endif
-
-#ifndef FATAL_EXIT_CODE
-# ifdef EXIT_FAILURE
-# define FATAL_EXIT_CODE EXIT_FAILURE
-# else
-# define FATAL_EXIT_CODE 1
-# endif
-#endif
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-/* We use this identifier later and it appears in some vendor param.h's. */
-# undef PREFETCH
-#endif
-
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-/* Get definitions of HOST_WIDE_INT and HOST_WIDEST_INT. */
-#include "hwint.h"
-
-/* A macro to determine whether a VALUE lies inclusively within a
- certain range without evaluating the VALUE more than once. This
- macro won't warn if the VALUE is unsigned and the LOWER bound is
- zero, as it would e.g. with "VALUE >= 0 && ...". Note the LOWER
- bound *is* evaluated twice, and LOWER must not be greater than
- UPPER. However the bounds themselves can be either positive or
- negative. */
-#define IN_RANGE(VALUE, LOWER, UPPER) \
- ((unsigned HOST_WIDE_INT) ((VALUE) - (LOWER)) <= ((UPPER) - (LOWER)))
-
-/* Infrastructure for defining missing _MAX and _MIN macros. Note that
- macros defined with these cannot be used in #if. */
-
-/* The extra casts work around common compiler bugs. */
-#define INTTYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
- It is necessary at least when t == time_t. */
-#define INTTYPE_MINIMUM(t) ((t) (INTTYPE_SIGNED (t) \
- ? ~ (t) 0 << (sizeof(t) * CHAR_BIT - 1) : (t) 0))
-#define INTTYPE_MAXIMUM(t) ((t) (~ (t) 0 - INTTYPE_MINIMUM (t)))
-
-/* Use that infrastructure to provide a few constants. */
-#ifndef UCHAR_MAX
-# define UCHAR_MAX INTTYPE_MAXIMUM (unsigned char)
-#endif
-
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# ifdef HAVE_TIME_H
-# include <time.h>
-# endif
-# endif
-#endif
-
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#else
-# ifdef HAVE_SYS_FILE_H
-# include <sys/file.h>
-# endif
-#endif
-
-#ifndef SEEK_SET
-# define SEEK_SET 0
-# define SEEK_CUR 1
-# define SEEK_END 2
-#endif
-#ifndef F_OK
-# define F_OK 0
-# define X_OK 1
-# define W_OK 2
-# define R_OK 4
-#endif
-#ifndef O_RDONLY
-# define O_RDONLY 0
-#endif
-#ifndef O_WRONLY
-# define O_WRONLY 1
-#endif
-
-/* Some systems define these in, e.g., param.h. We undefine these names
- here to avoid the warnings. We prefer to use our definitions since we
- know they are correct. */
-
-#undef MIN
-#undef MAX
-#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
-#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
-
-/* Returns the least number N such that N * Y >= X. */
-#define CEIL(x,y) (((x) + (y) - 1) / (y))
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#ifndef WIFSIGNALED
-#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
-#endif
-#ifndef WTERMSIG
-#define WTERMSIG(S) ((S) & 0x7f)
-#endif
-#ifndef WIFEXITED
-#define WIFEXITED(S) (((S) & 0xff) == 0)
-#endif
-#ifndef WEXITSTATUS
-#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
-#endif
-#ifndef WSTOPSIG
-#define WSTOPSIG WEXITSTATUS
-#endif
-#ifndef WCOREDUMP
-#define WCOREDUMP(S) ((S) & WCOREFLG)
-#endif
-#ifndef WCOREFLG
-#define WCOREFLG 0200
-#endif
-
-/* The HAVE_DECL_* macros are three-state, undefined, 0 or 1. If they
- are defined to 0 then we must provide the relevant declaration
- here. These checks will be in the undefined state while configure
- is running so be careful to test "defined (HAVE_DECL_*)". */
-
-#if defined (HAVE_DECL_ATOF) && !HAVE_DECL_ATOF
-extern double atof (const char *);
-#endif
-
-#if defined (HAVE_DECL_ATOL) && !HAVE_DECL_ATOL
-extern long atol (const char *);
-#endif
-
-#if defined (HAVE_DECL_FREE) && !HAVE_DECL_FREE
-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 (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 (const char *, const char *);
-#endif
-
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-
-#if defined (HAVE_DECL_MALLOC) && !HAVE_DECL_MALLOC
-extern void *malloc (size_t);
-#endif
-
-#if defined (HAVE_DECL_CALLOC) && !HAVE_DECL_CALLOC
-extern void *calloc (size_t, size_t);
-#endif
-
-#if defined (HAVE_DECL_REALLOC) && !HAVE_DECL_REALLOC
-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. */
-/* Disabled since it causes errors on solaris
-#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
-
-#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 (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. */
-#if !defined(HAVE_DESIGNATED_INITIALIZERS)
-#if defined(__APPLE__) && (__MACH__)
-#define HAVE_DESIGNATED_INITIALIZERS 0
-#else
-#define HAVE_DESIGNATED_INITIALIZERS \
- ((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L))
-#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
-
-/* Test if something is a normal file. */
-#ifndef S_ISREG
-#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-
-/* Test if something is a directory. */
-#ifndef S_ISDIR
-#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-
-/* Test if something is a character special file. */
-#ifndef S_ISCHR
-#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
-#endif
-
-/* Test if something is a block special file. */
-#ifndef S_ISBLK
-#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
-#endif
-
-/* Test if something is a socket. */
-#ifndef S_ISSOCK
-# ifdef S_IFSOCK
-# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
-# else
-# define S_ISSOCK(m) 0
-# endif
-#endif
-
-/* Test if something is a FIFO. */
-#ifndef S_ISFIFO
-# ifdef S_IFIFO
-# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
-# else
-# define S_ISFIFO(m) 0
-# endif
-#endif
-
-/* Approximate O_NONBLOCK. */
-#ifndef O_NONBLOCK
-#define O_NONBLOCK O_NDELAY
-#endif
-
-/* Approximate O_NOCTTY. */
-#ifndef O_NOCTTY
-#define O_NOCTTY 0
-#endif
-
-/* Define well known filenos if the system does not define them. */
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-#ifndef STDERR_FILENO
-# define STDERR_FILENO 2
-#endif
-
-/* Some systems have mkdir that takes a single argument. */
-#ifdef MKDIR_TAKES_ONE_ARG
-# define mkdir(a,b) mkdir(a)
-#endif
-
-/* Provide a way to print an address via printf. */
-#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 "%llx"
-# endif
-#endif /* ! HOST_PTR_PRINTF */
-
-/* By default, colon separates directories in a path. */
-#ifndef PATH_SEPARATOR
-#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 '/'
-# ifdef HAVE_DOS_BASED_FILE_SYSTEM
-# define DIR_SEPARATOR_2 '\\'
-# endif
-#endif
-
-/* Get libiberty declarations. */
-#include "libiberty.h"
-
-/* Provide a default for the HOST_BIT_BUCKET.
- This suffices for POSIX-like hosts. */
-
-#ifndef HOST_BIT_BUCKET
-#define HOST_BIT_BUCKET "/dev/null"
-#endif
-
-/* Be conservative and only use enum bitfields with GCC.
- FIXME: provide a complete autoconf test for buggy enum bitfields. */
-
-#if (GCC_VERSION > 2000)
-#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
-#else
-#define ENUM_BITFIELD(TYPE) unsigned int
-#endif
-
-/* 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
-
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER)
-#endif
-
-/* Various error reporting routines want to use __FUNCTION__. */
-#if (GCC_VERSION < 2007)
-#ifndef __FUNCTION__
-#define __FUNCTION__ "?"
-#endif /* ! __FUNCTION__ */
-#endif
-
-/* __builtin_expect(A, B) evaluates to A, but notifies the compiler that
- the most likely value of A is B. This feature was added at some point
- between 2.95 and 3.0. Let's use 3.0 as the lower bound for now. */
-#if (GCC_VERSION < 3000)
-#define __builtin_expect(a, b) (a)
-#endif
-
-/* Provide some sort of boolean type. We use stdbool.h if it's
- available. This must be after all inclusion of system headers,
- as some of them will mess us up. */
-#undef bool
-#undef true
-#undef false
-#undef TRUE
-#undef FALSE
-
-#ifdef HAVE_STDBOOL_H
-# include <stdbool.h>
-#else
-# if !HAVE__BOOL
-typedef char _Bool;
-# endif
-# define bool _Bool
-# define true 1
-# define false 0
-#endif
-
-#define TRUE true
-#define FALSE false
-
-/* As the last action in this file, we poison the identifiers that
- shouldn't be used. Note, luckily gcc-3.0's token-based integrated
- preprocessor won't trip on poisoned identifiers that arrive from
- the expansion of macros. E.g. #define strrchr rindex, won't error
- if rindex is poisoned after this directive is issued and later on
- strrchr is called.
-
- Note: We define bypass macros for the few cases where we really
- want to use the libc memory allocation routines. Otherwise we
- insist you use the "x" versions from libiberty. */
-
-#define really_call_malloc malloc
-#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
- system.h while doing so. Only poison these tokens if actually
- compiling gcc, so that the autoconf declaration tests for malloc
- etc don't spuriously fail. */
-#ifdef IN_GCC
-#undef calloc
-#undef strdup
- #pragma GCC poison calloc strdup
-
-#if !defined(FLEX_SCANNER) && !defined(YYBISON)
-#undef malloc
-#undef realloc
- #pragma GCC poison malloc realloc
-#endif
-
-/* Old target macros that have moved to the target hooks structure. */
- #pragma GCC poison ASM_OPEN_PAREN ASM_CLOSE_PAREN \
- FUNCTION_PROLOGUE FUNCTION_EPILOGUE \
- FUNCTION_END_PROLOGUE FUNCTION_BEGIN_EPILOGUE \
- DECL_MACHINE_ATTRIBUTES COMP_TYPE_ATTRIBUTES INSERT_ATTRIBUTES \
- VALID_MACHINE_DECL_ATTRIBUTE VALID_MACHINE_TYPE_ATTRIBUTE \
- SET_DEFAULT_TYPE_ATTRIBUTES SET_DEFAULT_DECL_ATTRIBUTES \
- MERGE_MACHINE_TYPE_ATTRIBUTES MERGE_MACHINE_DECL_ATTRIBUTES \
- MD_INIT_BUILTINS MD_EXPAND_BUILTIN ASM_OUTPUT_CONSTRUCTOR \
- 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 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 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 \
- STDC_VALUE TRAMPOLINE_ALIGN ASM_IDENTIFY_GCC_AFTER_SOURCE \
- SLOW_ZERO_EXTEND SUBREG_REGNO_OFFSET DWARF_LINE_MIN_INSTR_LENGTH \
- TRADITIONAL_RETURN_FLOAT NO_BUILTIN_SIZE_TYPE \
- NO_BUILTIN_PTRDIFF_TYPE NO_BUILTIN_WCHAR_TYPE NO_BUILTIN_WINT_TYPE \
- 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_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_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
- structure members) have been eliminated. */
-#undef bcopy
-#undef bzero
-#undef bcmp
-#undef rindex
- #pragma GCC poison bcopy bzero bcmp rindex
-
-#endif /* GCC >= 3.0 */
-
-/* SDCC specific */
-#include "sdcpp.h"
-
-#endif /* ! GCC_SYSTEM_H */
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.4.6 + SDCC";
+const char version_string[] = "4.1.1 + SDCC";
/* This is the location of the online document giving instructions for
reporting bugs. If you distribute a modified version of GCC,