/* C Compatible Compiler Preprocessor (CCCP)
- Copyright (C) 1986, 87, 89, 92-96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1986, 87, 89, 92-98, 1999 Free Software Foundation, Inc.
Written by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <signal.h>
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-#endif
-#endif
+#include "system.h"
+#include <signal.h>
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
-#if HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
-
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#include <errno.h>
-
-#if HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#endif
-
typedef unsigned char U_CHAR;
-#include "gansidecl.h"
#include "pcp.h"
+#include "intl.h"
+#include "prefix.h"
-#ifdef NEED_DECLARATION_INDEX
-extern char *index ();
-#endif
-
-#ifdef NEED_DECLARATION_RINDEX
-extern char *rindex ();
-#endif
-
-#ifdef NEED_DECLARATION_GETENV
-extern char *getenv ();
-#endif
+#ifdef MULTIBYTE_CHARS
+#include "mbchar.h"
+#include <locale.h>
+#endif /* MULTIBYTE_CHARS */
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
-# define __attribute__(x)
+#ifndef GET_ENV_PATH_LIST
+#define GET_ENV_PATH_LIST(VAR,NAME) do { (VAR) = getenv (NAME); } while (0)
#endif
#ifndef STANDARD_INCLUDE_DIR
# define PATH_SEPARATOR ':'
#endif
+/* By default, a slash separates directory names. */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+#endif
+
/* By default, the suffix for object files is ".o". */
#ifdef OBJECT_SUFFIX
# define HAVE_OBJECT_SUFFIX
# define OBJECT_SUFFIX ".o"
#endif
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-# include <stdarg.h>
-# define PRINTF_ALIST(msg) char *msg, ...
-# define PRINTF_DCL(msg)
-# define PRINTF_PROTO(ARGS, m, n) PROTO (ARGS) __attribute__ ((format (__printf__, m, n)))
-#else
-# include <varargs.h>
-# define PRINTF_ALIST(msg) msg, va_alist
-# define PRINTF_DCL(msg) char *msg; va_dcl
-# define PRINTF_PROTO(ARGS, m, n) () __attribute__ ((format (__printf__, m, n)))
-# define vfprintf(file, msg, args) \
- { \
- char *a0 = va_arg(args, char *); \
- char *a1 = va_arg(args, char *); \
- char *a2 = va_arg(args, char *); \
- char *a3 = va_arg(args, char *); \
- fprintf (file, msg, a0, a1, a2, a3); \
- }
-#endif
-
-#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
-#define PRINTF_PROTO_2(ARGS) PRINTF_PROTO(ARGS, 2, 3)
-#define PRINTF_PROTO_3(ARGS) PRINTF_PROTO(ARGS, 3, 4)
-
/* VMS-specific definitions */
#ifdef VMS
#include <descrip.h>
#define fopen(fname,mode) VMS_fopen (fname,mode)
#define freopen(fname,mode,ofile) VMS_freopen (fname,mode,ofile)
#define fstat(fd,stbuf) VMS_fstat (fd,stbuf)
+#define fwrite(ptr,size,nitems,stream) VMS_fwrite (ptr,size,nitems,stream)
static int VMS_fstat (), VMS_stat ();
static int VMS_open ();
static FILE *VMS_fopen ();
static FILE *VMS_freopen ();
+static size_t VMS_fwrite ();
static void hack_vms_include_specification ();
#define INO_T_EQ(a, b) (!bcmp((char *) &(a), (char *) &(b), sizeof (a)))
#define INO_T_HASH(a) 0
#endif /* VMS */
/* Windows does not natively support inodes, and neither does MSDOS. */
-#if (defined (_WIN32) && ! defined (CYGWIN32)) || defined (__MSDOS__)
+#if (defined (_WIN32) && ! defined (__CYGWIN__) && ! defined (_UWIN)) \
+ || defined (__MSDOS__)
#define INO_T_EQ(a, b) 0
#endif
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-
-#undef MIN
-#undef MAX
-#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
-#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
-
-/* Find the largest host integer type and set its size and type.
- Watch out: on some crazy hosts `long' is shorter than `int'. */
-
-#ifndef HOST_WIDE_INT
-# if HAVE_INTTYPES_H
-# include <inttypes.h>
-# define HOST_WIDE_INT intmax_t
-# else
-# if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)
-# define HOST_WIDE_INT int
-# else
-# if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG || ! (defined LONG_LONG_MAX || defined LLONG_MAX))
-# define HOST_WIDE_INT long
-# else
-# define HOST_WIDE_INT long long
-# endif
-# endif
-# endif
-#endif
-
-#ifndef S_ISREG
-#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-
-#ifndef S_ISDIR
-#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-
#ifndef INO_T_EQ
#define INO_T_EQ(a, b) ((a) == (b))
#endif
/* External declarations. */
extern char *version_string;
-extern char *update_path PROTO((char *, char *));
-#ifndef VMS
-#ifndef HAVE_STRERROR
-extern int sys_nerr;
-extern char *sys_errlist[];
-#else /* HAVE_STRERROR */
-char *strerror ();
-#endif
-#else /* VMS */
-char *strerror (int,...);
-#endif
-HOST_WIDE_INT parse_escape PROTO((char **, HOST_WIDE_INT));
-HOST_WIDE_INT parse_c_expression PROTO((char *, int));
-
-#ifndef errno
-extern int errno;
-#endif
+HOST_WIDEST_INT parse_escape PROTO((char **, HOST_WIDEST_INT));
+HOST_WIDEST_INT parse_c_expression PROTO((char *, int));
\f
/* Name under which this program was invoked. */
static int warn_undef;
+/* Nonzero means warn if we find white space where it doesn't belong. */
+
+static int warn_white_space;
+
/* Nonzero means warn if #import is used. */
static int warn_import = 1;
int c89;
+/* Nonzero for the 199x C Standard. */
+
+int c9x;
+
/* Nonzero causes output not to be done,
but directives such as #define that have side effects
are still obeyed. */
char *fname;
/* Filename specified with #line directive. */
char *nominal_fname;
+ /* The length of nominal_fname, which may contain embedded NULs. */
+ size_t nominal_fname_len;
/* Include file description. */
struct include_file *inc;
/* Record where in the search path this file was found.
int cxx_aware; /* Includes in this directory don't need to
be wrapped in extern "C" when compiling
C++. */
+ int included; /* Set if the directory is acceptable. */
} include_defaults_array[]
#ifdef INCLUDE_DEFAULTS
= INCLUDE_DEFAULTS;
#else
= {
/* Pick up GNU C++ specific include files. */
- { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },
- { OLD_GPLUSPLUS_INCLUDE_DIR, 0, 1, 1 },
+ { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1, 0 },
#ifdef CROSS_COMPILE
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
- { GCC_INCLUDE_DIR, "GCC", 0, 0 },
+ { GCC_INCLUDE_DIR, "GCC", 0, 0, 0 },
/* For cross-compilation, this dir name is generated
automatically in Makefile.in. */
- { CROSS_INCLUDE_DIR, "GCC", 0, 0 },
+ { CROSS_INCLUDE_DIR, "GCC", 0, 0, 0 },
#ifdef TOOL_INCLUDE_DIR
/* This is another place that the target system's headers might be. */
- { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0, 0 },
#endif
#else /* not CROSS_COMPILE */
#ifdef LOCAL_INCLUDE_DIR
/* This should be /usr/local/include and should come before
the fixincludes-fixed header files. */
- { LOCAL_INCLUDE_DIR, 0, 0, 1 },
+ { LOCAL_INCLUDE_DIR, 0, 0, 1, 0 },
#endif
#ifdef TOOL_INCLUDE_DIR
/* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.
Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */
- { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0, 0 },
#endif
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
- { GCC_INCLUDE_DIR, "GCC", 0, 0 },
+ { GCC_INCLUDE_DIR, "GCC", 0, 0, 0 },
/* Some systems have an extra dir of include files. */
#ifdef SYSTEM_INCLUDE_DIR
- { SYSTEM_INCLUDE_DIR, 0, 0, 0 },
+ { SYSTEM_INCLUDE_DIR, 0, 0, 0, 0 },
#endif
#ifndef STANDARD_INCLUDE_COMPONENT
#define STANDARD_INCLUDE_COMPONENT 0
#endif
- { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 },
+ { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0, 0 },
#endif /* not CROSS_COMPILE */
- { 0, 0, 0, 0 }
+ { 0, 0, 0, 0, 0 }
};
#endif /* no INCLUDE_DEFAULTS */
U_CHAR *expansion;
int line; /* Line number of definition */
char *file; /* File of definition */
+ size_t file_len; /* Length of file (which can contain NULs) */
char rest_args; /* Nonzero if last arg. absorbs the rest */
struct reflist {
struct reflist *next;
static char rest_extension[] = "...";
#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)
+/* This is the implicit parameter name when using variable number of
+ parameters for macros using the ISO C 9x extension. */
+static char va_args_name[] = "__VA_ARGS__";
+#define VA_ARGS_NAME_LENGTH (sizeof (va_args_name) - 1)
+
/* The structure of a node in the hash table. The hash table
has entries for all tokens defined by #define directives (type T_MACRO),
plus some special tokens like __LINE__ (these each have their own
T_DISABLED, /* macro temporarily turned off for rescan */
T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */
T_PCSTRING, /* precompiled string (hashval is KEYDEF *) */
+ T_POISON, /* defined with `#pragma poison' */
T_UNUSED /* Used for something not defined. */
};
#define HASHSTEP(old, c) ((old << 2) + c)
#define MAKE_POS(v) (v & 0x7fffffff) /* make number positive */
-/* Symbols to predefine. */
-
-#ifdef CPP_PREDEFINES
-static char *predefs = CPP_PREDEFINES;
-#else
-static char *predefs = "";
-#endif
\f
/* We let tm.h override the types used here, to handle trivial differences
such as the choice of unsigned int or long unsigned int for size_t.
#ifndef USER_LABEL_PREFIX
#define USER_LABEL_PREFIX ""
#endif
+char * user_label_prefix = USER_LABEL_PREFIX;
+#undef USER_LABEL_PREFIX
/* The string value for __REGISTER_PREFIX__ */
enum node_type type; /* Code which describes which directive. */
};
-#define IS_INCLUDE_DIRECTIVE_TYPE(t) (T_INCLUDE <= (t) && (t) <= T_IMPORT)
+#define IS_INCLUDE_DIRECTIVE_TYPE(t) \
+((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT)
/* These functions are declared to return int instead of void since they
are going to be placed in the table and some old compilers have trouble with
#endif
static int do_unassert DO_PROTO;
static int do_undef DO_PROTO;
-static int do_warning DO_PROTO;
static int do_xifdef DO_PROTO;
/* Here is the actual list of #-directives, most-often-used first. */
{ 6, do_include, "import", T_IMPORT},
{ 5, do_undef, "undef", T_UNDEF},
{ 5, do_error, "error", T_ERROR},
- { 7, do_warning, "warning", T_WARNING},
+ { 7, do_error, "warning", T_WARNING},
#ifdef SCCS_DIRECTIVE
{ 4, do_sccs, "sccs", T_SCCS},
#endif
static U_CHAR is_hor_space[256];
/* table to tell if c is horizontal or vertical space. */
U_CHAR is_space[256];
-/* names of some characters */
-static char *char_name[256];
#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
/* Name of output file, for error messages. */
static char *out_fname;
+/* Nonzero to ignore \ in string constants. Use to treat #line 1 "A:\file.h
+ as a non-form feed. If you want it to be a form feed, you must use
+ # 1 "\f". */
+static int ignore_escape_flag = 1;
/* Stack of conditionals currently in progress
(including both successful and failing conditionals). */
struct if_stack {
struct if_stack *next; /* for chaining to the next stack frame */
char *fname; /* copied from input when frame is made */
+ size_t fname_len; /* similarly */
int lineno; /* similarly */
int if_succeeded; /* true if a leg of this if-group
has been passed through rescan */
static U_CHAR *index0 PROTO((U_CHAR *, int, size_t));
static void trigraph_pcp PROTO((FILE_BUF *));
+static void check_white_space PROTO((FILE_BUF *));
static void newline_fix PROTO((U_CHAR *));
static void name_newline_fix PROTO((U_CHAR *));
static char *check_precompiled PROTO((int, struct stat *, char *, char **));
static int check_preconditions PROTO((char *));
-static void pcfinclude PROTO((U_CHAR *, U_CHAR *, U_CHAR *, FILE_BUF *));
+static void pcfinclude PROTO((U_CHAR *, U_CHAR *, FILE_BUF *));
static void pcstring_used PROTO((HASHNODE *));
static void write_output PROTO((void));
static void pass_thru_directive PROTO((U_CHAR *, U_CHAR *, FILE_BUF *, struct directive *));
static MACRODEF create_definition PROTO((U_CHAR *, U_CHAR *, FILE_BUF *));
-static int check_macro_name PROTO((U_CHAR *, char *));
+static int check_macro_name PROTO((U_CHAR *, int));
static int compare_defs PROTO((DEFINITION *, DEFINITION *));
static int comp_def_part PROTO((int, U_CHAR *, int, U_CHAR *, int, int));
static void do_once PROTO((void));
-static HOST_WIDE_INT eval_if_expression PROTO((U_CHAR *, int));
+static HOST_WIDEST_INT eval_if_expression PROTO((U_CHAR *, int));
static void conditional_skip PROTO((FILE_BUF *, int, enum node_type, U_CHAR *, FILE_BUF *));
static void skip_if_group PROTO((FILE_BUF *, int, FILE_BUF *));
static void validate_else PROTO((U_CHAR *, U_CHAR *));
static U_CHAR *skip_to_end_of_comment PROTO((FILE_BUF *, int *, int));
static U_CHAR *skip_quoted_string PROTO((U_CHAR *, U_CHAR *, int, int *, int *, int *));
-static char *quote_string PROTO((char *, char *));
+static char *quote_string PROTO((char *, char *, size_t));
static U_CHAR *skip_paren_group PROTO((FILE_BUF *));
/* Last arg to output_line_directive. */
static void macroexpand PROTO((HASHNODE *, FILE_BUF *));
struct argdata;
-static char *macarg PROTO((struct argdata *, int));
+static int macarg PROTO((struct argdata *, int));
-static U_CHAR *macarg1 PROTO((U_CHAR *, U_CHAR *, int *, int *, int *, int));
+static U_CHAR *macarg1 PROTO((U_CHAR *, U_CHAR *, struct hashnode *, int *, int *, int *, int));
static int discard_comments PROTO((U_CHAR *, int, int));
-static int change_newlines PROTO((U_CHAR *, int));
+static void change_newlines PROTO((struct argdata *));
-char *my_strerror PROTO((int));
-void error PRINTF_PROTO_1((char *, ...));
-static void verror PROTO((char *, va_list));
+static void notice PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1;
+static void vnotice PROTO((const char *, va_list));
+void error PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1;
+void verror PROTO((const char *, va_list));
static void error_from_errno PROTO((char *));
-void warning PRINTF_PROTO_1((char *, ...));
-static void vwarning PROTO((char *, va_list));
-static void error_with_line PRINTF_PROTO_2((int, char *, ...));
-static void verror_with_line PROTO((int, char *, va_list));
-static void vwarning_with_line PROTO((int, char *, va_list));
-static void warning_with_line PRINTF_PROTO_2((int, char *, ...));
-void pedwarn PRINTF_PROTO_1((char *, ...));
-void pedwarn_with_line PRINTF_PROTO_2((int, char *, ...));
-static void pedwarn_with_file_and_line PRINTF_PROTO_3((char *, int, char *, ...));
+void warning PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1;
+static void vwarning PROTO((const char *, va_list));
+static void error_with_line PVPROTO((int, const char *, ...)) ATTRIBUTE_PRINTF_2;
+static void verror_with_line PROTO((int, const char *, va_list));
+static void vwarning_with_line PROTO((int, const char *, va_list));
+static void warning_with_line PVPROTO((int, const char *, ...)) ATTRIBUTE_PRINTF_2;
+void pedwarn PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1;
+void pedwarn_with_line PVPROTO((int, const char *, ...)) ATTRIBUTE_PRINTF_2;
+static void pedwarn_with_file_and_line PVPROTO((const char *, size_t, int, const char *, ...)) ATTRIBUTE_PRINTF_4;
+static void pedwarn_strange_white_space PROTO((int));
static void print_containing_files PROTO((void));
static void initialize_char_syntax PROTO((void));
static void initialize_builtins PROTO((FILE_BUF *, FILE_BUF *));
-static void make_definition PROTO((char *, FILE_BUF *));
+static void make_definition PROTO((char *));
static void make_undef PROTO((char *, FILE_BUF *));
-static void make_assertion PROTO((char *, char *));
+static void make_assertion PROTO((const char *, const char *));
-static struct file_name_list *new_include_prefix PROTO((struct file_name_list *, char *, char *, char *));
+static struct file_name_list *new_include_prefix PROTO((struct file_name_list *, const char *, const char *, const char *));
static void append_include_chain PROTO((struct file_name_list *, struct file_name_list *));
-static int quote_string_for_make PROTO((char *, char *));
-static void deps_output PROTO((char *, int));
+static int quote_string_for_make PROTO((char *, const char *));
+static void deps_output PROTO((const char *, int));
-static void fatal PRINTF_PROTO_1((char *, ...)) __attribute__ ((noreturn));
-void fancy_abort PROTO((void)) __attribute__ ((noreturn));
+void fatal PVPROTO((const char *, ...)) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
+void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN;
static void perror_with_name PROTO((char *));
-static void pfatal_with_name PROTO((char *)) __attribute__ ((noreturn));
-static void pipe_closed PROTO((int)) __attribute__ ((noreturn));
-
-static void memory_full PROTO((void)) __attribute__ ((noreturn));
-GENERIC_PTR xmalloc PROTO((size_t));
-static GENERIC_PTR xrealloc PROTO((GENERIC_PTR, size_t));
-static GENERIC_PTR xcalloc PROTO((size_t, size_t));
-static char *savestring PROTO((char *));
+static void pfatal_with_name PROTO((char *)) ATTRIBUTE_NORETURN;
+static void pipe_closed PROTO((int)) ATTRIBUTE_NORETURN;
+
+static void memory_full PROTO((void)) ATTRIBUTE_NORETURN;
+static void print_help PROTO((void));
\f
/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
retrying if necessary. If MAX_READ_LEN is defined, read at most
len -= written;
}
}
+
+\f
+static void
+print_help ()
+{
+ printf ("Usage: %s [switches] input output\n", progname);
+ printf ("Switches:\n");
+ printf (" -include <file> Include the contents of <file> before other files\n");
+ printf (" -imacros <file> Accept definition of macros in <file>\n");
+ printf (" -iprefix <path> Specify <path> as a prefix for next two options\n");
+ printf (" -iwithprefix <dir> Add <dir> to the end of the system include paths\n");
+ printf (" -iwithprefixbefore <dir> Add <dir> to the end of the main include paths\n");
+ printf (" -isystem <dir> Add <dir> to the start of the system include paths\n");
+ printf (" -idirafter <dir> Add <dir> to the end of the system include paths\n");
+ printf (" -I <dir> Add <dir> to the end of the main include paths\n");
+ printf (" -nostdinc Do not search the system include directories\n");
+ printf (" -nostdinc++ Do not search the system include directories for C++\n");
+ printf (" -o <file> Put output into <file>\n");
+ printf (" -pedantic Issue all warnings demanded by strict ANSI C\n");
+ printf (" -traditional Follow K&R pre-processor behaviour\n");
+ printf (" -trigraphs Support ANSI C trigraphs\n");
+ printf (" -lang-c Assume that the input sources are in C\n");
+ printf (" -lang-c89 Assume that the input is C89; depricated\n");
+ printf (" -lang-c++ Assume that the input sources are in C++\n");
+ printf (" -lang-objc Assume that the input sources are in ObjectiveC\n");
+ printf (" -lang-objc++ Assume that the input sources are in ObjectiveC++\n");
+ printf (" -lang-asm Assume that the input sources are in assembler\n");
+ printf (" -lang-chill Assume that the input sources are in Chill\n");
+ printf (" -std=<std name> Specify the conformance standard; one of:\n");
+ printf (" gnu89, gnu9x, c89, c9x, iso9899:1990,\n");
+ printf (" iso9899:199409, iso9899:199x\n");
+ printf (" -+ Allow parsing of C++ style features\n");
+ printf (" -w Inhibit warning messages\n");
+ printf (" -Wtrigraphs Warn if trigraphs are encountered\n");
+ printf (" -Wno-trigraphs Do not warn about trigraphs\n");
+ printf (" -Wcomment{s} Warn if one comment starts inside another\n");
+ printf (" -Wno-comment{s} Do not warn about comments\n");
+ printf (" -Wtraditional Warn if a macro argument is/would be turned into\n");
+ printf (" a string if -traditional is specified\n");
+ printf (" -Wno-traditional Do not warn about stringification\n");
+ printf (" -Wundef Warn if an undefined macro is used by #if\n");
+ printf (" -Wno-undef Do not warn about testing undefined macros\n");
+ printf (" -Wimport Warn about the use of the #import directive\n");
+ printf (" -Wno-import Do not warn about the use of #import\n");
+ printf (" -Werror Treat all warnings as errors\n");
+ printf (" -Wno-error Do not treat warnings as errors\n");
+ printf (" -Wall Enable all preprocessor warnings\n");
+ printf (" -M Generate make dependencies\n");
+ printf (" -MM As -M, but ignore system header files\n");
+ printf (" -MD As -M, but put output in a .d file\n");
+ printf (" -MMD As -MD, but ignore system header files\n");
+ printf (" -MG Treat missing header file as generated files\n");
+ printf (" -g Include #define and #undef directives in the output\n");
+ printf (" -D<macro> Define a <macro> with string '1' as its value\n");
+ printf (" -D<macro>=<val> Define a <macro> with <val> as its value\n");
+ printf (" -A<question> (<answer>) Assert the <answer> to <question>\n");
+ printf (" -U<macro> Undefine <macro> \n");
+ printf (" -u or -undef Do not predefine any macros\n");
+ printf (" -v Display the version number\n");
+ printf (" -H Print the name of header files as they are used\n");
+ printf (" -C Do not discard comments\n");
+ printf (" -dM Display a list of macro definitions active at end\n");
+ printf (" -dD Preserve macro definitions in output\n");
+ printf (" -dN As -dD except that only the names are preserved\n");
+ printf (" -dI Include #include directives in the output\n");
+ printf (" -ifoutput Describe skipped code blocks in output \n");
+ printf (" -P Do not generate #line directives\n");
+ printf (" -$ Do not include '$' in identifiers\n");
+ printf (" -remap Remap file names when including files.\n");
+ printf (" -h or --help Display this information\n");
+}
\f
int
main (argc, argv)
char *cp;
int f, i;
FILE_BUF *fp;
- char **pend_files = (char **) xmalloc (argc * sizeof (char *));
- char **pend_defs = (char **) xmalloc (argc * sizeof (char *));
- char **pend_undefs = (char **) xmalloc (argc * sizeof (char *));
- char **pend_assertions = (char **) xmalloc (argc * sizeof (char *));
- char **pend_includes = (char **) xmalloc (argc * sizeof (char *));
+
+ char **pend_files;
+ char **pend_defs;
+ char **pend_undefs;
+ char **pend_assertions;
+ char **pend_includes;
/* Record the option used with each element of pend_assertions.
This is preparation for supporting more than one option for making
an assertion. */
- char **pend_assertion_options = (char **) xmalloc (argc * sizeof (char *));
- int inhibit_predefs = 0;
+ char **pend_assertion_options;
int no_standard_includes = 0;
int no_standard_cplusplus_includes = 0;
int missing_newline = 0;
signal (SIGPIPE, pipe_closed);
#endif
+#ifdef HAVE_LC_MESSAGES
+ setlocale (LC_MESSAGES, "");
+#endif
+ (void) bindtextdomain (PACKAGE, localedir);
+ (void) textdomain (PACKAGE);
+
progname = base_name (argv[0]);
#ifdef VMS
{
/* Remove extension from PROGNAME. */
char *p;
- char *s = progname = savestring (progname);
+ char *s = progname = xstrdup (progname);
if ((p = rindex (s, ';')) != 0) *p = '\0'; /* strip version number */
if ((p = rindex (s, '.')) != 0 /* strip type iff ".exe" */
}
#endif
+ /* Do not invoke xmalloc before this point, since locale and
+ progname need to be set first, in case a diagnostic is issued. */
+
+ pend_files = (char **) xmalloc (argc * sizeof (char *));
+ pend_defs = (char **) xmalloc (argc * sizeof (char *));
+ pend_undefs = (char **) xmalloc (argc * sizeof (char *));
+ pend_assertions = (char **) xmalloc (argc * sizeof (char *));
+ pend_includes = (char **) xmalloc (argc * sizeof (char *));
+ pend_assertion_options = (char **) xmalloc (argc * sizeof (char *));
+
in_fname = NULL;
out_fname = NULL;
bzero ((char *) pend_assertions, argc * sizeof (char *));
bzero ((char *) pend_includes, argc * sizeof (char *));
+#ifdef MULTIBYTE_CHARS
+ /* Change to the native locale for multibyte conversions. */
+ setlocale (LC_CTYPE, "");
+ literal_codeset = getenv ("LANG");
+#endif
+
/* Process switches and find input file name. */
for (i = 1; i < argc; i++) {
if (argv[i][0] != '-') {
if (out_fname != NULL)
- fatal ("Usage: %s [switches] input output", argv[0]);
+ {
+ print_help ();
+ fatal ("Too many arguments");
+ }
else if (in_fname != NULL)
out_fname = argv[i];
else
case 'i':
if (!strcmp (argv[i], "-include")) {
- int temp = i;
-
if (i + 1 == argc)
fatal ("Filename missing after `-include' option");
- else
- simplify_filename (pend_includes[temp] = argv[++i]);
+ else {
+ i++;
+ simplify_filename (pend_includes[i] = argv[i]);
+ }
}
if (!strcmp (argv[i], "-imacros")) {
- int temp = i;
-
if (i + 1 == argc)
fatal ("Filename missing after `-imacros' option");
- else
- simplify_filename (pend_files[temp] = argv[++i]);
+ else {
+ i++;
+ simplify_filename (pend_files[i] = argv[i]);
+ }
}
if (!strcmp (argv[i], "-iprefix")) {
if (i + 1 == argc)
if (include_prefix != 0)
prefix = include_prefix;
else {
- prefix = savestring (GCC_INCLUDE_DIR);
+ prefix = xstrdup (GCC_INCLUDE_DIR);
/* Remove the `include' from /usr/local/lib/gcc.../include. */
if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
prefix[strlen (prefix) - 7] = 0;
if (include_prefix != 0)
prefix = include_prefix;
else {
- prefix = savestring (GCC_INCLUDE_DIR);
+ prefix = xstrdup (GCC_INCLUDE_DIR);
/* Remove the `include' from /usr/local/lib/gcc.../include. */
if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
prefix[strlen (prefix) - 7] = 0;
case 'l':
if (! strcmp (argv[i], "-lang-c"))
- cplusplus = 0, cplusplus_comments = 1, c89 = 0, objc = 0;
- if (! strcmp (argv[i], "-lang-c89"))
- cplusplus = 0, cplusplus_comments = 0, c89 = 1, objc = 0;
- if (! strcmp (argv[i], "-lang-c++"))
- cplusplus = 1, cplusplus_comments = 1, c89 = 0, objc = 0;
- if (! strcmp (argv[i], "-lang-objc"))
- cplusplus = 0, cplusplus_comments = 1, c89 = 0, objc = 1;
- if (! strcmp (argv[i], "-lang-objc++"))
- cplusplus = 1, cplusplus_comments = 1, c89 = 0, objc = 1;
- if (! strcmp (argv[i], "-lang-asm"))
+ cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 1, objc = 0;
+ else if (! strcmp (argv[i], "-lang-c89"))
+ cplusplus = 0, cplusplus_comments = 0, c89 = 1, c9x = 0, objc = 0;
+ else if (! strcmp (argv[i], "-lang-c++"))
+ cplusplus = 1, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 0;
+ else if (! strcmp (argv[i], "-lang-objc"))
+ cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 1;
+ else if (! strcmp (argv[i], "-lang-objc++"))
+ cplusplus = 1, cplusplus_comments = 1, c89 = 0, c9x = 0, objc = 1;
+ else if (! strcmp (argv[i], "-lang-asm"))
lang_asm = 1;
- if (! strcmp (argv[i], "-lint"))
+ else if (! strcmp (argv[i], "-lint"))
for_lint = 1;
break;
cplusplus = 1, cplusplus_comments = 1;
break;
+ case 's':
+ if (!strcmp (argv[i], "-std=iso9899:1990")
+ || !strcmp (argv[i], "-std=iso9899:199409")
+ || !strcmp (argv[i], "-std=c89")
+ || !strcmp (argv[i], "-std=gnu89"))
+ cplusplus = 0, cplusplus_comments = 0, c89 = 1, c9x = 0, objc = 0;
+ else if (!strcmp (argv[i], "-std=iso9899:199x")
+ || !strcmp (argv[i], "-std=c9x")
+ || !strcmp (argv[i], "-std=gnu9x"))
+ cplusplus = 0, cplusplus_comments = 1, c89 = 0, c9x = 1, objc = 0;
+ break;
+
case 'w':
inhibit_warnings = 1;
break;
warn_stringify = 1;
else if (!strcmp (argv[i], "-Wno-traditional"))
warn_stringify = 0;
+ else if (!strcmp (argv[i], "-Wwhite-space"))
+ warn_white_space = 1;
+ else if (!strcmp (argv[i], "-Wno-white-space"))
+ warn_white_space = 0;
else if (!strcmp (argv[i], "-Wundef"))
warn_undef = 1;
else if (!strcmp (argv[i], "-Wno-undef"))
{
warn_trigraphs = 1;
warn_comments = 1;
+ warn_white_space = 1;
}
break;
+ case 'f':
+ if (!strcmp (argv[i], "-fleading-underscore"))
+ user_label_prefix = "_";
+ else if (!strcmp (argv[i], "-fno-leading-underscore"))
+ user_label_prefix = "";
+ break;
+
case 'M':
/* The style of the choices here is a bit mixed.
The chosen scheme is a hybrid of keeping all options in one string
debug_output = 1;
break;
+ case '-':
+ if (strcmp (argv[i], "--help") != 0)
+ return i;
+ print_help ();
+ exit (0);
+ break;
+
case 'v':
- fprintf (stderr, "GNU CPP version %s", version_string);
+ notice ("GNU CPP version %s", version_string);
#ifdef TARGET_VERSION
TARGET_VERSION;
#endif
on the command line. That way we can get rid of any
that were passed automatically in from GCC. */
int j;
- inhibit_predefs = 1;
for (j = 0; j < i; j++)
pend_defs[j] = pend_assertions[j] = 0;
} else {
case 'I': /* Add directory to path for includes. */
{
struct file_name_list *dirtmp;
+ char *dir = argv[i][2] ? argv[i] + 2 : argv[++i];
- if (! ignore_srcdir && !strcmp (argv[i] + 2, "-")) {
+ if (! ignore_srcdir && !strcmp (dir, "-")) {
ignore_srcdir = 1;
/* Don't use any preceding -I directories for #include <...>. */
first_bracket_include = 0;
}
else {
- dirtmp = new_include_prefix (last_include, NULL_PTR, "",
- argv[i][2] ? argv[i] + 2 : argv[++i]);
+ dirtmp = new_include_prefix (last_include, NULL_PTR, "", dir);
append_include_chain (dirtmp, dirtmp);
}
}
remap = 1;
break;
- case 'u':
- /* Sun compiler passes undocumented switch "-undef".
- Let's assume it means to inhibit the predefined symbols. */
- inhibit_predefs = 1;
- break;
-
case '\0': /* JF handle '-' as file name meaning stdin or stdout */
if (in_fname == NULL) {
in_fname = "";
/* Some people say that CPATH should replace the standard include dirs,
but that seems pointless: it comes before them, so it overrides them
anyway. */
- cp = getenv ("CPATH");
+ GET_ENV_PATH_LIST (cp, "CPATH");
if (cp && ! no_standard_includes)
path_include (cp);
if (in_fname == NULL)
in_fname = "";
fp->nominal_fname = fp->fname = in_fname;
+ fp->nominal_fname_len = strlen (in_fname);
fp->lineno = 0;
/* In C++, wchar_t is a distinct basic type, and we can expect
and option processing. */
initialize_builtins (fp, &outbuf);
- /* Do standard #defines and assertions
- that identify system and machine type. */
-
- if (!inhibit_predefs) {
- char *p = (char *) alloca (strlen (predefs) + 1);
-
-#ifdef VMS
- struct dsc$descriptor_s lcl_name;
- struct item_list {
- unsigned short length; /* input length */
- unsigned short code; /* item code */
- unsigned long dptr; /* data ptr */
- unsigned long lptr; /* output length ptr */
- };
-
- unsigned long syi_length;
- char syi_data[16];
-
- struct item_list items[] = {
- { 16, SYI$_VERSION, 0, 0 },
- { 0, 0, 0, 0 }
- };
-
- items[0].dptr = (unsigned long)syi_data;
- items[0].lptr = (unsigned long)(&syi_length);
-
- if (SYS$GETSYIW (0, 0, 0, items, NULL, NULL, NULL, NULL) == SS$_NORMAL)
- {
- unsigned long vms_version_value;
- char *vers;
-
- vers = syi_data;
- vms_version_value = 0;
-
- if (*vers == 'V')
- vers++;
- if (isdigit (*vers))
- {
- vms_version_value = (*vers - '0') * 10000000;
- }
- vers++;
- if (*vers == '.')
- {
- vers++;
- if (isdigit (*vers))
- {
- vms_version_value += (*vers - '0') * 100000;
- }
- }
-
- if (vms_version_value > 0)
- {
- char versbuf[32];
-
- sprintf (versbuf, "__VMS_VER=%08ld", vms_version_value);
- if (debug_output)
- output_line_directive (fp, &outbuf, 0, same_file);
- make_definition (versbuf, &outbuf);
- }
- }
-#endif
-
- strcpy (p, predefs);
- while (*p) {
- char *q;
- while (*p == ' ' || *p == '\t')
- p++;
- /* Handle -D options. */
- if (p[0] == '-' && p[1] == 'D') {
- q = &p[2];
- while (*p && *p != ' ' && *p != '\t')
- p++;
- if (*p != 0)
- *p++= 0;
- if (debug_output)
- output_line_directive (fp, &outbuf, 0, same_file);
- make_definition (q, &outbuf);
- while (*p == ' ' || *p == '\t')
- p++;
- } else if (p[0] == '-' && p[1] == 'A') {
- /* Handle -A options (assertions). */
- char *assertion;
- char *past_name;
- char *value;
- char *past_value;
- char *termination;
- int save_char;
-
- assertion = &p[2];
- past_name = assertion;
- /* Locate end of name. */
- while (*past_name && *past_name != ' '
- && *past_name != '\t' && *past_name != '(')
- past_name++;
- /* Locate `(' at start of value. */
- value = past_name;
- while (*value && (*value == ' ' || *value == '\t'))
- value++;
- if (*value++ != '(')
- abort ();
- while (*value && (*value == ' ' || *value == '\t'))
- value++;
- past_value = value;
- /* Locate end of value. */
- while (*past_value && *past_value != ' '
- && *past_value != '\t' && *past_value != ')')
- past_value++;
- termination = past_value;
- while (*termination && (*termination == ' ' || *termination == '\t'))
- termination++;
- if (*termination++ != ')')
- abort ();
- if (*termination && *termination != ' ' && *termination != '\t')
- abort ();
- /* Temporarily null-terminate the value. */
- save_char = *termination;
- *termination = '\0';
- /* Install the assertion. */
- make_assertion ("-A", assertion);
- *termination = (char) save_char;
- p = termination;
- while (*p == ' ' || *p == '\t')
- p++;
- } else {
- abort ();
- }
- }
- }
-
/* Now handle the command line options. */
/* Do -U's, -D's and -A's in the order they were seen. */
if (pend_defs[i]) {
if (debug_output)
output_line_directive (fp, &outbuf, 0, same_file);
- make_definition (pend_defs[i], &outbuf);
+ make_definition (pend_defs[i]);
}
if (pend_assertions[i])
make_assertion (pend_assertion_options[i], pend_assertions[i]);
switch ((objc << 1) + cplusplus)
{
case 0:
- epath = getenv ("C_INCLUDE_PATH");
+ GET_ENV_PATH_LIST (epath, "C_INCLUDE_PATH");
break;
case 1:
- epath = getenv ("CPLUS_INCLUDE_PATH");
+ GET_ENV_PATH_LIST (epath, "CPLUS_INCLUDE_PATH");
break;
case 2:
- epath = getenv ("OBJC_INCLUDE_PATH");
+ GET_ENV_PATH_LIST (epath, "OBJC_INCLUDE_PATH");
break;
case 3:
- epath = getenv ("OBJCPLUS_INCLUDE_PATH");
+ GET_ENV_PATH_LIST (epath, "OBJCPLUS_INCLUDE_PATH");
break;
}
/* If the environment var for this language is set,
if (c == PATH_SEPARATOR || !c) {
endp[-1] = 0;
include_defaults[num_dirs].fname
- = startp == endp ? "." : savestring (startp);
+ = startp == endp ? "." : xstrdup (startp);
endp[-1] = c;
include_defaults[num_dirs].component = 0;
include_defaults[num_dirs].cplusplus = cplusplus;
if (!no_standard_includes) {
struct default_include *p = include_defaults;
char *specd_prefix = include_prefix;
- char *default_prefix = savestring (GCC_INCLUDE_DIR);
+ char *default_prefix = xstrdup (GCC_INCLUDE_DIR);
int default_len = 0;
/* Remove the `include' from /usr/local/lib/gcc.../include. */
if (!strcmp (default_prefix + strlen (default_prefix) - 8, "/include")) {
append_include_chain (new, new);
if (first_system_include == 0)
first_system_include = new;
+ p->included = 1;
}
}
}
append_include_chain (new, new);
if (first_system_include == 0)
first_system_include = new;
+ p->included = 1;
}
}
}
/* With -v, print the list of dirs to search. */
if (verbose) {
struct file_name_list *p;
- fprintf (stderr, "#include \"...\" search starts here:\n");
+ notice ("#include \"...\" search starts here:\n");
for (p = include; p; p = p->next) {
if (p == first_bracket_include)
- fprintf (stderr, "#include <...> search starts here:\n");
+ notice ("#include <...> search starts here:\n");
if (!p->fname[0])
fprintf (stderr, " .\n");
else if (!strcmp (p->fname, "/") || !strcmp (p->fname, "//"))
/* Omit trailing '/'. */
fprintf (stderr, " %.*s\n", (int) strlen (p->fname) - 1, p->fname);
}
- fprintf (stderr, "End of search list.\n");
+ notice ("End of search list.\n");
+ {
+ struct default_include * d;
+ notice ("The following default directories have been omitted from the search path:\n");
+ for (d = include_defaults; d->fname; d++)
+ if (! d->included)
+ fprintf (stderr, " %s\n", d->fname);
+ notice ("End of omitted list.\n");
+ }
}
/* -MG doesn't select the form of output and must be specified with one of
else
print_deps = 1;
- s = spec;
/* Find the space before the DEPS_TARGET, if there is one. */
- /* This should use index. (mrs) */
- while (*s != 0 && *s != ' ') s++;
- if (*s != 0) {
+ s = index (spec, ' ');
+ if (s) {
deps_target = s + 1;
output_file = xmalloc (s - spec + 1);
bcopy (spec, output_file, s - spec);
output_file[s - spec] = 0;
- }
- else {
+ } else {
deps_target = 0;
output_file = spec;
}
strcpy (q, OBJECT_SUFFIX);
deps_output (p, ':');
- deps_output (in_fname, ' ');
}
+
+ deps_output (in_fname, ' ');
}
/* Scan the -imacros files before the main input.
if (fstat (f, &st) != 0)
pfatal_with_name (in_fname);
fp->nominal_fname = fp->fname = in_fname;
+ fp->nominal_fname_len = strlen (in_fname);
fp->lineno = 1;
fp->system_header_p = 0;
/* JF all this is mine about reading pipes and ttys */
if (!no_trigraphs)
trigraph_pcp (fp);
+ if (warn_white_space)
+ check_white_space (fp);
+
/* Now that we know the input file is valid, open the output. */
if (!out_fname || !strcmp (out_fname, ""))
warning_with_line (0, "%lu trigraph(s) encountered",
(unsigned long) (fptr - bptr) / 2);
}
+
+/* Warn about white space between backslash and end of line. */
+
+static void
+check_white_space (buf)
+ FILE_BUF *buf;
+{
+ register U_CHAR *sptr = buf->buf;
+ register U_CHAR *lptr = sptr + buf->length;
+ register U_CHAR *nptr;
+ int line = 0;
+
+ nptr = sptr = buf->buf;
+ lptr = sptr + buf->length;
+ for (nptr = sptr;
+ (nptr = index0 (nptr, '\n', (size_t) (lptr - nptr))) != NULL;
+ nptr ++) {
+ register U_CHAR *p = nptr;
+ line++;
+ for (p = nptr; sptr < p; p--) {
+ if (! is_hor_space[p[-1]]) {
+ if (p[-1] == '\\' && p != nptr)
+ warning_with_line (line,
+ "`\\' followed by white space at end of line");
+ break;
+ }
+ }
+ }
+}
\f
/* Move all backslash-newline pairs out of embarrassing places.
Exchange all such pairs following BP
with any potentially-embarrassing characters that follow them.
Potentially-embarrassing characters are / and *
(because a backslash-newline inside a comment delimiter
- would cause it not to be recognized). */
+ would cause it not to be recognized).
+ We assume that *BP == '\\'. */
static void
newline_fix (bp)
register U_CHAR *p = bp;
/* First count the backslash-newline pairs here. */
-
- while (p[0] == '\\' && p[1] == '\n')
+ do {
+ if (p[1] != '\n')
+ break;
p += 2;
+ } while (*p == '\\');
/* What follows the backslash-newlines is not embarrassing. */
if (*p != '/' && *p != '*')
+ /* What follows the backslash-newlines is not embarrassing. */
return;
/* Copy all potentially embarrassing characters
that follow the backslash-newline pairs
down to where the pairs originally started. */
-
- while (*p == '*' || *p == '/')
+ do
*bp++ = *p++;
+ while (*p == '*' || *p == '/');
/* Now write the same number of pairs after the embarrassing chars. */
while (bp < p) {
register U_CHAR *p = bp;
/* First count the backslash-newline pairs here. */
- while (p[0] == '\\' && p[1] == '\n')
+ do {
+ if (p[1] != '\n')
+ break;
p += 2;
+ } while (*p == '\\');
/* What follows the backslash-newlines is not embarrassing. */
if (!is_idchar[*p])
+ /* What follows the backslash-newlines is not embarrassing. */
return;
/* Copy all potentially embarrassing characters
that follow the backslash-newline pairs
down to where the pairs originally started. */
-
- while (is_idchar[*p])
+ do
*bp++ = *p++;
+ while (is_idchar[*p]);
/* Now write the same number of pairs after the embarrassing chars. */
while (bp < p) {
U_CHAR **argstart; /* point to command arg */
int *arglen, *cmdlen; /* how long they are */
{
- HOST_WIDE_INT linsize;
+ HOST_WIDEST_INT linsize;
register U_CHAR *numptr; /* temp for arg parsing */
*arglen = 0;
if ((linsize >= 7) && !bcmp (ibp, "VARARGS", 7)) {
*cmdlen = 7;
ibp += 7; linsize -= 7;
- if ((linsize == 0) || ! isdigit (*ibp)) return "VARARGS";
+ if ((linsize == 0) || ! ISDIGIT (*ibp)) return "VARARGS";
/* OK, read a number */
- for (numptr = *argstart = ibp; (numptr < limit) && isdigit (*numptr);
+ for (numptr = *argstart = ibp; (numptr < limit) && ISDIGIT (*numptr);
numptr++);
*arglen = numptr - *argstart;
return "VARARGS";
* If OUTPUT_MARKS is nonzero, keep Newline markers found in the input
* and insert them when appropriate. This is set while scanning macro
* arguments before substitution. It is zero when scanning for final output.
- * There are three types of Newline markers:
+ * There are two types of Newline markers:
* * Newline - follows a macro name that was not expanded
* because it appeared inside an expansion of the same macro.
* This marker prevents future expansion of that identifier.
bp += 2;
else if (*bp == '/' && bp[1] == '*') {
bp += 2;
- while (!(*bp == '*' && bp[1] == '/'))
- bp++;
- bp += 2;
+ while (1)
+ {
+ if (*bp == '*')
+ {
+ if (bp[1] == '/')
+ {
+ bp += 2;
+ break;
+ }
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (bp, limit - bp);
+ if (length > 1)
+ bp += (length - 1);
+#endif
+ }
+ bp++;
+ }
}
/* There is no point in trying to deal with C++ // comments here,
because if there is one, then this # must be part of the
/* Handle any pending identifier;
but the L in L'...' or L"..." is not an identifier. */
- if (ident_length
- && ! (ident_length == 1 && hash == HASHSTEP (0, 'L')))
- goto specialchar;
+ if (ident_length) {
+ if (! (ident_length == 1 && hash == HASHSTEP (0, 'L')))
+ goto specialchar;
+ ident_length = hash = 0;
+ }
start_line = ip->lineno;
if (!traditional) {
error_with_line (line_for_error (start_line),
"unterminated string or character constant");
- error_with_line (multiline_string_line,
- "possible real start of unterminated constant");
- multiline_string_line = 0;
+ if (multiline_string_line) {
+ error_with_line (multiline_string_line,
+ "possible real start of unterminated constant");
+ multiline_string_line = 0;
+ }
}
break;
}
*obp++ = *ibp;
switch (*ibp++) {
case '\n':
+ if (warn_white_space && ip->fname && is_hor_space[ibp[-2]])
+ warning ("white space at end of line in string");
++ip->lineno;
++op->lineno;
/* Traditionally, end of line ends a string constant with no error.
break;
case '\\':
- if (ibp >= limit)
- break;
if (*ibp == '\n') {
- /* Backslash newline is replaced by nothing at all,
- but keep the line counts correct. */
- --obp;
+ /* Backslash newline is replaced by nothing at all, but
+ keep the line counts correct. But if we are reading
+ from a macro, keep the backslash newline, since backslash
+ newlines have already been processed. */
+ if (ip->macro) {
+ *obp++ = '\n';
+ ++op->lineno;
+ } else
+ --obp;
++ibp;
++ip->lineno;
} else {
/* ANSI stupidly requires that in \\ the second \
is *not* prevented from combining with a newline. */
- while (*ibp == '\\' && ibp[1] == '\n') {
- ibp += 2;
- ++ip->lineno;
+ if (!ip->macro) {
+ while (*ibp == '\\' && ibp[1] == '\n') {
+ *obp++ = *ibp++;
+ *obp++ = *ibp++;
+ ++ip->lineno;
+ ++op->lineno;
+ }
}
*obp++ = *ibp++;
}
if (ibp[-1] == c)
goto while2end;
break;
+#ifdef MULTIBYTE_CHARS
+ default:
+ {
+ int length;
+ --ibp;
+ length = local_mblen (ibp, limit - ibp);
+ if (length > 0)
+ {
+ --obp;
+ bcopy (ibp, obp, length);
+ obp += length;
+ ibp += length;
+ }
+ else
+ ++ibp;
+ }
+ break;
+#endif
}
}
while2end:
break;
case '/':
- if (*ibp == '\\' && ibp[1] == '\n')
+ if (ip->macro != 0)
+ goto randomchar;
+ if (*ibp == '\\')
newline_fix (ibp);
-
if (*ibp != '*'
&& !(cplusplus_comments && *ibp == '/'))
goto randomchar;
- if (ip->macro != 0)
- goto randomchar;
if (ident_length)
goto specialchar;
U_CHAR *before_bp = ibp;
while (++ibp < limit) {
- if (*ibp == '\n') {
- if (ibp[-1] != '\\') {
+ if (*ibp == '\n')
+ {
if (put_out_comments) {
bcopy ((char *) before_bp, (char *) obp, ibp - before_bp);
obp += ibp - before_bp;
}
break;
}
- if (warn_comments)
- warning ("multiline `//' comment");
- ++ip->lineno;
- /* Copy the newline into the output buffer, in order to
- avoid the pain of a #line every time a multiline comment
- is seen. */
- if (!put_out_comments)
- *obp++ = '\n';
- ++op->lineno;
- }
+ if (*ibp == '\\')
+ {
+ if (ibp + 1 < limit && ibp[1] == '\n')
+ {
+ if (warn_comments)
+ warning ("multiline `//' comment");
+ ++ip->lineno;
+ /* Copy the newline into the output buffer, in order to
+ avoid the pain of a #line every time a multiline comment
+ is seen. */
+ if (!put_out_comments)
+ *obp++ = '\n';
+ ++op->lineno;
+ ++ibp;
+ }
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (ibp, limit - ibp);
+ if (length > 1)
+ ibp += (length - 1);
+#endif
+ }
}
break;
}
case '*':
if (ibp[-2] == '/' && warn_comments)
warning ("`/*' within comment");
- if (*ibp == '\\' && ibp[1] == '\n')
+ if (*ibp == '\\')
newline_fix (ibp);
if (*ibp == '/')
goto comment_end;
goto limit_reached;
}
break;
+#ifdef MULTIBYTE_CHARS
+ default:
+ {
+ int length;
+ length = local_mblen (ibp, limit - ibp);
+ if (length > 1)
+ ibp += (length - 1);
+ }
+ break;
+#endif
}
}
comment_end:
if (ident_length == 0) {
for (;;) {
- while (ibp[0] == '\\' && ibp[1] == '\n') {
- ++ip->lineno;
- ibp += 2;
+ if (!ip->macro) {
+ while (ibp[0] == '\\' && ibp[1] == '\n') {
+ ++ip->lineno;
+ ibp += 2;
+ }
}
c = *ibp++;
if (!is_idchar[c] && c != '.') {
/* A sign can be part of a preprocessing number
if it follows an `e' or `p'. */
if (c == 'e' || c == 'E' || c == 'p' || c == 'P') {
- while (ibp[0] == '\\' && ibp[1] == '\n') {
- ++ip->lineno;
- ibp += 2;
+ if (!ip->macro) {
+ while (ibp[0] == '\\' && ibp[1] == '\n') {
+ ++ip->lineno;
+ ibp += 2;
+ }
}
if (*ibp == '+' || *ibp == '-') {
*obp++ = *ibp++;
old_iln = ip->lineno;
old_oln = op->lineno;
}
- /* A comment: copy it unchanged or discard it. */
- else if (*ibp == '/' && ibp[1] == '*') {
- if (put_out_comments) {
- *obp++ = '/';
- *obp++ = '*';
- } else if (! traditional) {
- *obp++ = ' ';
- }
- ibp += 2;
- while (ibp + 1 != limit
- && !(ibp[0] == '*' && ibp[1] == '/')) {
- /* We need not worry about newline-marks,
- since they are never found in comments. */
- if (*ibp == '\n') {
- /* Newline in a file. Count it. */
- ++ip->lineno;
- ++op->lineno;
- }
- if (put_out_comments)
- *obp++ = *ibp++;
- else
- ibp++;
- }
- ibp += 2;
- if (put_out_comments) {
- *obp++ = '*';
- *obp++ = '/';
- }
- }
else if (is_space[*ibp]) {
*obp++ = *ibp++;
if (ibp[-1] == '\n') {
}
}
}
+ else if (ip->macro)
+ break;
+ else if (*ibp == '/') {
+ /* If a comment, copy it unchanged or discard it. */
+ if (ibp[1] == '\\')
+ newline_fix (ibp + 1);
+ if (ibp[1] == '*') {
+ if (put_out_comments) {
+ *obp++ = '/';
+ *obp++ = '*';
+ } else if (! traditional) {
+ *obp++ = ' ';
+ }
+ for (ibp += 2; ibp < limit; ibp++) {
+ /* We need not worry about newline-marks,
+ since they are never found in comments. */
+ if (ibp[0] == '*') {
+ if (ibp[1] == '\\')
+ newline_fix (ibp + 1);
+ if (ibp[1] == '/') {
+ ibp += 2;
+ if (put_out_comments) {
+ *obp++ = '*';
+ *obp++ = '/';
+ }
+ break;
+ }
+ }
+ else if (*ibp == '\n') {
+ /* Newline in a file. Count it. */
+ ++ip->lineno;
+ ++op->lineno;
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (ibp, limit - ibp);
+ if (length > 1)
+ {
+ if (put_out_comments)
+ {
+ bcopy (ibp, obp, length - 1);
+ obp += length - 1;
+ }
+ ibp += (length - 1);
+ }
+#endif
+ }
+ if (put_out_comments)
+ *obp++ = *ibp;
+ }
+ } else if (ibp[1] == '/' && cplusplus_comments) {
+ if (put_out_comments) {
+ *obp++ = '/';
+ *obp++ = '/';
+ } else if (! traditional) {
+ *obp++ = ' ';
+ }
+ for (ibp += 2; ; ibp++)
+ {
+ if (*ibp == '\n')
+ break;
+ if (*ibp == '\\' && ibp[1] == '\n')
+ {
+ if (put_out_comments)
+ *obp++ = *ibp++;
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (ibp, limit - ibp);
+ if (length > 1)
+ {
+ if (put_out_comments)
+ {
+ bcopy (ibp, obp, length - 1);
+ obp += length - 1;
+ }
+ ibp += (length - 1);
+ }
+#endif
+ }
+ if (put_out_comments)
+ *obp++ = *ibp;
+ }
+ } else
+ break;
+ }
+ else if (ibp[0] == '\\' && ibp[1] == '\n') {
+ ibp += 2;
+ ++ip->lineno;
+ }
else break;
}
if (*ibp != '(') {
ip = &instack[indepth];
ip->fname = 0;
ip->nominal_fname = 0;
+ ip->nominal_fname_len = 0;
ip->inc = 0;
ip->system_header_p = 0;
ip->macro = 0;
if (indepth != odepth)
abort ();
- /* Record the output. */
- obuf.length = obuf.bufp - obuf.buf;
-
assertions_flag = save_assertions_flag;
return obuf;
}
/* Record where the directive started. do_xifdef needs this. */
directive_start = bp - 1;
+ ignore_escape_flag = 1;
+
/* Skip whitespace and \-newline. */
while (1) {
if (is_hor_space[*bp]) {
if (*bp != ' ' && *bp != '\t' && pedantic)
- pedwarn ("%s in preprocessing directive", char_name[*bp]);
+ pedwarn_strange_white_space (*bp);
bp++;
- } else if (*bp == '/' && (bp[1] == '*'
- || (cplusplus_comments && bp[1] == '/'))) {
+ } else if (*bp == '/') {
+ if (bp[1] == '\\')
+ newline_fix (bp + 1);
+ if (! (bp[1] == '*' || (cplusplus_comments && bp[1] == '/')))
+ break;
ip->bufp = bp + 2;
skip_to_end_of_comment (ip, &ip->lineno, 0);
bp = ip->bufp;
if (is_idchar[*cp])
cp++;
else {
- if (*cp == '\\' && cp[1] == '\n')
+ if (*cp == '\\')
name_newline_fix (cp);
if (is_idchar[*cp])
cp++;
pedwarn ("`#' followed by integer");
after_ident = ident;
kt = line_directive_table;
+ ignore_escape_flag = 0;
goto old_linenum;
}
register U_CHAR c = *bp++;
switch (c) {
case '\\':
- if (bp < limit) {
- if (*bp == '\n') {
- ip->lineno++;
- copy_directive = 1;
- bp++;
- } else if (traditional)
- bp++;
- }
+ if (*bp == '\n') {
+ ip->lineno++;
+ copy_directive = 1;
+ bp++;
+ } else if (traditional && bp < limit)
+ bp++;
break;
+ case '"':
+ /* "..." is special for #include. */
+ if (IS_INCLUDE_DIRECTIVE_TYPE (kt->type)) {
+ while (bp < limit && *bp != '\n') {
+ if (*bp == '"') {
+ bp++;
+ break;
+ }
+ if (*bp == '\\' && bp[1] == '\n') {
+ ip->lineno++;
+ copy_directive = 1;
+ bp++;
+ }
+ bp++;
+ }
+ break;
+ }
+ /* Fall through. */
case '\'':
- case '\"':
bp = skip_quoted_string (bp - 1, limit, ip->lineno, &ip->lineno, ©_directive, &unterminated);
/* Don't bother calling the directive if we already got an error
message due to unterminated string. Skip everything and pretend
break;
case '/':
- if (*bp == '\\' && bp[1] == '\n')
+ if (*bp == '\\')
newline_fix (bp);
if (*bp == '*'
|| (cplusplus_comments && *bp == '/')) {
case '\r':
case '\v':
if (pedantic)
- pedwarn ("%s in preprocessing directive", char_name[c]);
+ pedwarn_strange_white_space (c);
break;
case '\n':
/* If a directive should be copied through, and -C was given,
pass it through before removing comments. */
if (!no_output && put_out_comments
- && (kt->type == T_DEFINE ? dump_macros == dump_definitions
+ && ((kt->type == T_DEFINE || kt->type == T_UNDEF)
+ ? dump_macros == dump_definitions
: IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes
: kt->type == T_PRAGMA)) {
int len;
register U_CHAR *xp = buf;
/* Need to copy entire directive into temp buffer before dispatching */
- cp = (U_CHAR *) alloca (bp - buf + 5); /* room for directive plus
- some slop */
+ /* room for directive plus some slop */
+ cp = (U_CHAR *) alloca (2 * (bp - buf) + 5);
buf = cp;
/* Copy to the new buffer, deleting comments
- and backslash-newlines (and whitespace surrounding the latter). */
+ and backslash-newlines (and whitespace surrounding the latter
+ if outside of char and string constants). */
while (xp < bp) {
register U_CHAR c = *xp++;
case '\'':
case '\"':
{
+ int backslash_newlines_p;
+
register U_CHAR *bp1
= skip_quoted_string (xp - 1, bp, ip->lineno,
- NULL_PTR, NULL_PTR, NULL_PTR);
- while (xp != bp1)
- if (*xp == '\\') {
- if (*++xp != '\n')
- *cp++ = '\\';
- else
- xp++;
- } else
+ NULL_PTR, &backslash_newlines_p,
+ NULL_PTR);
+ if (backslash_newlines_p)
+ while (xp != bp1)
+ {
+ /* With something like:
+
+ #define X "a\
+ b"
+
+ we should still remove the backslash-newline
+ pair as part of phase two. */
+ if (xp[0] == '\\' && xp[1] == '\n')
+ xp += 2;
+ else
+ *cp++ = *xp++;
+ }
+ else
+ /* This is the same as the loop above, but taking
+ advantage of the fact that we know there are no
+ backslash-newline pairs. */
+ while (xp != bp1)
*cp++ = *xp++;
}
break;
directives through. */
if (!no_output && already_output == 0
- && (kt->type == T_DEFINE ? dump_names <= dump_macros
+ && ((kt->type == T_DEFINE || kt->type == T_UNDEF)
+ ? (int) dump_names <= (int) dump_macros
: IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes
: kt->type == T_PRAGMA)) {
int len;
bcopy (buf, (char *) op->bufp, len);
}
op->bufp += len;
- } /* Don't we need a newline or #line? */
+ }
/* Call the appropriate directive handler. buf now points to
either the appropriate place in the input buffer, or to
static struct tm *
timestamp ()
{
- static struct tm *timebuf;
- if (!timebuf) {
+ static struct tm tmbuf;
+ if (! tmbuf.tm_mday) {
time_t t = time ((time_t *) 0);
- timebuf = localtime (&t);
+ struct tm *tm = localtime (&t);
+ if (tm)
+ tmbuf = *tm;
+ else {
+ /* Use 0000-01-01 00:00:00 if local time is not available. */
+ tmbuf.tm_year = -1900;
+ tmbuf.tm_mday = 1;
+ }
}
- return timebuf;
+ return &tmbuf;
}
static char *monthnames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
case T_FILE:
case T_BASE_FILE:
{
- char *string;
- if (hp->type == T_FILE)
- string = ip->nominal_fname;
- else
- string = instack[0].nominal_fname;
+ FILE_BUF *p = hp->type == T_FILE ? ip : &instack[0];
+ char *string = p->nominal_fname;
if (string)
{
- buf = (char *) alloca (3 + 4 * strlen (string));
- quote_string (buf, string);
+ size_t string_len = p->nominal_fname_len;
+ buf = (char *) alloca (3 + 4 * string_len);
+ quote_string (buf, string, string_len);
}
else
buf = "\"\"";
break;
case T_USER_LABEL_PREFIX_TYPE:
- buf = USER_LABEL_PREFIX;
+ buf = user_label_prefix;
break;
case T_REGISTER_PREFIX_TYPE:
|| (hp->type == T_MACRO && hp->value.defn->predefined)))
/* Output a precondition for this macro use. */
fprintf (pcp_outfile, "#define %s\n", hp->name);
- buf = " 1 ";
+ if (hp->type == T_POISON) {
+ error("attempt to use poisoned `%s'.", hp->name);
+ buf = " 0 ";
+ } else {
+ buf = " 1 ";
+ }
}
else
if (pcp_outfile && pcp_inside_if) {
}
break;
+ case T_POISON:
+ error("attempt to use poisoned `%s'.", hp->name);
+ buf = " 0 "; /* Consider poisoned symbol to not be defined */
+ break;
+
oops:
error ("`defined' without an identifier");
&& !instack[indepth].system_header_p && !import_warning) {
import_warning = 1;
warning ("using `#import' is not recommended");
- fprintf (stderr, "The fact that a certain header file need not be processed more than once\n");
- fprintf (stderr, "should be indicated in the header file, not where it is used.\n");
- fprintf (stderr, "The best way to do this is with a conditional of this form:\n\n");
- fprintf (stderr, " #ifndef _FOO_H_INCLUDED\n");
- fprintf (stderr, " #define _FOO_H_INCLUDED\n");
- fprintf (stderr, " ... <real contents of file> ...\n");
- fprintf (stderr, " #endif /* Not _FOO_H_INCLUDED */\n\n");
- fprintf (stderr, "Then users can use `#include' any number of times.\n");
- fprintf (stderr, "GNU C automatically avoids processing the file more than once\n");
- fprintf (stderr, "when it is equipped with such a conditional.\n");
+ notice ("The fact that a certain header file need not be processed more than once\n\
+should be indicated in the header file, not where it is used.\n\
+The best way to do this is with a conditional of this form:\n\
+\n\
+ #ifndef _FOO_H_INCLUDED\n\
+ #define _FOO_H_INCLUDED\n\
+ ... <real contents of file> ...\n\
+ #endif /* Not _FOO_H_INCLUDED */\n\
+\n\
+Then users can use `#include' any number of times.\n\
+GNU C automatically avoids processing the file more than once\n\
+when it is equipped with such a conditional.\n");
}
get_filename:
FILE_BUF *fp;
/* Copy the operand text, concatenating the strings. */
{
- while (fin != limit) {
- while (fin != limit && *fin != '\"')
- *fend++ = *fin++;
- fin++;
+ for (;;) {
+ for (;;) {
+ if (fin == limit)
+ goto invalid_include_file_name;
+ *fend = *fin++;
+ if (*fend == '"')
+ break;
+ fend++;
+ }
if (fin == limit)
break;
/* If not at the end, there had better be another string. */
/* Found a named file. Figure out dir of the file,
and put it in front of the search list. */
dsp = ((struct file_name_list *)
- alloca (sizeof (struct file_name_list) + strlen (nam)));
+ alloca (sizeof (struct file_name_list)
+ + fp->nominal_fname_len));
strcpy (dsp->fname, nam);
simplify_filename (dsp->fname);
nam = base_name (dsp->fname);
*nam = 0;
+#ifdef VMS
+ /* for hack_vms_include_specification(), a local
+ dir specification must start with "./" on VMS. */
+ if (nam == dsp->fname)
+ {
+ *nam++ = '.';
+ *nam++ = '/';
+ *nam = 0;
+ }
+#endif
/* But for efficiency's sake, do not insert the dir
if it matches the search list's first dir. */
dsp->next = search_start;
* code from case '<' is repeated here) and generates a warning.
* (Note: macro expansion of `xyz' takes precedence.)
*/
- if (retried && isalpha(*(U_CHAR *) (--fbeg))) {
- while (fin != limit && (!isspace(*fin)))
+ /* Note: The argument of ISALPHA() can be evaluated twice, so do
+ the pre-decrement outside of the macro. */
+ if (retried && (--fin, ISALPHA(*(U_CHAR *) (fin)))) {
+ while (fin != limit && (!ISSPACE(*fin)))
*fend++ = *fin++;
warning ("VAX-C-style include specification found, use '#include <filename.h>' !");
vaxc_include = 1;
#endif
fail:
- if (retried) {
- error ("`#%s' expects \"FILENAME\" or <FILENAME>", keyword->name);
- return 0;
- } else {
+ if (! retried) {
/* Expand buffer and then remove any newline markers.
We can't just tell expand_to_temp_buffer to omit the markers,
since it would put extra spaces in include file names. */
FILE_BUF trybuf;
U_CHAR *src;
+ int errors_before_expansion = errors;
trybuf = expand_to_temp_buffer (buf, limit, 1, 0);
+ if (errors != errors_before_expansion) {
+ free (trybuf.buf);
+ goto invalid_include_file_name;
+ }
src = trybuf.buf;
buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1);
limit = buf;
}
*limit = 0;
free (trybuf.buf);
- retried++;
+ retried = 1;
goto get_filename;
}
+
+ invalid_include_file_name:
+ error ("`#%s' expects \"FILENAME\" or <FILENAME>", keyword->name);
+ return 0;
}
/* For #include_next, skip in the search path
}
}
- strcpy (fname, searchptr->fname);
- strcat (fname, fbeg);
#ifdef VMS
/* Change this 1/2 Unix 1/2 VMS file specification into a
full VMS file specification */
- if (searchptr->fname[0]) {
- /* Fix up the filename */
- hack_vms_include_specification (fname, vaxc_include);
- } else {
- /* This is a normal VMS filespec, so use it unchanged. */
- strcpy (fname, fbeg);
- /* if it's '#include filename', add the missing .h */
- if (vaxc_include && index(fname,'.')==NULL) {
- strcat (fname, ".h");
+ if (searchptr->fname[0])
+ {
+ strcpy (fname, searchptr->fname);
+ if (fname[strlen (fname) - 1] == ':')
+ {
+ char *slashp;
+ slashp = strchr (fbeg, '/');
+
+ /* start at root-dir of logical device if no path given. */
+ if (slashp == 0)
+ strcat (fname, "[000000]");
+ }
+ strcat (fname, fbeg);
+
+ /* Fix up the filename */
+ hack_vms_include_specification (fname, vaxc_include);
}
- }
+ else
+ {
+ /* This is a normal VMS filespec, so use it unchanged. */
+ strcpy (fname, fbeg);
+ /* if it's '#include filename', add the missing .h */
+ if (vaxc_include && index(fname,'.')==NULL)
+ strcat (fname, ".h");
+ }
+#else
+ strcpy (fname, searchptr->fname);
+ strcat (fname, fbeg);
#endif /* VMS */
f = open_include_file (fname, searchptr, importing, &inc);
if (f != -1) {
/* Actually process the file */
if (pcfbuf) {
- pcfname = xmalloc (strlen (pcftry) + 1);
- strcpy (pcfname, pcftry);
- pcfinclude ((U_CHAR *) pcfbuf, (U_CHAR *) pcfbuflimit,
- (U_CHAR *) fname, op);
+ pcfname = xstrdup (pcftry);
+ pcfinclude ((U_CHAR *) pcfbuf, (U_CHAR *) fname, op);
}
else
finclude (f, inc, op, is_system_include (fname), searchptr);
char *s = fname;
char *p;
#if defined (__MSDOS__) || defined (_WIN32)
- if (isalpha (s[0]) && s[1] == ':') s += 2;
+ if (ISALPHA (s[0]) && s[1] == ':') s += 2;
#endif
#ifdef VMS
if ((p = rindex (s, ':'))) s = p + 1; /* Skip device. */
absolute_filename (filename)
char *filename;
{
-#if defined (__MSDOS__) || (defined (_WIN32) && !defined (__CYGWIN32__))
- if (isalpha (filename[0]) && filename[1] == ':') filename += 2;
+#if defined (__MSDOS__) \
+ || (defined (_WIN32) && !defined (__CYGWIN__) && !defined (_UWIN))
+ if (ISALPHA (filename[0]) && filename[1] == ':') filename += 2;
#endif
-#if defined (__CYGWIN32__)
+#if defined (__CYGWIN__)
/* At present, any path that begins with a drive spec is absolute. */
- if (isalpha (filename[0]) && filename[1] == ':') return 1;
+ if (ISALPHA (filename[0]) && filename[1] == ':') return 1;
+#endif
+#ifdef VMS
+ if (index (filename, ':') != 0) return 1;
#endif
if (filename[0] == '/') return 1;
#ifdef DIR_SEPARATOR
return 0;
}
+/* Returns whether or not a given character is a directory separator.
+ Used by simplify_filename. */
+static inline
+int
+is_dir_separator(ch)
+ char ch;
+{
+ return (ch == DIR_SEPARATOR)
+#if defined (DIR_SEPARATOR_2)
+ || (ch == DIR_SEPARATOR_2)
+#endif
+ ;
+}
+
/* Remove unnecessary characters from FILENAME in place,
to avoid unnecessary filename aliasing.
Return the length of the resulting string.
char *to0;
/* Remove redundant initial /s. */
- if (*from == '/') {
- *to++ = '/';
- if (*++from == '/') {
- if (*++from == '/') {
- /* 3 or more initial /s are equivalent to 1 /. */
- while (*++from == '/')
- continue;
- } else {
- /* On some hosts // differs from /; Posix allows this. */
- static int slashslash_vs_slash;
- if (slashslash_vs_slash == 0) {
- struct stat s1, s2;
- slashslash_vs_slash = ((stat ("/", &s1) == 0 && stat ("//", &s2) == 0
- && INO_T_EQ (s1.st_ino, s2.st_ino)
- && s1.st_dev == s2.st_dev)
- ? 1 : -1);
- }
- if (slashslash_vs_slash < 0)
- *to++ = '/';
- }
+ if (is_dir_separator (*from))
+ {
+ *to++ = DIR_SEPARATOR;
+ if (is_dir_separator (*++from))
+ {
+ if (is_dir_separator (*++from))
+ {
+ /* 3 or more initial /s are equivalent to 1 /. */
+ while (is_dir_separator (*++from))
+ continue;
+ }
+ else
+ {
+ /* On some hosts // differs from /; Posix allows this. */
+ *to++ = DIR_SEPARATOR;
+ }
+ }
}
- }
- to0 = to;
- for (;;) {
- if (from[0] == '.' && from[1] == '/')
- from += 2;
- else {
- /* Copy this component and trailing /, if any. */
- while ((*to++ = *from++) != '/') {
- if (!to[-1]) {
- /* Trim . component at end of nonempty name. */
- to -= filename <= to - 3 && to[-3] == '/' && to[-2] == '.';
-
- /* Trim unnecessary trailing /s. */
- while (to0 < --to && to[-1] == '/')
- continue;
+ to0 = to;
- *to = 0;
- return to - filename;
- }
- }
- }
+ for (;;)
+ {
+#ifndef VMS
+ if (from[0] == '.' && from[1] == '/')
+ from += 2;
+ else
+#endif
+ {
+ /* Copy this component and trailing DIR_SEPARATOR, if any. */
+ while (!is_dir_separator (*to++ = *from++))
+ {
+ if (!to[-1])
+ {
+ /* Trim . component at end of nonempty name. */
+ to -= filename <= to - 3 && to[-3] == DIR_SEPARATOR && to[-2] == '.';
+
+ /* Trim unnecessary trailing /s. */
+ while (to0 < --to && to[-1] == DIR_SEPARATOR)
+ continue;
+
+ *to = 0;
+ return to - filename;
+ }
+ }
+#if defined(DIR_SEPARATOR_2)
+ /* Simplify to one directory separator. */
+ to[-1] = DIR_SEPARATOR;
+#endif
+ }
/* Skip /s after a /. */
- while (*from == '/')
+ while (is_dir_separator (*from))
from++;
}
}
map_list_ptr = ((struct file_name_map_list *)
xmalloc (sizeof (struct file_name_map_list)));
- map_list_ptr->map_list_name = savestring (dirname);
+ map_list_ptr->map_list_name = xstrdup (dirname);
map_list_ptr->map_list_map = NULL;
dirlen = strlen (dirname);
fd = open (fname, O_RDONLY, 0);
if (fd < 0)
- return fd;
+ {
+#ifdef VMS
+ /* if #include <dir/file> fails, try again with hacked spec. */
+ if (!hack_vms_include_specification (fname, 0))
+ return fd;
+ fd = open (fname, O_RDONLY, 0);
+ if (fd < 0)
+#endif
+ return fd;
+ }
if (!inc) {
/* FNAME was not in include_hashtab; insert a new entry. */
return fd;
}
-/* Return the remapped name of the the include file FILENAME.
+/* Return the remapped name of the include file FILENAME.
SEARCHPTR is the directory being tried from the include file path. */
static char *
fp = &instack[indepth + 1];
bzero ((char *) fp, sizeof (FILE_BUF));
fp->nominal_fname = fp->fname = fname;
+ fp->nominal_fname_len = strlen (fname);
fp->inc = inc;
fp->length = 0;
fp->lineno = 1;
if (!no_trigraphs)
trigraph_pcp (fp);
+ if (warn_white_space)
+ check_white_space (fp);
+
output_line_directive (fp, op, 0, enter_file);
rescan (op, 0);
check_precompiled (pcf, st, fname, limit)
int pcf;
struct stat *st;
- char *fname;
+ char *fname ATTRIBUTE_UNUSED;
char **limit;
{
int length = 0;
in. OP is the main output buffer. */
static void
-pcfinclude (buf, limit, name, op)
- U_CHAR *buf, *limit, *name;
+pcfinclude (buf, name, op)
+ U_CHAR *buf, *name;
FILE_BUF *op;
{
FILE_BUF tmpbuf;
cp += 4 - ((size_t) cp & 3);
/* Now get the string. */
- str = (STRINGDEF *) (GENERIC_PTR) cp;
+ str = (STRINGDEF *) (PTR) cp;
string_start = cp += sizeof (STRINGDEF);
for (; *cp; cp++) /* skip the string */
tmpbuf = expand_to_temp_buffer (string_start, cp++, 0, 0);
/* Lineno is already set in the precompiled file */
str->contents = tmpbuf.buf;
- str->len = tmpbuf.length;
+ str->len = tmpbuf.bufp - tmpbuf.buf;
str->writeflag = 0;
str->filename = name;
str->output_mark = outbuf.bufp - outbuf.buf;
else
/* Otherwise, for each key, */
for (; nkeys--; free (tmpbuf.buf), cp = endofthiskey + 1) {
- KEYDEF *kp = (KEYDEF *) (GENERIC_PTR) cp;
+ KEYDEF *kp = (KEYDEF *) (PTR) cp;
HASHNODE *hp;
+ U_CHAR *bp;
/* It starts with a KEYDEF structure */
cp += sizeof (KEYDEF);
/* Expand the key, and enter it into the hash table. */
tmpbuf = expand_to_temp_buffer (cp, endofthiskey, 0, 0);
- tmpbuf.bufp = tmpbuf.buf;
+ bp = tmpbuf.buf;
- while (is_hor_space[*tmpbuf.bufp])
- tmpbuf.bufp++;
- if (!is_idstart[*tmpbuf.bufp]
- || tmpbuf.bufp == tmpbuf.buf + tmpbuf.length) {
+ while (is_hor_space[*bp])
+ bp++;
+ if (!is_idstart[*bp] || bp == tmpbuf.bufp) {
str->writeflag = 1;
continue;
}
- hp = lookup (tmpbuf.bufp, -1, -1);
+ hp = lookup (bp, -1, -1);
if (hp == NULL) {
kp->chain = 0;
- install (tmpbuf.bufp, -1, T_PCSTRING, (char *) kp, -1);
+ install (bp, -1, T_PCSTRING, (char *) kp, -1);
}
else if (hp->type == T_PCSTRING) {
kp->chain = hp->value.keydef;
line_directive_len *= 2);
sprintf (line_directive, "\n# %d ", next_string->lineno);
strcpy (quote_string (line_directive + strlen (line_directive),
- (char *) next_string->filename),
+ (char *) next_string->filename,
+ strlen ((char *) next_string->filename)),
"\n");
safe_write (fileno (stdout), line_directive, strlen (line_directive));
safe_write (fileno (stdout),
FILE_BUF *op;
struct directive *keyword;
{
- register unsigned keyword_length = keyword->length;
+ register int keyword_length = keyword->length;
check_expand (op, 1 + keyword_length + (limit - buf));
*op->bufp++ = '#';
int sym_length; /* and how long it is */
int line = instack[indepth].lineno;
char *file = instack[indepth].nominal_fname;
+ size_t file_len = instack[indepth].nominal_fname_len;
int rest_args = 0;
DEFINITION *defn;
bp++;
symname = bp; /* remember where it starts */
- sym_length = check_macro_name (bp, "macro");
+ sym_length = check_macro_name (bp, 0);
bp += sym_length;
/* Lossage will occur if identifiers or control keywords are broken
rest_extension);
if (!is_idstart[*bp])
+ {
+ if (c9x && limit - bp > (long) REST_EXTENSION_LENGTH
+ && bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0)
+ {
+ /* This is the ISO C 9x way to write macros with variable
+ number of arguments. */
+ rest_args = 1;
+ temp->rest_args = 1;
+ }
+ else
pedwarn ("invalid character in macro parameter name");
+ }
/* Find the end of the arg name. */
while (is_idchar[*bp]) {
bp++;
/* do we have a "special" rest-args extension here? */
- if (limit - bp > REST_EXTENSION_LENGTH
+ if (limit - bp > (long) REST_EXTENSION_LENGTH
&& bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) {
if (pedantic && !instack[indepth].system_header_p)
pedwarn ("ANSI C does not allow macro with variable arguments");
break;
}
}
+ if (bp == temp->name && rest_args == 1)
+ {
+ /* This is the ISO C 9x style. */
+ temp->name = (U_CHAR *) va_args_name;
+ temp->length = VA_ARGS_NAME_LENGTH;
+ }
+ else
temp->length = bp - temp->name;
if (rest_args == 1)
bp += REST_EXTENSION_LENGTH;
bp++;
SKIP_WHITE_SPACE (bp);
/* A comma at this point can only be followed by an identifier. */
- if (!is_idstart[*bp]) {
+ if (!is_idstart[*bp]
+ && !(c9x && limit - bp > (long) REST_EXTENSION_LENGTH
+ && bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0)) {
error ("badly punctuated parameter list in `#define'");
goto nope;
}
for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
if (temp->length == otemp->length
- && bcmp (temp->name, otemp->name, temp->length) == 0) {
+ && bcmp (temp->name, otemp->name, temp->length) == 0)
+ {
error ("duplicate argument name `%.*s' in `#define'",
temp->length, temp->name);
goto nope;
}
+ if (rest_args == 0 && temp->length == VA_ARGS_NAME_LENGTH
+ && bcmp (temp->name, va_args_name, VA_ARGS_NAME_LENGTH) == 0)
+ {
+ error ("\
+reserved name `%s' used as argument name in `#define'", va_args_name);
+ goto nope;
+ }
}
}
defn->line = line;
defn->file = file;
+ defn->file_len = file_len;
/* OP is null if this is a predefinition */
defn->predefined = !op;
{
int hashcode;
MACRODEF mdef;
+ enum node_type newtype = keyword->type == T_DEFINE ? T_MACRO : T_POISON;
/* If this is a precompiler run (with -pcp) pass thru #define directives. */
if (pcp_outfile && op)
/* Redefining a precompiled key is ok. */
if (hp->type == T_PCSTRING)
ok = 1;
+ /* Redefining a poisoned identifier is even worse than `not ok'. */
+ else if (hp->type == T_POISON)
+ ok = -1;
+ /* Poisoning anything else is not ok.
+ The poison should always come first. */
+ else if (newtype == T_POISON)
+ ok = 0;
/* Redefining a macro is ok if the definitions are the same. */
else if (hp->type == T_MACRO)
ok = ! compare_defs (mdef.defn, hp->value.defn);
/* Redefining a constant is ok with -D. */
else if (hp->type == T_CONST)
ok = ! done_initializing;
- /* Print the warning if it's not ok. */
- if (!ok) {
- /* If we are passing through #define and #undef directives, do
- that for this re-definition now. */
- if (debug_output && op)
- pass_thru_directive (buf, limit, op, keyword);
-
- pedwarn ("`%.*s' redefined", mdef.symlen, mdef.symnam);
- if (hp->type == T_MACRO)
- pedwarn_with_file_and_line (hp->value.defn->file, hp->value.defn->line,
- "this is the location of the previous definition");
- }
- /* Replace the old definition. */
- hp->type = T_MACRO;
- hp->value.defn = mdef.defn;
+
+ /* Print the warning or error if it's not ok. */
+ if (ok <= 0)
+ {
+ /* If we are passing through #define and #undef directives, do
+ that for this re-definition now. */
+ if (debug_output && op)
+ pass_thru_directive (buf, limit, op, keyword);
+
+ if (hp->type == T_POISON)
+ error ("redefining poisoned `%.*s'", mdef.symlen, mdef.symnam);
+ else
+ pedwarn ("`%.*s' redefined", mdef.symlen, mdef.symnam);
+ if (hp->type == T_MACRO)
+ pedwarn_with_file_and_line (hp->value.defn->file,
+ hp->value.defn->file_len,
+ hp->value.defn->line,
+ "this is the location of the previous definition");
+ }
+ if (hp->type != T_POISON)
+ {
+ /* Replace the old definition. */
+ hp->type = newtype;
+ hp->value.defn = mdef.defn;
+ }
} else {
/* If we are passing through #define and #undef directives, do
that for this new definition now. */
if (debug_output && op)
pass_thru_directive (buf, limit, op, keyword);
- install (mdef.symnam, mdef.symlen, T_MACRO,
+ install (mdef.symnam, mdef.symlen, newtype,
(char *) mdef.defn, hashcode);
}
}
}
\f
/* Check a purported macro name SYMNAME, and yield its length.
- USAGE is the kind of name this is intended for. */
+ ASSERTION is nonzero if this is really for an assertion name. */
static int
-check_macro_name (symname, usage)
+check_macro_name (symname, assertion)
U_CHAR *symname;
- char *usage;
+ int assertion;
{
U_CHAR *p;
int sym_length;
sym_length = p - symname;
if (sym_length == 0
|| (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
- error ("invalid %s name", usage);
+ error (assertion ? "invalid assertion name" : "invalid macro name");
else if (!is_idstart[*symname]
|| (sym_length == 7 && ! bcmp (symname, "defined", 7)))
- error ("invalid %s name `%.*s'", usage, sym_length, symname);
+ error ((assertion
+ ? "invalid assertion name `%.*s'"
+ : "invalid macro name `%.*s'"),
+ sym_length, symname);
return sym_length;
}
break;
case '\\':
- if (p < limit && expected_delimiter) {
+ if (expected_delimiter) {
/* In a string, backslash goes through
and makes next char ordinary. */
*exp_p++ = *p++;
}
} else {
/* In -traditional mode, recognize arguments inside strings and
- and character constants, and ignore special properties of #.
+ character constants, and ignore special properties of #.
Arguments inside strings are considered "stringified", but no
extra quote marks are supplied. */
switch (c) {
}
}
+#ifdef MULTIBYTE_CHARS
+ /* Handle multibyte characters inside string and character literals. */
+ if (expected_delimiter != '\0')
+ {
+ int length;
+ --p;
+ length = local_mblen (p, limit - p);
+ if (length > 1)
+ {
+ --exp_p;
+ bcopy (p, exp_p, length);
+ p += length;
+ exp_p += length;
+ continue;
+ }
+ ++p;
+ }
+#endif
+
/* Handle the start of a symbol. */
if (is_idchar[c] && nargs > 0) {
U_CHAR *id_beg = p - 1;
static int
do_assert (buf, limit, op, keyword)
U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
U_CHAR *bp; /* temp ptr into input buffer */
U_CHAR *symname; /* remember where symbol name starts */
bp++;
symname = bp; /* remember where it starts */
- sym_length = check_macro_name (bp, "assertion");
+ sym_length = check_macro_name (bp, 1);
bp += sym_length;
/* #define doesn't do this, but we should. */
SKIP_WHITE_SPACE (bp);
static int
do_unassert (buf, limit, op, keyword)
U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
U_CHAR *bp; /* temp ptr into input buffer */
U_CHAR *symname; /* remember where symbol name starts */
bp++;
symname = bp; /* remember where it starts */
- sym_length = check_macro_name (bp, "assertion");
+ sym_length = check_macro_name (bp, 1);
bp += sym_length;
/* #define doesn't do this, but we should. */
SKIP_WHITE_SPACE (bp);
return hp;
}
-/* Find the most recent hash node for name name (ending with first
+/* Find the most recent hash node for name "name" (ending with first
non-identifier char) installed by install
If LEN is >= 0, it is the length of the name.
do_line (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
register U_CHAR *bp;
FILE_BUF *ip = &instack[indepth];
/* Point to macroexpanded line, which is null-terminated now. */
bp = tem.buf;
+ limit = tem.bufp;
SKIP_WHITE_SPACE (bp);
- if (!isdigit (*bp)) {
+ if (!ISDIGIT (*bp)) {
error ("invalid format `#line' directive");
return 0;
}
pedwarn ("line number out of range in `#line' directive");
/* skip over the line number. */
- while (isdigit (*bp))
+ while (ISDIGIT (*bp))
bp++;
#if 0 /* #line 10"foo.c" is supposed to be allowed. */
p = bp;
for (;;)
switch ((*p++ = *bp++)) {
- case '\0':
- error ("invalid format `#line' directive");
- return 0;
-
case '\\':
- {
- char *bpc = (char *) bp;
- HOST_WIDE_INT c = parse_escape (&bpc, (HOST_WIDE_INT) (U_CHAR) (-1));
- bp = (U_CHAR *) bpc;
- if (c < 0)
- p--;
- else
- p[-1] = c;
- }
+ if (! ignore_escape_flag)
+ {
+ char *bpc = (char *) bp;
+ HOST_WIDEST_INT c = parse_escape (&bpc, (HOST_WIDEST_INT) (U_CHAR) (-1));
+ bp = (U_CHAR *) bpc;
+ if (c < 0)
+ p--;
+ else
+ p[-1] = c;
+ }
break;
case '\"':
- p[-1] = 0;
+ *--p = 0;
goto fname_done;
}
fname_done:
if (hp->length == fname_length &&
bcmp (hp->value.cpval, fname, fname_length) == 0) {
ip->nominal_fname = hp->value.cpval;
+ ip->nominal_fname_len = fname_length;
break;
}
if (hp == 0) {
hp->next = *hash_bucket;
*hash_bucket = hp;
- hp->length = fname_length;
ip->nominal_fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE);
- bcopy (fname, hp->value.cpval, fname_length);
+ ip->nominal_fname_len = hp->length = fname_length;
+ bcopy (fname, hp->value.cpval, fname_length + 1);
}
} else if (*bp) {
error ("invalid format `#line' directive");
pass_thru_directive (buf, limit, op, keyword);
SKIP_WHITE_SPACE (buf);
- sym_length = check_macro_name (buf, "macro");
+ sym_length = check_macro_name (buf, 0);
while ((hp = lookup (buf, sym_length, -1)) != NULL) {
/* If we are generating additional info for debugging (with -g) we
need to pass through all effective #undef directives. */
if (debug_output && op)
pass_thru_directive (orig_buf, limit, op, keyword);
- if (hp->type != T_MACRO)
- warning ("undefining `%s'", hp->name);
- delete_macro (hp);
+ if (hp->type == T_POISON)
+ error ("cannot undefine poisoned `%s'", hp->name);
+ else {
+ if (hp->type != T_MACRO)
+ warning ("undefining `%s'", hp->name);
+ delete_macro (hp);
+ }
}
if (pedantic) {
return 0;
}
\f
+
/* Report an error detected by the program we are processing.
- Use the text of the line in the error message.
- (We use error because it prints the filename & line#.) */
+ Use the text of the line in the error message. */
static int
do_error (buf, limit, op, keyword)
U_CHAR *buf, *limit;
- FILE_BUF *op;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
struct directive *keyword;
{
int length = limit - buf;
bcopy ((char *) buf, (char *) copy, length);
copy[length] = 0;
SKIP_WHITE_SPACE (copy);
- error ("#error %s", copy);
- return 0;
-}
-/* Report a warning detected by the program we are processing.
- Use the text of the line in the warning message, then continue.
- (We use error because it prints the filename & line#.) */
+ switch (keyword->type) {
+ case T_ERROR:
+ error ("#error %s", copy);
+ break;
+
+ case T_WARNING:
+ if (pedantic && !instack[indepth].system_header_p)
+ pedwarn ("ANSI C does not allow `#warning'");
+ warning ("#warning %s", copy);
+ break;
+
+ default:
+ abort ();
+ }
-static int
-do_warning (buf, limit, op, keyword)
- U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
-{
- int length = limit - buf;
- U_CHAR *copy = (U_CHAR *) alloca (length + 1);
- bcopy ((char *) buf, (char *) copy, length);
- copy[length] = 0;
- SKIP_WHITE_SPACE (copy);
- /* Use `pedwarn' not `warning', because #warning isn't in the C Standard;
- if -pedantic-errors is given, #warning should cause an error. */
- pedwarn ("#warning %s", copy);
return 0;
}
-
/* Remember the name of the current file being read from so that we can
avoid ever including it again. */
do_ident (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
FILE_BUF trybuf;
int len;
do_once ();
}
+ if (!strncmp (buf, "poison", 6)) {
+ /* Poison these symbols so that all subsequent usage produces an
+ error message. */
+ U_CHAR *p = buf + 6;
+
+ SKIP_WHITE_SPACE (p);
+ while (p < limit)
+ {
+ U_CHAR *end = p;
+
+ while (end < limit && is_idchar[*end])
+ end++;
+ if (end < limit && !is_space[*end])
+ {
+ error ("invalid #pragma poison");
+ return 0;
+ }
+ do_define(p, end, op, keyword);
+ p = end;
+ SKIP_WHITE_SPACE (p);
+ }
+ }
+
if (!strncmp ((char *) buf, "implementation", 14)) {
/* Be quiet about `#pragma implementation' for a file only if it hasn't
been included yet. */
return 0;
fname = p + 1;
- if ((p = (U_CHAR *) index ((char *) fname, '\"')))
- *p = '\0';
+ p = skip_quoted_string (p, limit, 0, NULL_PTR, NULL_PTR, NULL_PTR);
+ if (p[-1] == '"')
+ *--p = '\0';
for (h = 0; h < INCLUDE_HASHSIZE; h++) {
struct include_file *inc;
static int
do_sccs (buf, limit, op, keyword)
- U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
if (pedantic)
pedwarn ("ANSI C does not allow `#sccs'");
do_if (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
- HOST_WIDE_INT value;
+ HOST_WIDEST_INT value;
FILE_BUF *ip = &instack[indepth];
value = eval_if_expression (buf, limit - buf);
do_elif (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
- HOST_WIDE_INT value;
+ HOST_WIDEST_INT value;
FILE_BUF *ip = &instack[indepth];
if (if_stack == instack[indepth].if_stack) {
if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
error ("`#elif' after `#else'");
fprintf (stderr, " (matches line %d", if_stack->lineno);
- if (if_stack->fname != NULL && ip->fname != NULL
- && strcmp (if_stack->fname, ip->nominal_fname) != 0)
- fprintf (stderr, ", file %s", if_stack->fname);
+ if (! (if_stack->fname_len == ip->nominal_fname_len
+ && !bcmp (if_stack->fname, ip->nominal_fname,
+ if_stack->fname_len))) {
+ fprintf (stderr, ", file ");
+ fwrite (if_stack->fname, sizeof if_stack->fname[0],
+ if_stack->fname_len, stderr);
+ }
fprintf (stderr, ")\n");
}
if_stack->type = T_ELIF;
/* Evaluate a #if expression in BUF, of length LENGTH, then parse the
result as a C expression and return the value as an int. */
-static HOST_WIDE_INT
+static HOST_WIDEST_INT
eval_if_expression (buf, length)
U_CHAR *buf;
int length;
{
FILE_BUF temp_obuf;
HASHNODE *save_defined;
- HOST_WIDE_INT value;
+ HOST_WIDEST_INT value;
save_defined = install ((U_CHAR *) "defined", -1, T_SPEC_DEFINED,
NULL_PTR, -1);
pcp_inside_if = 0;
delete_macro (save_defined); /* clean up special symbol */
- temp_obuf.buf[temp_obuf.length] = '\n';
+ *temp_obuf.bufp = '\n';
value = parse_c_expression ((char *) temp_obuf.buf,
warn_undef && !instack[indepth].system_header_p);
HASHNODE *hp;
if (! traditional) {
- if (isdigit (buf[0]))
+ if (ISDIGIT (buf[0]))
pedwarn ("`#%s' argument starts with a digit", keyword->name);
else if (end != limit)
pedwarn ("garbage at end of `#%s' argument", keyword->name);
}
}
+ if ((hp != NULL) && (hp->type == T_POISON)) {
+ error("attempt to use poisoned `%s'.", hp->name);
+ hp = NULL;
+ }
skip = (hp == NULL) ^ (keyword->type == T_IFNDEF);
if (start_of_file && !skip) {
control_macro = (U_CHAR *) xmalloc (end - buf + 1);
temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
temp->fname = ip->nominal_fname;
+ temp->fname_len = ip->nominal_fname_len;
temp->lineno = ip->lineno;
temp->next = if_stack;
temp->control_macro = control_macro;
/* Save info about where the group starts. */
U_CHAR *beg_of_group = bp;
int beg_lineno = ip->lineno;
+ int skipping_include_directive = 0;
if (output_conditionals && op != 0) {
char *ptr = "#failed\n";
while (bp < endb) {
switch (*bp++) {
case '/': /* possible comment */
- if (*bp == '\\' && bp[1] == '\n')
+ if (*bp == '\\')
newline_fix (bp);
if (*bp == '*'
|| (cplusplus_comments && *bp == '/')) {
bp = skip_to_end_of_comment (ip, &ip->lineno, 0);
}
break;
+ case '<':
+ if (skipping_include_directive) {
+ while (bp < endb && *bp != '>' && *bp != '\n') {
+ if (*bp == '\\' && bp[1] == '\n') {
+ ip->lineno++;
+ bp++;
+ }
+ bp++;
+ }
+ }
+ break;
case '\"':
+ if (skipping_include_directive) {
+ while (bp < endb && *bp != '\n') {
+ if (*bp == '"') {
+ bp++;
+ break;
+ }
+ if (*bp == '\\' && bp[1] == '\n') {
+ ip->lineno++;
+ bp++;
+ }
+ bp++;
+ }
+ break;
+ }
+ /* Fall through. */
case '\'':
bp = skip_quoted_string (bp - 1, endb, ip->lineno, &ip->lineno,
NULL_PTR, NULL_PTR);
break;
case '\\':
- /* Char after backslash loses its special meaning. */
- if (bp < endb) {
- if (*bp == '\n')
- ++ip->lineno; /* But do update the line-count. */
+ /* Char after backslash loses its special meaning in some cases. */
+ if (*bp == '\n') {
+ ++ip->lineno;
+ bp++;
+ } else if (traditional && bp < endb)
bp++;
- }
break;
case '\n':
++ip->lineno;
beg_of_line = bp;
+ skipping_include_directive = 0;
break;
case '%':
if (beg_of_line == 0 || traditional)
bp += 2;
else if (*bp == '/' && bp[1] == '*') {
bp += 2;
- while (!(*bp == '*' && bp[1] == '/'))
- bp++;
- bp += 2;
+ while (1)
+ {
+ if (*bp == '*')
+ {
+ if (bp[1] == '/')
+ {
+ bp += 2;
+ break;
+ }
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (bp, endb - bp);
+ if (length > 1)
+ bp += (length - 1);
+#endif
+ }
+ bp++;
+ }
}
/* There is no point in trying to deal with C++ // comments here,
because if there is one, then this # must be part of the
else if (*bp == '\\' && bp[1] == '\n')
bp += 2;
else if (*bp == '/') {
+ if (bp[1] == '\\')
+ newline_fix (bp + 1);
if (bp[1] == '*') {
for (bp += 2; ; bp++) {
if (*bp == '\n')
else if (*bp == '*') {
if (bp[-1] == '/' && warn_comments)
warning ("`/*' within comment");
+ if (bp[1] == '\\')
+ newline_fix (bp + 1);
if (bp[1] == '/')
break;
}
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (bp, endb - bp);
+ if (length > 1)
+ bp += (length - 1);
+#endif
+ }
}
bp += 2;
} else if (bp[1] == '/' && cplusplus_comments) {
for (bp += 2; ; bp++) {
- if (*bp == '\n') {
- if (bp[-1] != '\\')
- break;
- if (warn_comments)
- warning ("multiline `//' comment");
- ip->lineno++;
- }
+ if (*bp == '\n')
+ break;
+ if (*bp == '\\' && bp[1] == '\n')
+ {
+ if (warn_comments)
+ warning ("multiline `//' comment");
+ ip->lineno++;
+ bp++;
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (bp, endb - bp);
+ if (length > 1)
+ bp += (length - 1);
+#endif
+ }
}
} else
break;
if (is_idchar[*bp])
bp++;
else {
- if (*bp == '\\' && bp[1] == '\n')
+ if (*bp == '\\')
name_newline_fix (bp);
if (is_idchar[*bp])
bp++;
if_stack = temp;
temp->lineno = ip->lineno;
temp->fname = ip->nominal_fname;
+ temp->fname_len = ip->nominal_fname_len;
temp->type = kt->type;
break;
case T_ELSE:
free (temp);
break;
- default:
+ case T_INCLUDE:
+ case T_INCLUDE_NEXT:
+ case T_IMPORT:
+ skipping_include_directive = 1;
+ break;
+
+ default:
break;
}
break;
do_else (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
FILE_BUF *ip = &instack[indepth];
if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
error ("`#else' after `#else'");
fprintf (stderr, " (matches line %d", if_stack->lineno);
- if (strcmp (if_stack->fname, ip->nominal_fname) != 0)
- fprintf (stderr, ", file %s", if_stack->fname);
+ if (! (if_stack->fname_len == ip->nominal_fname_len
+ && !bcmp (if_stack->fname, ip->nominal_fname,
+ if_stack->fname_len))) {
+ fprintf (stderr, ", file ");
+ fwrite (if_stack->fname, sizeof if_stack->fname[0],
+ if_stack->fname_len, stderr);
+ }
fprintf (stderr, ")\n");
}
if_stack->type = T_ELSE;
do_endif (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
if (pedantic) {
SKIP_WHITE_SPACE (buf);
break;
}
}
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (p, limit - p);
+ if (length > 1)
+ p += (length - 1);
+#endif
+ }
}
}
else if (cplusplus_comments && p[1] == '/')
}
if (cplusplus_comments && bp[-1] == '/') {
for (; bp < limit; bp++) {
- if (*bp == '\n') {
- if (bp[-1] != '\\')
- break;
- if (!nowarn && warn_comments)
- warning ("multiline `//' comment");
- if (line_counter)
- ++*line_counter;
- if (op)
- ++op->lineno;
- }
+ if (*bp == '\n')
+ break;
+ if (*bp == '\\' && bp + 1 < limit && bp[1] == '\n')
+ {
+ if (!nowarn && warn_comments)
+ warning ("multiline `//' comment");
+ if (line_counter)
+ ++*line_counter;
+ if (op)
+ {
+ ++op->lineno;
+ *op->bufp++ = *bp;
+ }
+ ++bp;
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (bp, limit - bp);
+ if (length > 1)
+ {
+ if (op)
+ {
+ bcopy (bp, op->bufp, length - 1);
+ op->bufp += (length - 1);
+ }
+ bp += (length - 1);
+ }
+#endif
+ }
if (op)
*op->bufp++ = *bp;
}
case '*':
if (bp[-2] == '/' && !nowarn && warn_comments)
warning ("`/*' within comment");
- if (*bp == '\\' && bp[1] == '\n')
+ if (*bp == '\\')
newline_fix (bp);
if (*bp == '/') {
if (op)
return bp;
}
break;
+#ifdef MULTIBYTE_CHARS
+ default:
+ {
+ int length;
+ bp--;
+ length = local_mblen (bp, limit - bp);
+ if (length <= 0)
+ length = 1;
+ if (op)
+ {
+ op->bufp--;
+ bcopy (bp, op->bufp, length);
+ op->bufp += length;
+ }
+ bp += length;
+ }
+#endif
}
}
The input stack state is not changed.
If COUNT_NEWLINES is nonzero, it points to an int to increment
- for each newline passed.
+ for each newline passed; also, warn about any white space
+ just before line end.
If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it
if we pass a backslash-newline.
++*count_newlines;
bp += 2;
}
- if (*bp == '\n' && count_newlines) {
+ if (*bp == '\n') {
if (backslash_newlines_p)
*backslash_newlines_p = 1;
- ++*count_newlines;
+ if (count_newlines)
+ ++*count_newlines;
}
bp++;
} else if (c == '\n') {
}
if (match == '\'') {
error_with_line (line_for_error (start_line),
- "unterminated string or character constant");
+ "unterminated character constant");
bp--;
if (eofp)
*eofp = 1;
break;
}
/* If not traditional, then allow newlines inside strings. */
- if (count_newlines)
+ if (count_newlines) {
+ if (warn_white_space && is_hor_space[bp[-2]])
+ warning ("white space at end of line in string");
++*count_newlines;
+ }
if (multiline_string_line == 0) {
if (pedantic)
pedwarn_with_line (line_for_error (start_line),
}
} else if (c == match)
break;
+#ifdef MULTIBYTE_CHARS
+ {
+ int length;
+ --bp;
+ length = local_mblen (bp, limit - bp);
+ if (length <= 0)
+ length = 1;
+ bp += length;
+ }
+#endif
}
return bp;
}
/* Place into DST a quoted string representing the string SRC.
+ SRCLEN is the length of SRC; SRC may contain null bytes.
Return the address of DST's terminating null. */
static char *
-quote_string (dst, src)
+quote_string (dst, src, srclen)
char *dst, *src;
+ size_t srclen;
{
U_CHAR c;
+ char *srclim = src + srclen;
*dst++ = '\"';
- for (;;)
+ while (src != srclim)
switch ((c = *src++))
{
default:
- if (isprint (c))
+ if (ISPRINT (c))
*dst++ = c;
else
{
*dst++ = '\\';
*dst++ = c;
break;
-
- case '\0':
- *dst++ = '\"';
- *dst = '\0';
- return dst;
}
+
+ *dst++ = '\"';
+ *dst = '\0';
+ return dst;
}
/* Skip across a group of balanced parens, starting from IP->bufp.
ip->bufp++;
}
- line_directive_buf = (char *) alloca (4 * strlen (ip->nominal_fname) + 100);
+ line_directive_buf = (char *) alloca (4 * ip->nominal_fname_len + 100);
sprintf (line_directive_buf, "# %d ", ip->lineno);
line_end = quote_string (line_directive_buf + strlen (line_directive_buf),
- ip->nominal_fname);
+ ip->nominal_fname, ip->nominal_fname_len);
if (file_change != same_file) {
*line_end++ = ' ';
*line_end++ = file_change == enter_file ? '1' : '2';
/* This structure represents one parsed argument in a macro call.
`raw' points to the argument text as written (`raw_length' is its length).
`expanded' points to the argument's macro-expansion
- (its length is `expand_length').
- `stringified_length' is the length the argument would have
- if stringified.
+ (its length is `expand_length', and its allocated size is `expand_size').
+ `stringified_length_bound' is an upper bound on the length
+ the argument would have if stringified.
`use_count' is the number of times this macro arg is substituted
into the macro. If the actual use count exceeds 10,
the value stored is 10.
struct argdata {
U_CHAR *raw, *expanded;
- int raw_length, expand_length;
- int stringified_length;
+ int raw_length, expand_length, expand_size;
+ int stringified_length_bound;
U_CHAR *free1, *free2;
char newlines;
char use_count;
if (nargs >= 0) {
register int i;
struct argdata *args;
- char *parse_error = 0;
+ int parse_error = 0;
args = (struct argdata *) alloca ((nargs + 1) * sizeof (struct argdata));
for (i = 0; i < nargs; i++) {
args[i].raw = (U_CHAR *) "";
args[i].expanded = 0;
- args[i].raw_length = args[i].expand_length
- = args[i].stringified_length = 0;
+ args[i].raw_length = args[i].expand_length = args[i].expand_size
+ = args[i].stringified_length_bound = 0;
args[i].free1 = args[i].free2 = 0;
args[i].use_count = 0;
}
else
parse_error = macarg (NULL_PTR, 0);
if (parse_error) {
- error_with_line (line_for_error (start_line), parse_error);
+ error_with_line (line_for_error (start_line),
+ "unterminated macro call");
break;
}
i++;
xbuf_len = defn->length;
for (ap = defn->pattern; ap != NULL; ap = ap->next) {
if (ap->stringify)
- xbuf_len += args[ap->argno].stringified_length;
+ xbuf_len += args[ap->argno].stringified_length_bound;
else if (ap->raw_before != 0 || ap->raw_after != 0 || traditional)
/* Add 4 for two newline-space markers to prevent
token concatenation. */
1, 0);
args[ap->argno].expanded = obuf.buf;
- args[ap->argno].expand_length = obuf.length;
+ args[ap->argno].expand_length = obuf.bufp - obuf.buf;
+ args[ap->argno].expand_size = obuf.length;
args[ap->argno].free2 = obuf.buf;
- }
+ xbuf_len += args[ap->argno].expand_length;
+ } else {
+ /* If the arg appears more than once, its later occurrences
+ may have newline turned into backslash-'n', which is a
+ factor of 2 expansion. */
+ xbuf_len += 2 * args[ap->argno].expand_length;
+ }
/* Add 4 for two newline-space markers to prevent
token concatenation. */
- xbuf_len += args[ap->argno].expand_length + 4;
+ xbuf_len += 4;
}
if (args[ap->argno].use_count < 10)
args[ap->argno].use_count++;
for (; i < arglen; i++) {
c = arg->raw[i];
- /* Special markers Newline Space
- generate nothing for a stringified argument. */
- if (c == '\n' && arg->raw[i+1] != '\n') {
- i++;
- continue;
- }
-
- /* Internal sequences of whitespace are replaced by one space
- except within an string or char token. */
- if (! in_string
- && (c == '\n' ? arg->raw[i+1] == '\n' : is_space[c])) {
- while (1) {
- /* Note that Newline Space does occur within whitespace
- sequences; consider it part of the sequence. */
- if (c == '\n' && is_space[arg->raw[i+1]])
- i += 2;
- else if (c != '\n' && is_space[c])
- i++;
- else break;
- c = arg->raw[i];
- }
- i--;
- c = ' ';
+ if (in_string) {
+ /* Generate nothing for backslash-newline in a string. */
+ if (c == '\\' && arg->raw[i + 1] == '\n') {
+ i++;
+ continue;
+ }
+ } else {
+ /* Special markers
+ generate nothing for a stringified argument. */
+ if (c == '\n') {
+ i++;
+ continue;
+ }
+
+ /* Internal sequences of whitespace are replaced by one space
+ except within a string or char token. */
+ if (is_space[c]) {
+ i++;
+ while (is_space[(c = arg->raw[i])])
+ /* Newline markers can occur within a whitespace sequence;
+ consider them part of the sequence. */
+ i += (c == '\n') + 1;
+ i--;
+ c = ' ';
+ }
}
if (escaped)
else {
if (c == '\\')
escaped = 1;
- if (in_string) {
+ else if (in_string) {
if (c == in_string)
in_string = 0;
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (arg->raw + i, arglen - i);
+ if (length > 1)
+ {
+ bcopy (arg->raw + i, xbuf + totlen, length);
+ i += length - 1;
+ totlen += length;
+ continue;
+ }
+#endif
+ }
} else if (c == '\"' || c == '\'')
in_string = c;
}
- /* Escape these chars */
- if (c == '\"' || (in_string && c == '\\'))
+ /* Escape double-quote, and backslashes in strings.
+ Newlines in strings are best escaped as \n, since
+ otherwise backslash-backslash-newline-newline is
+ mishandled. The C Standard doesn't allow newlines in
+ strings, so we can escape newlines as we please. */
+ if (c == '\"'
+ || (in_string
+ && (c == '\\'
+ || (c == '\n' ? (c = 'n', 1) : 0))))
xbuf[totlen++] = '\\';
- if (isprint (c))
- xbuf[totlen++] = c;
- else {
- sprintf ((char *) &xbuf[totlen], "\\%03o", (unsigned int) c);
- totlen += 4;
- }
+ /* We used to output e.g. \008 for control characters here,
+ but this doesn't conform to the C Standard.
+ Just output the characters as-is. */
+ xbuf[totlen++] = c;
}
if (!traditional)
xbuf[totlen++] = '\"'; /* insert ending quote */
/* Don't bother doing change_newlines for subsequent
uses of arg. */
arg->use_count = 1;
- arg->expand_length
- = change_newlines (arg->expanded, arg->expand_length);
+ change_newlines (arg);
}
}
ip2->fname = 0;
ip2->nominal_fname = 0;
+ ip2->nominal_fname_len = 0;
ip2->inc = 0;
/* This may not be exactly correct, but will give much better error
messages for nested macro calls than using a line number of zero. */
REST_ARGS is passed to macarg1 to make it absorb the rest of the args.
Return nonzero to indicate a syntax error. */
-static char *
+static int
macarg (argptr, rest_args)
register struct argdata *argptr;
int rest_args;
{
FILE_BUF *ip = &instack[indepth];
int paren = 0;
- int newlines = 0;
+ int lineno0 = ip->lineno;
int comments = 0;
- char *result = 0;
+ int result = 0;
/* Try to parse as much of the argument as exists at this
input stack level. */
- U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length,
- &paren, &newlines, &comments, rest_args);
+ U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro,
+ &paren, &ip->lineno, &comments, rest_args);
/* If we find the end of the argument at this level,
set up *ARGPTR to point at it in the input stack. */
- if (!(ip->fname != 0 && (newlines != 0 || comments != 0))
+ if (!(ip->fname != 0 && (ip->lineno != lineno0 || comments != 0))
&& bp != ip->buf + ip->length) {
if (argptr != 0) {
argptr->raw = ip->bufp;
argptr->raw_length = bp - ip->bufp;
- argptr->newlines = newlines;
+ argptr->newlines = ip->lineno - lineno0;
}
ip->bufp = bp;
} else {
Therefore, we must allocate a temporary buffer and copy
the macro argument into it. */
int bufsize = bp - ip->bufp;
- int extra = newlines;
+ int extra = ip->lineno - lineno0;
U_CHAR *buffer = (U_CHAR *) xmalloc (bufsize + extra + 1);
int final_start = 0;
bcopy ((char *) ip->bufp, (char *) buffer, bufsize);
ip->bufp = bp;
- ip->lineno += newlines;
while (bp == ip->buf + ip->length) {
if (instack[indepth].macro == 0) {
- result = "unterminated macro call";
+ result = 1;
break;
}
ip->macro->type = T_MACRO;
if (ip->free_ptr)
free (ip->free_ptr);
ip = &instack[--indepth];
- newlines = 0;
+ lineno0 = ip->lineno;
comments = 0;
- bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
- &newlines, &comments, rest_args);
+ bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro, &paren,
+ &ip->lineno, &comments, rest_args);
final_start = bufsize;
bufsize += bp - ip->bufp;
- extra += newlines;
+ extra += ip->lineno - lineno0;
buffer = (U_CHAR *) xrealloc (buffer, bufsize + extra + 1);
bcopy ((char *) ip->bufp, (char *) (buffer + bufsize - (bp - ip->bufp)),
bp - ip->bufp);
ip->bufp = bp;
- ip->lineno += newlines;
}
/* Now, if arg is actually wanted, record its raw form,
argptr->raw = buffer;
argptr->raw_length = bufsize;
argptr->free1 = buffer;
- argptr->newlines = newlines;
- if ((newlines || comments) && ip->fname != 0)
+ argptr->newlines = ip->lineno - lineno0;
+ if ((argptr->newlines || comments) && ip->fname != 0)
argptr->raw_length
= final_start +
discard_comments (argptr->raw + final_start,
argptr->raw_length - final_start,
- newlines);
+ argptr->newlines);
argptr->raw[argptr->raw_length] = 0;
if (argptr->raw_length > bufsize + extra)
abort ();
SKIP_ALL_WHITE_SPACE (buf);
else
#endif
- if (c == '\"' || c == '\\') /* escape these chars */
+ if (c == '\"' || c == '\\' || c == '\n') /* escape these chars */
totlen++;
- else if (!isprint (c))
- totlen += 3;
}
- argptr->stringified_length = totlen;
+ argptr->stringified_length_bound = totlen;
}
return result;
}
\f
/* Scan text from START (inclusive) up to LIMIT (exclusive),
+ taken from the expansion of MACRO,
counting parens in *DEPTHPTR,
and return if reach LIMIT
or before a `)' that would make *DEPTHPTR negative
Set *COMMENTS to 1 if a comment is seen. */
static U_CHAR *
-macarg1 (start, limit, depthptr, newlines, comments, rest_args)
+macarg1 (start, limit, macro, depthptr, newlines, comments, rest_args)
U_CHAR *start;
register U_CHAR *limit;
+ struct hashnode *macro;
int *depthptr, *newlines, *comments;
int rest_args;
{
break;
case '\\':
/* Traditionally, backslash makes following char not special. */
- if (bp + 1 < limit && traditional)
- {
- bp++;
- /* But count source lines anyway. */
- if (*bp == '\n')
- ++*newlines;
- }
+ if (traditional && bp + 1 < limit && bp[1] != '\n')
+ bp++;
break;
case '\n':
++*newlines;
break;
case '/':
- if (bp[1] == '\\' && bp[2] == '\n')
+ if (macro)
+ break;
+ if (bp[1] == '\\')
newline_fix (bp + 1);
if (bp[1] == '*') {
*comments = 1;
else if (*bp == '*') {
if (bp[-1] == '/' && warn_comments)
warning ("`/*' within comment");
- if (bp[1] == '\\' && bp[2] == '\n')
+ if (bp[1] == '\\')
newline_fix (bp + 1);
if (bp[1] == '/') {
bp++;
break;
}
}
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (bp, limit - bp);
+ if (length > 1)
+ bp += (length - 1);
+#endif
+ }
}
} else if (bp[1] == '/' && cplusplus_comments) {
*comments = 1;
for (bp += 2; bp < limit; bp++) {
if (*bp == '\n') {
++*newlines;
- if (bp[-1] != '\\')
- break;
- if (warn_comments)
- warning ("multiline `//' comment");
+ break;
}
+ if (*bp == '\\' && bp + 1 < limit && bp[1] == '\n')
+ {
+ ++*newlines;
+ if (warn_comments)
+ warning ("multiline `//' comment");
+ ++bp;
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (bp, limit - bp);
+ if (length > 1)
+ bp += (length - 1);
+#endif
+ }
}
}
break;
case '\"':
{
int quotec;
- for (quotec = *bp++; bp + 1 < limit && *bp != quotec; bp++) {
+ for (quotec = *bp++; bp < limit && *bp != quotec; bp++) {
if (*bp == '\\') {
bp++;
if (*bp == '\n')
++*newlines;
while (*bp == '\\' && bp[1] == '\n') {
bp += 2;
+ ++*newlines;
}
} else if (*bp == '\n') {
+ if (warn_white_space && is_hor_space[bp[-1]] && ! macro)
+ warning ("white space at end of line in string");
++*newlines;
if (quotec == '\'')
break;
}
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ length = local_mblen (bp, limit - bp);
+ if (length > 1)
+ bp += (length - 1);
+#endif
+ }
}
}
break;
break;
case '/':
- if (*ibp == '\\' && ibp[1] == '\n')
+ if (*ibp == '\\')
newline_fix (ibp);
/* Delete any comment. */
if (cplusplus_comments && ibp[0] == '/') {
/* Comments are equivalent to spaces. */
obp[-1] = ' ';
ibp++;
- while (ibp < limit && (*ibp != '\n' || ibp[-1] == '\\'))
- ibp++;
+ while (ibp < limit)
+ {
+ if (*ibp == '\n')
+ break;
+ if (*ibp == '\\' && ibp + 1 < limit && ibp[1] == '\n')
+ ibp++;
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length = local_mblen (ibp, limit - ibp);
+ if (length > 1)
+ ibp += (length - 1);
+#endif
+ }
+ ibp++;
+ }
break;
}
if (ibp[0] != '*' || ibp + 1 >= limit)
obp--;
else
obp[-1] = ' ';
- ibp++;
- while (ibp + 1 < limit) {
- if (ibp[0] == '*'
- && ibp[1] == '\\' && ibp[2] == '\n')
- newline_fix (ibp + 1);
- if (ibp[0] == '*' && ibp[1] == '/')
- break;
- ibp++;
+ while (++ibp < limit) {
+ if (ibp[0] == '*') {
+ if (ibp[1] == '\\')
+ newline_fix (ibp + 1);
+ if (ibp[1] == '/') {
+ ibp += 2;
+ break;
+ }
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length = local_mblen (ibp, limit - ibp);
+ if (length > 1)
+ ibp += (length - 1);
+#endif
+ }
}
- ibp += 2;
break;
case '\'':
*obp++ = c = *ibp++;
if (c == quotec)
break;
- if (c == '\n' && quotec == '\'')
- break;
- if (c == '\\' && ibp < limit) {
- while (*ibp == '\\' && ibp[1] == '\n')
- ibp += 2;
- *obp++ = *ibp++;
+ if (c == '\n')
+ {
+ if (quotec == '\'')
+ break;
+ }
+ else if (c == '\\') {
+ if (ibp < limit && *ibp == '\n') {
+ ibp++;
+ obp--;
+ } else {
+ while (*ibp == '\\' && ibp[1] == '\n')
+ ibp += 2;
+ if (ibp < limit)
+ *obp++ = *ibp++;
+ }
}
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ ibp--;
+ length = local_mblen (ibp, limit - ibp);
+ if (length > 1)
+ {
+ obp--;
+ bcopy (ibp, obp, length);
+ ibp += length;
+ obp += length;
+ }
+ else
+ ibp++;
+#endif
+ }
}
}
break;
return obp - start;
}
\f
-/* Turn newlines to spaces in the string of length LENGTH at START,
- except inside of string constants.
- The string is copied into itself with its beginning staying fixed. */
+/* Turn newlines to spaces in the macro argument ARG.
+ Remove backslash-newline from string constants,
+ and turn other newlines in string constants to backslash-'n'. */
-static int
-change_newlines (start, length)
- U_CHAR *start;
- int length;
+static void
+change_newlines (arg)
+ struct argdata *arg;
{
+ U_CHAR *start = arg->expanded;
+ int length = arg->expand_length;
register U_CHAR *ibp;
register U_CHAR *obp;
register U_CHAR *limit;
*obp++ = c = *ibp++;
if (c == quotec)
break;
- if (c == '\n' && quotec == '\'')
- break;
+ else if (c == '\\' && ibp < limit && *ibp == '\n')
+ *obp++ = *ibp++;
+ else if (c == '\n')
+ {
+ if (quotec == '\'')
+ break;
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ int length;
+ ibp--;
+ length = local_mblen (ibp, limit - ibp);
+ if (length > 1)
+ {
+ obp--;
+ bcopy (ibp, obp, length);
+ ibp += length;
+ obp += length;
+ }
+ else
+ ibp++;
+#endif
+ }
}
}
break;
}
}
- return obp - start;
+ arg->expand_length = obp - arg->expanded;
+
+ if (start != arg->expanded)
+ free (start);
}
\f
-/* my_strerror - return the descriptive text associated with an
- `errno' code. */
+/* notice - output message to stderr */
-char *
-my_strerror (errnum)
- int errnum;
+static void
+notice VPROTO ((const char * msgid, ...))
{
- char *result;
-
-#ifndef VMS
-#ifndef HAVE_STRERROR
- result = (char *) ((errnum < sys_nerr) ? sys_errlist[errnum] : 0);
-#else
- result = strerror (errnum);
-#endif
-#else /* VMS */
- /* VAXCRTL's strerror() takes an optional second argument, which only
- matters when the first argument is EVMSERR. However, it's simplest
- just to pass it unconditionally. `vaxc$errno' is declared in
- <errno.h>, and maintained by the library in parallel with `errno'.
- We assume that caller's `errnum' either matches the last setting of
- `errno' by the library or else does not have the value `EVMSERR'. */
-
- result = strerror (errnum, vaxc$errno);
+#ifndef ANSI_PROTOTYPES
+ const char * msgid;
#endif
+ va_list args;
- if (!result)
- result = "undocumented I/O error";
+ VA_START (args, msgid);
- return result;
+#ifndef ANSI_PROTOTYPES
+ msgid = va_arg (args, const char *);
+#endif
+
+ vnotice (msgid, args);
+ va_end (args);
+}
+
+static void
+vnotice (msgid, args)
+ const char *msgid;
+ va_list args;
+{
+ vfprintf (stderr, _(msgid), args);
}
/* error - print error message and increment count of errors. */
void
-error (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+error VPROTO ((const char * msgid, ...))
{
+#ifndef ANSI_PROTOTYPES
+ const char * msgid;
+#endif
va_list args;
- VA_START (args, msg);
- verror (msg, args);
+ VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ msgid = va_arg (args, const char *);
+#endif
+
+ verror (msgid, args);
va_end (args);
}
-static void
-verror (msg, args)
- char *msg;
+void
+verror (msgid, args)
+ const char *msgid;
va_list args;
{
int i;
break;
}
- if (ip != NULL)
- fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
- vfprintf (stderr, msg, args);
+ if (ip != NULL) {
+ fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+ ip->nominal_fname_len, stderr);
+ fprintf (stderr, ":%d: ", ip->lineno);
+ }
+ vnotice (msgid, args);
fprintf (stderr, "\n");
errors++;
}
error_from_errno (name)
char *name;
{
+ int e = errno;
int i;
FILE_BUF *ip = NULL;
break;
}
- if (ip != NULL)
- fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
+ if (ip != NULL) {
+ fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+ ip->nominal_fname_len, stderr);
+ fprintf (stderr, ":%d: ", ip->lineno);
+ }
- fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
+ fprintf (stderr, "%s: %s\n", name, xstrerror (e));
errors++;
}
/* Print error message but don't count it. */
void
-warning (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+warning VPROTO ((const char * msgid, ...))
{
+#ifndef ANSI_PROTOTYPES
+ const char * msgid;
+#endif
va_list args;
- VA_START (args, msg);
- vwarning (msg, args);
+ VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ msgid = va_arg (args, const char *);
+#endif
+
+ vwarning (msgid, args);
va_end (args);
}
static void
-vwarning (msg, args)
- char *msg;
+vwarning (msgid, args)
+ const char *msgid;
va_list args;
{
int i;
break;
}
- if (ip != NULL)
- fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
- fprintf (stderr, "warning: ");
- vfprintf (stderr, msg, args);
+ if (ip != NULL) {
+ fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+ ip->nominal_fname_len, stderr);
+ fprintf (stderr, ":%d: ", ip->lineno);
+ }
+ notice ("warning: ");
+ vnotice (msgid, args);
fprintf (stderr, "\n");
}
static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-error_with_line (int line, PRINTF_ALIST (msg))
-#else
-error_with_line (line, PRINTF_ALIST (msg))
- int line;
- PRINTF_DCL (msg)
-#endif
+error_with_line VPROTO ((int line, const char * msgid, ...))
{
+#ifndef ANSI_PROTOTYPES
+ int line;
+ const char * msgid;
+#endif
va_list args;
- VA_START (args, msg);
- verror_with_line (line, msg, args);
+ VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ line = va_arg (args, int);
+ msgid = va_arg (args, const char *);
+#endif
+
+ verror_with_line (line, msgid, args);
va_end (args);
}
+
static void
-verror_with_line (line, msg, args)
+verror_with_line (line, msgid, args)
int line;
- char *msg;
+ const char *msgid;
va_list args;
{
int i;
break;
}
- if (ip != NULL)
- fprintf (stderr, "%s:%d: ", ip->nominal_fname, line);
- vfprintf (stderr, msg, args);
+ if (ip != NULL) {
+ fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+ ip->nominal_fname_len, stderr);
+ fprintf (stderr, ":%d: ", line);
+ }
+ vnotice (msgid, args);
fprintf (stderr, "\n");
errors++;
}
static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-warning_with_line (int line, PRINTF_ALIST (msg))
-#else
-warning_with_line (line, PRINTF_ALIST (msg))
- int line;
- PRINTF_DCL (msg)
-#endif
+warning_with_line VPROTO ((int line, const char * msgid, ...))
{
+#ifndef ANSI_PROTOTYPES
+ int line;
+ const char * msgid;
+#endif
va_list args;
- VA_START (args, msg);
- vwarning_with_line (line, msg, args);
+ VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ line = va_arg (args, int);
+ msgid = va_arg (args, const char *);
+#endif
+
+ vwarning_with_line (line, msgid, args);
va_end (args);
}
static void
-vwarning_with_line (line, msg, args)
+vwarning_with_line (line, msgid, args)
int line;
- char *msg;
+ const char *msgid;
va_list args;
{
int i;
break;
}
- if (ip != NULL)
- fprintf (stderr, line ? "%s:%d: " : "%s: ", ip->nominal_fname, line);
- fprintf (stderr, "warning: ");
- vfprintf (stderr, msg, args);
+ if (ip != NULL) {
+ fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+ ip->nominal_fname_len, stderr);
+ fprintf (stderr, line ? ":%d: " : ": ", line);
+ }
+ notice ("warning: ");
+ vnotice (msgid, args);
fprintf (stderr, "\n");
}
/* Print an error message and maybe count it. */
void
-pedwarn (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+pedwarn VPROTO ((const char * msgid, ...))
{
+#ifndef ANSI_PROTOTYPES
+ const char * msgid;
+#endif
va_list args;
- VA_START (args, msg);
+ VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ msgid = va_arg (args, const char *);
+#endif
+
if (pedantic_errors)
- verror (msg, args);
+ verror (msgid, args);
else
- vwarning (msg, args);
+ vwarning (msgid, args);
va_end (args);
}
void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-pedwarn_with_line (int line, PRINTF_ALIST (msg))
-#else
-pedwarn_with_line (line, PRINTF_ALIST (msg))
- int line;
- PRINTF_DCL (msg)
-#endif
+pedwarn_with_line VPROTO ((int line, const char * msgid, ...))
{
+#ifndef ANSI_PROTOTYPES
+ int line;
+ const char * msgid;
+#endif
va_list args;
- VA_START (args, msg);
+ VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ line = va_arg (args, int);
+ msgid = va_arg (args, const char *);
+#endif
+
if (pedantic_errors)
- verror_with_line (line, msg, args);
+ verror_with_line (line, msgid, args);
else
- vwarning_with_line (line, msg, args);
+ vwarning_with_line (line, msgid, args);
va_end (args);
}
giving specified file name and line number, not current. */
static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-pedwarn_with_file_and_line (char *file, int line, PRINTF_ALIST (msg))
-#else
-pedwarn_with_file_and_line (file, line, PRINTF_ALIST (msg))
- char *file;
- int line;
- PRINTF_DCL (msg)
-#endif
+pedwarn_with_file_and_line VPROTO ((const char *file, size_t file_len, int line,
+ const char * msgid, ...))
{
+#ifndef ANSI_PROTOTYPES
+ const char *file;
+ size_t file_len;
+ int line;
+ const char * msgid;
+#endif
va_list args;
if (!pedantic_errors && inhibit_warnings)
return;
- if (file != NULL)
- fprintf (stderr, "%s:%d: ", file, line);
+
+ VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ file = va_arg (args, const char *);
+ file_len = va_arg (args, size_t);
+ line = va_arg (args, int);
+ msgid = va_arg (args, const char *);
+#endif
+
+ if (file) {
+ fwrite (file, sizeof file[0], file_len, stderr);
+ fprintf (stderr, ":%d: ", line);
+ }
if (pedantic_errors)
errors++;
if (!pedantic_errors)
- fprintf (stderr, "warning: ");
- VA_START (args, msg);
- vfprintf (stderr, msg, args);
+ notice ("warning: ");
+ vnotice (msgid, args);
va_end (args);
fprintf (stderr, "\n");
}
+
+static void
+pedwarn_strange_white_space (ch)
+ int ch;
+{
+ switch (ch)
+ {
+ case '\f': pedwarn ("formfeed in preprocessing directive"); break;
+ case '\r': pedwarn ("carriage return in preprocessing directive"); break;
+ case '\v': pedwarn ("vertical tab in preprocessing directive"); break;
+ default: abort ();
+ }
+}
\f
/* Print the file names and line numbers of the #include
directives which led to the current file. */
ip = &instack[i];
if (first) {
first = 0;
- fprintf (stderr, "In file included");
+ notice ( "In file included from ");
} else {
- fprintf (stderr, ",\n ");
+ notice (",\n from ");
}
- fprintf (stderr, " from %s:%d", ip->nominal_fname, ip->lineno);
+ fwrite (ip->nominal_fname, sizeof ip->nominal_fname[0],
+ ip->nominal_fname_len, stderr);
+ fprintf (stderr, ":%d", ip->lineno);
}
if (! first)
fprintf (stderr, ":\n");
if (minsize > obuf->length)
obuf->length = minsize;
- if ((p = (U_CHAR *) xrealloc (obuf->buf, obuf->length)) == NULL)
- memory_full ();
+ p = (U_CHAR *) xrealloc (obuf->buf, obuf->length);
obuf->bufp = p + (obuf->bufp - obuf->buf);
obuf->buf = p;
}
/*
- * find the most recent hash node for name name (ending with first
+ * find the most recent hash node for name "name" (ending with first
* non-identifier char) installed by install
*
* If LEN is >= 0, it is the length of the name.
* refer to them.
*/
for (i = 'a'; i <= 'z'; i++) {
- is_idchar[i - 'a' + 'A'] = 1;
+ is_idchar[TOUPPER(i)] = 1;
is_idchar[i] = 1;
- is_idstart[i - 'a' + 'A'] = 1;
+ is_idstart[TOUPPER(i)] = 1;
is_idstart[i] = 1;
}
for (i = '0'; i <= '9'; i++)
is_space['\f'] = 1;
is_space['\n'] = 1;
is_space['\r'] = 1;
-
- char_name['\v'] = "vertical tab";
- char_name['\f'] = "formfeed";
- char_name['\r'] = "carriage return";
}
/* Initialize the built-in macros. */
install ((U_CHAR *) "__STDC__", -1, T_CONST, "1", -1);
install ((U_CHAR *) "__STDC_VERSION__", -1, T_CONST, "199409L", -1);
}
- if (objc)
- install ((U_CHAR *) "__OBJC__", -1, T_CONST, "1", -1);
/* This is supplied using a -D by the compiler driver
so that it is present only when truly compiling with GNU C. */
/* install ((U_CHAR *) "__GNUC__", -1, T_CONST, "2", -1); */
*/
static void
-make_definition (str, op)
+make_definition (str)
char *str;
- FILE_BUF *op;
{
FILE_BUF *ip;
struct directive *kt;
NULL_PTR, NULL_PTR, &unterminated);
if (unterminated)
return;
- while (p != p1)
+ while (p != p1) {
if (*p == '\\' && p[1] == '\n')
p += 2;
+ else if (*p == '\n')
+ {
+ *q++ = '\\';
+ *q++ = 'n';
+ p++;
+ }
else
*q++ = *p++;
+ }
} else if (*p == '\\' && p[1] == '\n')
p += 2;
/* Change newline chars into newline-markers. */
ip = &instack[++indepth];
ip->nominal_fname = ip->fname = "*Initialization*";
+ ip->nominal_fname_len = strlen (ip->nominal_fname);
ip->buf = ip->bufp = buf;
ip->length = strlen ((char *) buf);
ip = &instack[++indepth];
ip->nominal_fname = ip->fname = "*undef*";
+ ip->nominal_fname_len = strlen (ip->nominal_fname);
ip->buf = ip->bufp = (U_CHAR *) str;
ip->length = strlen (str);
static void
make_assertion (option, str)
- char *option;
- char *str;
+ const char *option;
+ const char *str;
{
FILE_BUF *ip;
struct directive *kt;
ip = &instack[++indepth];
ip->nominal_fname = ip->fname = "*Initialization*";
+ ip->nominal_fname_len = strlen (ip->nominal_fname);
ip->buf = ip->bufp = buf;
ip->length = strlen ((char *) buf);
--indepth;
}
\f
-#ifndef DIR_SEPARATOR
-#define DIR_SEPARATOR '/'
-#endif
-
/* The previous include prefix, if any, is PREV_FILE_NAME.
Translate any pathnames with COMPONENT.
Allocate a new include prefix whose name is the
static struct file_name_list *
new_include_prefix (prev_file_name, component, prefix, name)
struct file_name_list *prev_file_name;
- char *component;
- char *prefix;
- char *name;
+ const char *component;
+ const char *prefix;
+ const char *name;
{
if (name == 0)
fatal ("Directory name missing after command line option");
if (len == 1 && dir->fname[len - 1] == '.')
len = 0;
else
+#ifdef VMS
+ /* must be '/', hack_vms_include_specification triggers on it. */
+ dir->fname[len++] = '/';
+#else
dir->fname[len++] = DIR_SEPARATOR;
+#endif
dir->fname[len] = 0;
}
static int
quote_string_for_make (dst, src)
char *dst;
- char *src;
+ const char *src;
{
- char *p = src;
+ const char *p = src;
int i = 0;
for (;;)
{
preceded by 2N backslashes represents N backslashes at
the end of a file name; and backslashes in other
contexts should not be doubled. */
- char *q;
+ const char *q;
for (q = p - 1; src < q && q[-1] == '\\'; q--)
{
if (dst)
static void
deps_output (string, spacer)
- char *string;
+ const char *string;
int spacer;
{
int size = quote_string_for_make ((char *) 0, string);
deps_buffer[deps_size] = 0;
}
\f
-static void
-fatal (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+void
+fatal VPROTO ((const char * msgid, ...))
{
+#ifndef ANSI_PROTOTYPES
+ const char * msgid;
+#endif
va_list args;
fprintf (stderr, "%s: ", progname);
- VA_START (args, msg);
- vfprintf (stderr, msg, args);
+ VA_START (args, msgid);
+
+#ifndef ANSI_PROTOTYPES
+ msgid = va_arg (args, const char *);
+#endif
+ vnotice (msgid, args);
va_end (args);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
perror_with_name (name)
char *name;
{
- fprintf (stderr, "%s: ", progname);
- fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
+ fprintf (stderr, "%s: %s: %s\n", progname, name, xstrerror (errno));
errors++;
}
static void
pipe_closed (signo)
/* If this is missing, some compilers complain. */
- int signo;
+ int signo ATTRIBUTE_UNUSED;
{
fatal ("output pipe has been closed");
}
{
fatal ("Memory exhausted.");
}
+\f
+#ifdef VMS
+/* Under VMS we need to fix up the "include" specification filename.
-GENERIC_PTR
-xmalloc (size)
- size_t size;
-{
- register GENERIC_PTR ptr = (GENERIC_PTR) malloc (size);
- if (!ptr)
- memory_full ();
- return ptr;
-}
+ Rules for possible conversions
-static GENERIC_PTR
-xrealloc (old, size)
- GENERIC_PTR old;
- size_t size;
-{
- register GENERIC_PTR ptr = (GENERIC_PTR) realloc (old, size);
- if (!ptr)
- memory_full ();
- return ptr;
-}
+ fullname tried paths
-static GENERIC_PTR
-xcalloc (number, size)
- size_t number, size;
-{
- register size_t total = number * size;
- register GENERIC_PTR ptr = (GENERIC_PTR) malloc (total);
- if (!ptr)
- memory_full ();
- bzero (ptr, total);
- return ptr;
-}
+ name name
+ ./dir/name [.dir]name
+ /dir/name dir:name
+ /name [000000]name, name
+ dir/name dir:[000000]name, dir:name, dir/name
+ dir1/dir2/name dir1:[dir2]name, dir1:[000000.dir2]name
+ path:/name path:[000000]name, path:name
+ path:/dir/name path:[000000.dir]name, path:[dir]name
+ path:dir/name path:[dir]name
+ [path]:[dir]name [path.dir]name
+ path/[dir]name [path.dir]name
-static char *
-savestring (input)
- char *input;
-{
- size_t size = strlen (input);
- char *output = xmalloc (size + 1);
- strcpy (output, input);
- return output;
-}
-\f
-#ifdef VMS
+ The path:/name input is constructed when expanding <> includes.
-/* Under VMS we need to fix up the "include" specification filename so
- that everything following the 1st slash is changed into its correct
- VMS file specification. */
+ return 1 if name was changed, 0 else. */
-static void
-hack_vms_include_specification (fname, vaxc_include)
- char *fname;
+static int
+hack_vms_include_specification (fullname, vaxc_include)
+ char *fullname;
int vaxc_include;
{
- register char *cp, *cp1, *cp2;
- int f, check_filename_before_returning;
+ register char *basename, *unixname, *local_ptr, *first_slash;
+ int f, check_filename_before_returning, must_revert;
char Local[512];
check_filename_before_returning = 0;
+ must_revert = 0;
+ /* See if we can find a 1st slash. If not, there's no path information. */
+ first_slash = index (fullname, '/');
+ if (first_slash == 0)
+ return 0; /* Nothing to do!!! */
- cp = base_name (fname);
+ /* construct device spec if none given. */
+
+ if (index (fullname, ':') == 0)
+ {
+
+ /* If fullname has a slash, take it as device spec. */
+
+ if (first_slash == fullname)
+ {
+ first_slash = index (fullname+1, '/'); /* 2nd slash ? */
+ if (first_slash)
+ *first_slash = ':'; /* make device spec */
+ for (basename = fullname; *basename != 0; basename++)
+ *basename = *(basename+1); /* remove leading slash */
+ }
+ else if ((first_slash[-1] != '.') /* keep ':/', './' */
+ && (first_slash[-1] != ':')
+ && (first_slash[-1] != ']')) /* or a vms path */
+ {
+ *first_slash = ':';
+ }
+ else if ((first_slash[1] == '[') /* skip './' in './[dir' */
+ && (first_slash[-1] == '.'))
+ fullname += 2;
+ }
+
+ /* Get part after first ':' (basename[-1] == ':')
+ or last '/' (basename[-1] == '/'). */
+
+ basename = base_name (fullname);
/*
* Check if we have a vax-c style '#include filename'
* and add the missing .h
*/
- if (vaxc_include && !index (cp,'.'))
- strcat (cp, ".h");
- cp2 = Local; /* initialize */
+ if (vaxc_include && !index (basename,'.'))
+ strcat (basename, ".h");
+
+ local_ptr = Local; /* initialize */
/* We are trying to do a number of things here. First of all, we are
trying to hammer the filenames into a standard format, such that later
If no device is specified, then the first directory name is taken to be
a device name (or a rooted logical). */
- /* See if we found that 1st slash */
- if (cp == 0) return; /* Nothing to do!!! */
- if (*cp != '/') return; /* Nothing to do!!! */
- /* Point to the UNIX filename part (which needs to be fixed!) */
- cp1 = cp+1;
+ /* Point to the UNIX filename part (which needs to be fixed!)
+ but skip vms path information.
+ [basename != fullname since first_slash != 0]. */
+
+ if ((basename[-1] == ':') /* vms path spec. */
+ || (basename[-1] == ']')
+ || (basename[-1] == '>'))
+ unixname = basename;
+ else
+ unixname = fullname;
+
+ if (*unixname == '/')
+ unixname++;
+
/* If the directory spec is not rooted, we can just copy
- the UNIX filename part and we are done */
- if (((cp - fname) > 1) && ((cp[-1] == ']') || (cp[-1] == '>'))) {
- if (cp[-2] != '.') {
- /*
- * The VMS part ends in a `]', and the preceding character is not a `.'.
- * We strip the `]', and then splice the two parts of the name in the
- * usual way. Given the default locations for include files in cccp.c,
- * we will only use this code if the user specifies alternate locations
- * with the /include (-I) switch on the command line. */
- cp -= 1; /* Strip "]" */
- cp1--; /* backspace */
- } else {
- /*
- * The VMS part has a ".]" at the end, and this will not do. Later
- * processing will add a second directory spec, and this would be a syntax
- * error. Thus we strip the ".]", and thus merge the directory specs.
- * We also backspace cp1, so that it points to a '/'. This inhibits the
- * generation of the 000000 root directory spec (which does not belong here
- * in this case).
- */
- cp -= 2; /* Strip ".]" */
- cp1--; }; /* backspace */
- } else {
+ the UNIX filename part and we are done. */
- /* We drop in here if there is no VMS style directory specification yet.
- * If there is no device specification either, we make the first dir a
- * device and try that. If we do not do this, then we will be essentially
- * searching the users default directory (as if they did a #include "asdf.h").
- *
- * Then all we need to do is to push a '[' into the output string. Later
- * processing will fill this in, and close the bracket.
- */
- if (cp[-1] != ':') *cp2++ = ':'; /* dev not in spec. take first dir */
- *cp2++ = '['; /* Open the directory specification */
- }
+ if (((basename - fullname) > 1)
+ && ( (basename[-1] == ']')
+ || (basename[-1] == '>')))
+ {
+ if (basename[-2] != '.')
+ {
+
+ /* The VMS part ends in a `]', and the preceding character is not a `.'.
+ -> PATH]:/name (basename = '/name', unixname = 'name')
+ We strip the `]', and then splice the two parts of the name in the
+ usual way. Given the default locations for include files in cccp.c,
+ we will only use this code if the user specifies alternate locations
+ with the /include (-I) switch on the command line. */
+
+ basename -= 1; /* Strip "]" */
+ unixname--; /* backspace */
+ }
+ else
+ {
+
+ /* The VMS part has a ".]" at the end, and this will not do. Later
+ processing will add a second directory spec, and this would be a syntax
+ error. Thus we strip the ".]", and thus merge the directory specs.
+ We also backspace unixname, so that it points to a '/'. This inhibits the
+ generation of the 000000 root directory spec (which does not belong here
+ in this case). */
+
+ basename -= 2; /* Strip ".]" */
+ unixname--; /* backspace */
+ }
+ }
+
+ else
+
+ {
+
+ /* We drop in here if there is no VMS style directory specification yet.
+ If there is no device specification either, we make the first dir a
+ device and try that. If we do not do this, then we will be essentially
+ searching the users default directory (as if they did a #include "asdf.h").
+
+ Then all we need to do is to push a '[' into the output string. Later
+ processing will fill this in, and close the bracket. */
+
+ if ((unixname != fullname) /* vms path spec found. */
+ && (basename[-1] != ':'))
+ *local_ptr++ = ':'; /* dev not in spec. take first dir */
+
+ *local_ptr++ = '['; /* Open the directory specification */
+ }
+
+ if (unixname == fullname) /* no vms dir spec. */
+ {
+ must_revert = 1;
+ if ((first_slash != 0) /* unix dir spec. */
+ && (*unixname != '/') /* not beginning with '/' */
+ && (*unixname != '.')) /* or './' or '../' */
+ *local_ptr++ = '.'; /* dir is local ! */
+ }
/* at this point we assume that we have the device spec, and (at least
the opening "[" for a directory specification. We may have directories
- specified already */
+ specified already.
- /* If there are no other slashes then the filename will be
+ If there are no other slashes then the filename will be
in the "root" directory. Otherwise, we need to add
directory specifications. */
- if (index (cp1, '/') == 0) {
- /* Just add "000000]" as the directory string */
- strcpy (cp2, "000000]");
- cp2 += strlen (cp2);
- check_filename_before_returning = 1; /* we might need to fool with this later */
- } else {
- /* As long as there are still subdirectories to add, do them. */
- while (index (cp1, '/') != 0) {
- /* If this token is "." we can ignore it */
- if ((cp1[0] == '.') && (cp1[1] == '/')) {
- cp1 += 2;
- continue;
- }
- /* Add a subdirectory spec. Do not duplicate "." */
- if (cp2[-1] != '.' && cp2[-1] != '[' && cp2[-1] != '<')
- *cp2++ = '.';
- /* If this is ".." then the spec becomes "-" */
- if ((cp1[0] == '.') && (cp1[1] == '.') && (cp[2] == '/')) {
- /* Add "-" and skip the ".." */
- *cp2++ = '-';
- cp1 += 3;
- continue;
- }
- /* Copy the subdirectory */
- while (*cp1 != '/') *cp2++= *cp1++;
- cp1++; /* Skip the "/" */
+
+ if (index (unixname, '/') == 0)
+ {
+ /* if no directories specified yet and none are following. */
+ if (local_ptr[-1] == '[')
+ {
+ /* Just add "000000]" as the directory string */
+ strcpy (local_ptr, "000000]");
+ local_ptr += strlen (local_ptr);
+ check_filename_before_returning = 1; /* we might need to fool with this later */
+ }
}
- /* Close the directory specification */
- if (cp2[-1] == '.') /* no trailing periods */
- cp2--;
- *cp2++ = ']';
- }
- /* Now add the filename */
- while (*cp1) *cp2++ = *cp1++;
- *cp2 = 0;
+ else
+ {
+
+ /* As long as there are still subdirectories to add, do them. */
+ while (index (unixname, '/') != 0)
+ {
+ /* If this token is "." we can ignore it
+ if it's not at the beginning of a path. */
+ if ((unixname[0] == '.') && (unixname[1] == '/'))
+ {
+ /* remove it at beginning of path. */
+ if ( ((unixname == fullname) /* no device spec */
+ && (fullname+2 != basename)) /* starts with ./ */
+ /* or */
+ || ((basename[-1] == ':') /* device spec */
+ && (unixname-1 == basename))) /* and ./ afterwards */
+ *local_ptr++ = '.'; /* make '[.' start of path. */
+ unixname += 2;
+ continue;
+ }
+
+ /* Add a subdirectory spec. Do not duplicate "." */
+ if ( local_ptr[-1] != '.'
+ && local_ptr[-1] != '['
+ && local_ptr[-1] != '<')
+ *local_ptr++ = '.';
+
+ /* If this is ".." then the spec becomes "-" */
+ if ( (unixname[0] == '.')
+ && (unixname[1] == '.')
+ && (unixname[2] == '/'))
+ {
+ /* Add "-" and skip the ".." */
+ if ((local_ptr[-1] == '.')
+ && (local_ptr[-2] == '['))
+ local_ptr--; /* prevent [.- */
+ *local_ptr++ = '-';
+ unixname += 3;
+ continue;
+ }
+
+ /* Copy the subdirectory */
+ while (*unixname != '/')
+ *local_ptr++= *unixname++;
+
+ unixname++; /* Skip the "/" */
+ }
+
+ /* Close the directory specification */
+ if (local_ptr[-1] == '.') /* no trailing periods */
+ local_ptr--;
+
+ if (local_ptr[-1] == '[') /* no dir needed */
+ local_ptr--;
+ else
+ *local_ptr++ = ']';
+ }
+
+ /* Now add the filename. */
+
+ while (*unixname)
+ *local_ptr++ = *unixname++;
+ *local_ptr = 0;
+
/* Now append it to the original VMS spec. */
- strcpy (cp, Local);
+
+ strcpy ((must_revert==1)?fullname:basename, Local);
/* If we put a [000000] in the filename, try to open it first. If this fails,
remove the [000000], and return that name. This provides flexibility
to the user in that they can use both rooted and non-rooted logical names
to point to the location of the file. */
- if (check_filename_before_returning) {
- f = open (fname, O_RDONLY, 0666);
- if (f >= 0) {
- /* The file name is OK as it is, so return it as is. */
- close (f);
- return;
+ if (check_filename_before_returning)
+ {
+ f = open (fullname, O_RDONLY, 0666);
+ if (f >= 0)
+ {
+ /* The file name is OK as it is, so return it as is. */
+ close (f);
+ return 1;
+ }
+
+ /* The filename did not work. Try to remove the [000000] from the name,
+ and return it. */
+
+ basename = index (fullname, '[');
+ local_ptr = index (fullname, ']') + 1;
+ strcpy (basename, local_ptr); /* this gets rid of it */
+
}
- /* The filename did not work. Try to remove the [000000] from the name,
- and return it. */
- cp = index (fname, '[');
- cp2 = index (fname, ']') + 1;
- strcpy (cp, cp2); /* this gets rid of it */
- }
- return;
+
+ return 1;
}
#endif /* VMS */
\f
return result;
}
+
+static size_t
+VMS_fwrite (ptr, size, nitems, stream)
+ void const *ptr;
+ size_t size;
+ size_t nitems;
+ FILE *stream;
+{
+ /* VMS fwrite has undesirable results
+ if STREAM happens to be a record oriented file.
+ Work around this problem by writing each character individually. */
+ char const *p = ptr;
+ size_t bytes = size * nitems;
+ char *lim = p + bytes;
+
+ while (p < lim)
+ if (putc (*p++, stream) == EOF)
+ return 0;
+
+ return bytes;
+}
#endif /* VMS */