diff options
Diffstat (limited to 'ACE/TAO/TAO_IDL/contrib/mcpp/system.cpp')
-rw-r--r-- | ACE/TAO/TAO_IDL/contrib/mcpp/system.cpp | 4930 |
1 files changed, 4930 insertions, 0 deletions
diff --git a/ACE/TAO/TAO_IDL/contrib/mcpp/system.cpp b/ACE/TAO/TAO_IDL/contrib/mcpp/system.cpp new file mode 100644 index 00000000000..ff8ef927b17 --- /dev/null +++ b/ACE/TAO/TAO_IDL/contrib/mcpp/system.cpp @@ -0,0 +1,4930 @@ +/*- $Id$ + * Copyright (c) 1998, 2002-2008 Kiyoshi Matsui <kmatsui@t3.rim.or.jp> + * All rights reserved. + * + * Some parts of this code are derived from the public domain software + * DECUS cpp (1984,1985) written by Martin Minow. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * S Y S T E M . C + * S y s t e m D e p e n d e n t R o u t i n e s + * + * Routines dependent on O.S., compiler or compiler-driver. + * To port MCPP for the systems not yet ported, you must + * 1. specify the constants in "configed.H" or "noconfig.H", + * 2. append the system-dependent routines in this file. + */ +#if PREPROCESSED +#include "mcpp.H" +#else +#include "system.H" +#include "internal.H" +#endif + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_stat.h" + +#if HOST_SYS_FAMILY == SYS_UNIX +#include "ace/OS_NS_unistd.h" /* For getcwd(), readlink() */ +#elif HOST_COMPILER == MSC || HOST_COMPILER == LCC +#include "direct.h" +#define getcwd( buf, size) _getcwd( buf, size) +#elif HOST_COMPILER == BORLANDC +#include "dir.h" +#endif + +#include "sys/types.h" +#include "sys/stat.h" /* For stat() */ +#if ! defined( S_ISREG) +#define S_ISREG( mode) (mode & S_IFREG) +#define S_ISDIR( mode) (mode & S_IFDIR) +#endif +#if HOST_COMPILER == MSC +#define S_IFREG _S_IFREG +#define S_IFDIR _S_IFDIR +#define stat( path, stbuf) _stat( path, stbuf) +#endif + +/* Function to compare path-list */ +#if FNAME_FOLD +#if HOST_COMPILER == GNUC /* CYGWIN, MINGW, MAC */ +#include <ace/OS_NS_strings.h> /* POSIX 1, 2001 */ +#define str_case_eq( str1, str2) (ACE_OS::strcasecmp( str1, str2) == 0) +#else /* MSC, BORLANDC, LCC */ +#if HOST_COMPILER == MSC +#define stricmp( str1, str2) _stricmp( str1, str2) +#endif +#define str_case_eq( str1, str2) (ACE_OS::stricmp( str1, str2) == 0) +#endif +#else /* ! FNAME_FOLD */ +#define str_case_eq( str1, str2) (ACE_OS::strcmp( str1, str2) == 0) +#endif + +/* + * PATH_DELIM is defined for the O.S. which has single byte path-delimiter. + * Note: '\\' or any other character identical to second byte of MBCHAR should + * not be used for PATH_DELIM for convenience of path-list parsing. + */ +#if SYS_FAMILY == SYS_UNIX || SYS_FAMILY == SYS_WIN || SYSTEM == SYS_UNKNOWN +#define PATH_DELIM '/' +#define SPECIAL_PATH_DELIM FALSE +#else /* Any other path-delimiter, define PATH_DELIM by yourself */ +#define SPECIAL_PATH_DELIM TRUE /* Any path-delimiter other than '/' */ +#endif + +/* + * OBJEXT is the suffix to denote "object" file. + */ +#ifndef OBJEXT +#if SYS_FAMILY == SYS_UNIX || HOST_COMPILER == GNUC +#define OBJEXT "o" +#elif SYS_FAMILY == SYS_WIN +#define OBJEXT "obj" +#elif 1 +/* Add here appropriate definitions for other systems. */ +#endif +#endif + +static void version( void); +/* Print version message */ +static void usage( int opt); +/* Putout usage of MCPP */ +static void set_opt_list( char * optlist); +/* Set list of legal option chars */ +static int parse_warn_level( const char * mcpp_optarg, int opt); +/* Parse warning level option */ +static void def_a_macro( int opt, char * def); +/* Do a -D option */ +static void chk_opts( int sflag, int trad); +/* Check consistency of options */ +#if COMPILER != GNUC +static void init_cpu_macro( int gval, int sse); +/* Predefine CPU-dependent macros */ +#endif +static void init_predefines( void); +/* Set and unset predefined macros */ +static void init_std_defines( void); +/* Predefine Standard macros */ +static void set_limit( void); +/* Set minimum translation limits */ +static void set_pragma_op( void); +/* Set the _Pragma() operator */ +static void put_info( FILEINFO * sharp_file); +/* Print compiler-specific-inf */ +static char * set_files( int argc, char ** argv, const char ** in_pp + , const char ** out_pp); +/* Set input, output, diagnostic */ +static void set_sys_dirs( int set_cplus_dir); +/* Set system-specific include dirs */ +static void set_env_dirs( void); +/* Set user-defined include dirs */ +static void parse_env( const char * env); +/* Parse environment variables */ +static void set_a_dir( const char * dirname); +/* Append an include directory */ +static char * norm_dir( const char * dirname, int framework); +/* Normalize include directory path */ +static char * norm_path( const char * dir, const char * fname, int inf + , int hmap); /* Normalize pathname to compare */ +#if SYS_FAMILY == SYS_UNIX +static void deref_syml( char * slbuf1, char * slbuf2, char * chk_start); +/* Dereference symbolic linked directory and file */ +#endif +#if COMPILER == GNUC +static void init_gcc_macro( void); +/* Predefine GCC-specific macros */ +static void chk_env( void); +/* Check the environment variables */ +#elif COMPILER == MSC +static void init_msc_macro( void); +/* Predefine Visual C-specific macros */ +#endif +static void def_macros( void); +/* Define macros specified by -D */ +static void undef_macros( void); +/* Undefine macros specified by -U */ +static char * md_init( const char * filename, char * output); +/* Initialize makefile dependency */ +static char * md_quote( char * output); +/* 'Quote' special characters */ +static int open_include( char * filename, int searchlocal, int next); +/* Open the file to include */ +static int has_directory( const char * source, char * directory); +/* Get directory part of fname */ +static int is_full_path( const char * path); +/* The path is absolute path list ? */ +static int search_dir( char * filename, int searchlocal, int next); +/* Search the include directories */ +static int open_file( const char ** dirp, const char * src_dir + , const char * filename, int local, int include_opt, int sys_frame); +/* Open a source file */ +static const char * set_fname( const char * filename); +/* Remember the source filename */ +#if SYSTEM == SYS_MAC +#if COMPILER == GNUC +static char * search_header_map( const char * hmap_file + , const char * filename, char * pathlist); +/* Search header map file for a header */ +static unsigned hmap_hash( const char * fname); +/* Get hash value for the fname */ +#endif +static void init_framework( void); +/* Initialize framework[] */ +static int search_framework( char * filename); +/* Search "Framework" directories */ +static int search_subdir( char * fullname, char * cp, char * frame + , char * fname, int sys_frame); +/* Search "Headers" and other dirs */ +#endif /* SYSTEM == SYS_MAC */ +#if 0 /* This function is only for debugging use */ +static int chk_dirp( const char ** dirp); +/* Check validity of dirp arg for open_file() */ +#endif +static void cur_file( FILEINFO * file, FILEINFO * sharp_file, int marker); +/* Output current source file name */ +#if SYS_FAMILY == SYS_WIN +static char * bsl2sl( char * filename); +/* Convert \ to / in path-list */ +#endif +static int is_junk( void); +/* The directive has trailing junk? */ +static void do_once( const char * fullname); +/* Process #pragma once */ +static int included( const char * fullname); +/* The file has been once included? */ +static void push_or_pop( int direction); +/* Push or pop a macro definition */ +static int do_prestd_directive( void); +/* Process pre-Standard directives */ +static void do_preprocessed( void); +/* Process preprocessed file */ +static int do_debug( int set); +/* #pragma MCPP debug, #debug */ +static void dump_path( void); +/* Print include search path */ +static void do_asm( int asm_start); +/* Process #asm, #endasm */ +static int mcpp_getopt( int argc, char * const * argv, const char * opts); +/* getopt() to prevent linking of glibc getopt */ + +/* for mcpp_getopt() */ +static int mcpp_optind = 1; +static int mcpp_opterr = 1; +static int mcpp_optopt; +static char * mcpp_optarg; + +static int mb_changed = FALSE; /* Flag of -e option */ +static char cur_work_dir[ PATHMAX + 1]; /* Current working directory*/ + +/* + * incdir[] stores the -I directories (and the system-specific #include <...> + * directories). This is set by set_a_dir(). A trailing PATH_DELIM is + * appended if absent. + */ +static const char ** incdir; /* Include directories */ +static const char ** incend; /* -> active end of incdir */ +static int max_inc; /* Number of incdir[] */ + +typedef struct inc_list { /* List of directories or files */ + char * name; /* Filename or directory-name */ + size_t len; /* Length of 'name' */ +} INC_LIST; + +/* + * fnamelist[] stores the souce file names opened by #include directive for + * debugging information. + */ +static INC_LIST * fnamelist; /* Source file names */ +static INC_LIST * fname_end; /* -> active end of fnamelist */ +static int max_fnamelist; /* Number of fnamelist[] */ + +/* once_list[] stores the #pragma once file names. */ +static INC_LIST * once_list; /* Once opened file */ +static INC_LIST * once_end; /* -> active end of once_list */ +static int max_once; /* Number of once_list[] */ + +#define INIT_NUM_INCLUDE 32 /* Initial number of incdir[] */ +#define INIT_NUM_FNAMELIST 256 /* Initial number of fnamelist[] */ +#define INIT_NUM_ONCE 64 /* Initial number of once_list[] */ + +/* + * 'search_rule' holds searching rule of #include "header.h" to search first + * before searching user specified or system-specific include directories. + * 'search_rule' is initialized to SEARCH_INIT. It can be changed by -I1, -I2 + * or -I3 option. -I1 specifies CURRENT, -I2 SOURCE and -I3 both. + */ + +static int search_rule = SEARCH_INIT; /* Rule to search include file */ + +static int nflag = FALSE; /* Flag of -N (-undef) option */ +static long std_val = -1L; /* Value of __STDC_VERSION__ or __cplusplus */ + +#define MAX_DEF 256 +#define MAX_UNDEF (MAX_DEF/4) +static char * def_list[ MAX_DEF]; /* Macros to be defined */ +static const char * undef_list[ MAX_UNDEF]; /* Macros to be undefined */ +static size_t def_cnt(0); /* Count of def_list */ +static size_t undef_cnt (0); /* Count of undef_list */ + +/* Values of mkdep. */ +#define MD_MKDEP 1 /* Output source file dependency line */ +#define MD_SYSHEADER 2 /* Print also system-header names */ +#define MD_FILE 4 /* Output to the file named *.d */ +#define MD_PHONY 8 /* Print also phony targets for each header */ +#define MD_QUOTE 16 /* 'Quote' $ and space in target name */ + +static FILE * mkdep_fp; /* For -Mx option */ +static char * mkdep_target; +/* For -MT TARGET option and for GCC's queer environment variables. */ +static char * mkdep_mf; /* Argument of -MF option */ +static char * mkdep_md; /* Argument of -MD option */ +static char * mkdep_mq; /* Argument of -MQ option */ +static char * mkdep_mt; /* Argument of -MT option */ + +/* sharp_filename is filename for #line line, used only in cur_file() */ +static char * sharp_filename = NULL; +static char * argv0; /* argv[ 0] for usage() and version() */ +static int ansi; /* __STRICT_ANSI__ flag for GNUC */ +static int compat_mode; +/* "Compatible" mode of recursive macro expansion */ +#define MAX_ARCH_LEN 16 +static char arch[ MAX_ARCH_LEN]; /* -arch or -m64, -m32 options */ + +#if COMPILER == GNUC +#define N_QUOTE_DIR 8 +/* quote_dir[]: Include directories for "header" specified by -iquote */ +/* quote_dir_end: Active end of quote_dir */ +static const char * quote_dir[ N_QUOTE_DIR]; +static const char ** quote_dir_end = quote_dir; +/* sys_dirp indicates the first directory to search for system headers. */ +static const char ** sys_dirp = NULL; /* System header directory */ +static const char * sysroot = NULL; /* Logical root directory of header */ +static int i_split = FALSE; /* For -I- option */ +static int gcc_work_dir = FALSE; /* For -fworking-directory */ +static int gcc_maj_ver; /* __GNUC__ */ +static int gcc_min_ver; /* __GNUC_MINOR__ */ +static int dDflag = FALSE; /* Flag of -dD option */ +static int dMflag = FALSE; /* Flag of -dM option */ +#endif + +#if COMPILER == GNUC || COMPILER == MSC +/* + * preinclude points to the file specified by -include (-Fl for MSC) option, + * which is included prior to the main input file. + */ +#define NPREINCLUDE 8 +static char * preinclude[ NPREINCLUDE]; /* File to pre-include */ +static char ** preinc_end = preinclude; /* -> active end of preinclude */ +#endif + +#if COMPILER == MSC +static int wchar_t_modified = FALSE; /* -Zc:wchar_t flag */ +#endif + +#if COMPILER == LCC +static const char * optim_name = "__LCCOPTIMLEVEL"; +#endif + +#if SYSTEM == SYS_CYGWIN +static int no_cygwin = FALSE; /* -mno-cygwin */ + +#elif SYSTEM == SYS_MAC +#define MAX_FRAMEWORK 8 +static char * framework[ MAX_FRAMEWORK]; /* Framework directories*/ +static int num_framework; /* Current number of framework[] */ +static int sys_framework; /* System framework dir */ +static const char ** to_search_framework; +/* Search framework[] next to the directory */ +static int in_import; /* #import rather than #include */ +#endif + +#define NO_DIR FALSE +#if NO_DIR +/* Unofficial feature to strip directory part of include file */ +static int no_dir; +#endif + +#ifdef MCPP_LIB +void init_system( void) +/* Initialize static variables */ +{ + if (sharp_filename) + ACE_OS::free( sharp_filename); + sharp_filename = 0; + incend = incdir = 0; + fnamelist = once_list = 0; + search_rule = SEARCH_INIT; + mb_changed = nflag = ansi = compat_mode = FALSE; + mkdep_fp = 0; + mkdep_target = mkdep_mf = mkdep_md = mkdep_mq = mkdep_mt = 0; + std_val = -1L; + def_cnt = undef_cnt = 0; + mcpp_optind = mcpp_opterr = 1; +#if COMPILER == GNUC + sys_dirp = 0; + sysroot = 0; + gcc_work_dir = i_split = FALSE; + quote_dir_end = quote_dir; + dDflag = dMflag = FALSE; +#endif +#if COMPILER == MSC + wchar_t_modified = FALSE; +#endif +#if COMPILER == GNUC || COMPILER == MSC + preinc_end = preinclude; +#endif +#if SYSTEM == SYS_CYGWIN + no_cygwin = FALSE; +#elif SYSTEM == SYS_MAC + num_framework = sys_framework = 0; + to_search_framework = 0; +#endif +#if NO_DIR + no_dir = FALSE; +#endif +} + +#endif + +#define OPTLISTLEN 80 + +void do_options( + int argc, + char ** argv, + const char ** in_pp, /* Input file name */ + const char ** out_pp /* Output file name */ + ) +/* + * Process command line arguments, called only at MCPP startup. + */ +{ + char optlist[ OPTLISTLEN]; /* List of option letter*/ + const char * warning = "warning: -%c%s option is ignored\n"; + int opt; + int unset_sys_dirs; + /* Unset system-specific and site-specific include directories ? */ + int set_cplus_dir; /* Set C++ include directory ? (for GCC)*/ + int show_path; /* Show include directory list */ + //DEFBUF * /*defp*/; + VAL_SIGN * valp; + int sflag; /* -S option or similar */ + int trad; /* -traditional */ + int old_mode; /* backup of 'mcpp_mode'*/ + int gval, sse; + char * cp; + int i; +#if COMPILER == GNUC +#define NSYSDIR 8 + /* System include directory specified by -isystem */ + char * sysdir[ NSYSDIR] = { 0, }; + char ** sysdir_end = sysdir; + int integrated_cpp; /* Flag of cc1 which integrates cpp in it */ +#elif COMPILER == LCC + const char * debug_name = "__LCCDEBUGLEVEL"; +#endif + + argv0 = argv[ 0]; + nflag = unset_sys_dirs = show_path = sflag = trad = FALSE; + arch[ 0] = 0; + gval = sse = 0; + set_cplus_dir = TRUE; + + /* Get current directory for -I option and #pragma once */ + ACE_OS::getcwd( cur_work_dir, PATHMAX); +#if SYS_FAMILY == SYS_WIN + bsl2sl( cur_work_dir); +#endif + ACE_OS::sprintf( cur_work_dir + ACE_OS::strlen( cur_work_dir), "%c%c", PATH_DELIM, EOS); + /* Append trailing path-delimiter */ + +#if COMPILER == GNUC + defp = look_id( "__GNUC__"); /* Already defined by init_defines() */ + gcc_maj_ver = atoi( defp->repl); + defp = look_id( "__GNUC_MINOR__"); + gcc_min_ver = atoi( defp->repl); + integrated_cpp = ((gcc_maj_ver == 3 && gcc_min_ver >= 3) + || gcc_maj_ver == 4); +#endif +#if COMPILER == GNUC || COMPILER == MSC + option_flags.dollar_in_name = TRUE; + /* GCC and Visual C allows '$' in name by default */ +#endif + + set_opt_list( optlist); + + opt_search: ; + while (mcpp_optind < argc + && (opt = mcpp_getopt( argc, argv, optlist)) != EOF) { + + switch (opt) { /* Command line option character */ + +#if COMPILER == GNUC + case '$': /* Forbid '$' in identifier */ + option_flags.dollar_in_name = FALSE; + break; +#endif + + case '+': +#if COMPILER == GNUC + plus: +#endif + if (cplus_val || sflag) { + mcpp_fputs( "warning: -+ option is ignored\n", ERR); + break; + } + cplus_val = CPLUS; + break; +#if COMPILER == GNUC + case '-': + if (memcmp( mcpp_optarg, "sysroot", 7) == 0) { + if (mcpp_optarg[ 7] == '=') /* --sysroot=DIR */ + sysroot = mcpp_optarg + 8; + else if (mcpp_optarg[ 7] == EOS) /* --sysroot DIR */ + sysroot = argv[ mcpp_optind++]; + else + usage( opt); + break; + } else { + usage( opt); + } +#endif + case '2': /* Reverse digraphs recognition */ + option_flags.dig = ! option_flags.dig; + break; + case '3': /* Reverse trigraph recogniion */ + option_flags.trig = ! option_flags.trig; + break; + + case '@': /* Special preprocessing mode */ + old_mode = mcpp_mode; + if (str_eq( mcpp_optarg, "post") + || str_eq( mcpp_optarg, "poststd")) + mcpp_mode = POST_STD; /* 'post-Standard' mode */ + else if (str_eq( mcpp_optarg, "old") + || str_eq( mcpp_optarg, "oldprep")) + mcpp_mode = OLD_PREP; /* 'old-Preprocessor' mode */ + else if (str_eq( mcpp_optarg, "kr")) + mcpp_mode = KR; /* 'K&R 1st' mode */ + else if (str_eq( mcpp_optarg, "std")) + mcpp_mode = STD; /* 'Standard' mode (default)*/ + else if (str_eq( mcpp_optarg, "compat")) { + compat_mode = TRUE; /* 'compatible' mode */ + mcpp_mode = STD; + } + else + usage( opt); + standard = (mcpp_mode == STD || mcpp_mode == POST_STD); + if (old_mode != STD && old_mode != mcpp_mode) + mcpp_fprintf( ERR, "Mode is redefined to: %s\n", mcpp_optarg); + break; + +#if COMPILER == GNUC + case 'A': /* Ignore -A system(gnu), -A cpu(vax) or so */ + break; + case 'a': + if (str_eq( mcpp_optarg, "nsi")) { /* -ansi */ + look_and_install( "__STRICT_ANSI__", DEF_NOARGS_PREDEF, null + , "1"); + ansi = TRUE; + break; + } else if (memcmp( mcpp_optarg, "uxbase", 6) == 0) { + mcpp_optind++; + break; /* Ignore '-auxbase some' or such nonsence */ +#if SYSTEM == SYS_MAC + } else if (str_eq( mcpp_optarg, "rch")) { /* -arch */ + strcpy( arch, argv[ mcpp_optind++]); + if (str_eq( arch, "ppc") || str_eq( arch, "ppc7400") + || str_eq( arch, "ppc64") + || str_eq( arch, "i386") || str_eq( arch, "i686") + || str_eq( arch, "x86_64") || str_eq( arch, "amd64")) { + if (str_eq( arch, "i686")) + strcpy( arch, "i386"); + else if (str_eq( arch, "amd64")) + strcpy( arch, "x86_64"); + else if (str_eq( arch, "ppc7400")) + strcpy( arch, "ppc"); + break; + } /* Else usage() */ +#endif + } + usage( opt); +#elif COMPILER == MSC + case 'a': + if (memcmp( mcpp_optarg, "rch", 3) == 0) { + if (str_eq( mcpp_optarg + 3, ":SSE") /* -arch:SSE */ + || str_eq( mcpp_optarg + 3, ":sse")) + sse = 1; + else if (str_eq( mcpp_optarg + 3, ":SSE2") /* -arch:SSE2 */ + || str_eq( mcpp_optarg + 3, ":sse2")) + sse = 2; + /* Else ignore */ + } else { + usage( opt); + } + break; + + case 'A': + option_flags.lang_asm = TRUE; /* "assembler" source */ + break; +#else + case 'a': + option_flags.lang_asm = TRUE; /* "assembler" source */ + break; +#endif + +#if ! STD_LINE_PREFIX + case 'b': + std_line_prefix = TRUE; /* Putout line and file infor- */ + break; /* mation in C source style. */ +#endif + + case 'C': /* Keep comments */ + option_flags.c = TRUE; + break; + +#if COMPILER == GNUC + case 'c': + if (! integrated_cpp) + usage( opt); + break; /* Else ignore this option */ + case 'd': + if (str_eq( mcpp_optarg, "M")) { /* -dM */ + dMflag = TRUE; + no_output++; + } else if (str_eq( mcpp_optarg, "D")) { /* -dD */ + dDflag = TRUE; + } else if (str_eq( mcpp_optarg, "igraphs")) { /* -digraphs */ + option_flags.dig = TRUE; + } else if (str_eq( mcpp_optarg, "umpbase")) { /* -dumpbase */ + ; /* Ignore */ + } else { + usage( opt); + } + break; +#endif /* COMPILER == GNUC */ + + case 'D': /* Define symbol */ + if (def_cnt >= MAX_DEF) { + mcpp_fputs( "Too many -D options.\n", ERR); + longjmp( error_exit, -1); + } + def_list[ def_cnt++] = mcpp_optarg; + break; + + case 'e': + /* Change the default MBCHAR encoding */ + if (set_encoding( mcpp_optarg, FALSE, 0) == 0) + usage( opt); + mb_changed = TRUE; + break; + +#if COMPILER == GNUC + case 'E': + if (! integrated_cpp) + usage( opt); + break; /* Ignore this option */ + case 'f': + if (memcmp( mcpp_optarg, "input-charset=", 14) == 0) { + /* Treat -finput-charset= as the same option as -e */ + if (set_encoding( mcpp_optarg + 14, FALSE, 0) == 0) + usage( opt); + mb_changed = TRUE; + } else if (str_eq( mcpp_optarg, "working-directory")) { + gcc_work_dir = TRUE; + } else if (str_eq( mcpp_optarg, "no-working-directory")) { + gcc_work_dir = FALSE; + } else if (str_eq( mcpp_optarg, "stack-protector")) { + look_and_install( "__SSP__", DEF_NOARGS_PREDEF, null, "1"); + } else if (str_eq( mcpp_optarg, "stack-protector-all")) { + look_and_install( "__SSP_ALL__", DEF_NOARGS_PREDEF, null, "2"); + } else if (str_eq( mcpp_optarg, "exceptions")) { + look_and_install( "__EXCEPTIONS", DEF_NOARGS_PREDEF, null + , "1"); + } else if (str_eq( mcpp_optarg, "no-exceptions")) { + undef_list[ undef_cnt++] = "__EXCEPTIONS"; + } else if (str_eq( mcpp_optarg, "PIC") + || str_eq( mcpp_optarg, "pic") + || str_eq( mcpp_optarg, "PIE") + || str_eq( mcpp_optarg, "pie")) { + look_and_install( "__PIC__", DEF_NOARGS_PREDEF, null, "1"); + look_and_install( "__pic__", DEF_NOARGS_PREDEF, null, "1"); + } else if (str_eq( mcpp_optarg, "no-dollars-in-identifiers")) { + option_flags.dollar_in_name = FALSE; + } else if (str_eq( mcpp_optarg, "no-show-column")) { + ; /* Ignore this option */ + } else if (! integrated_cpp) { + usage( opt); + } + break; + + case 'g': + if (!isdigit( *mcpp_optarg) + && str_eq( argv[ mcpp_optind - 2], "-g")) + /* Neither '-g 0' nor '-ggdb' -- No argument */ + mcpp_optind--; + break; /* Ignore the option */ +#elif COMPILER == LCC + case 'g': /* Define __LCCDEBUGLEVEL as <n> */ + if (*(mcpp_optarg + 1) == EOS && isdigit( *mcpp_optarg)) { + defp = look_id( debug_name); + strcpy( defp->repl, mcpp_optarg); + } else { + usage( opt); + } + break; +#elif COMPILER == MSC + case 'G': + if (*(mcpp_optarg + 1) == EOS) { /* -Gx */ + switch (*mcpp_optarg) { + case '3': case '4': case '5': case '6': + gval = *mcpp_optarg; + break; + case 'B': /* -GB */ + gval = '6'; + break; + case 'R': + look_and_install( "_CPPRTTI", DEF_NOARGS_PREDEF, null + , "1"); + break; + case 'X': + look_and_install( "_CPPUNWIND", DEF_NOARGS_PREDEF, null + , "1"); + break; + case 'Z': + look_and_install( "__MSVC_RUNTIME_CHECKS" + , DEF_NOARGS_PREDEF, null, "1"); + break; + default : + mcpp_fprintf( ERR, warning, opt, mcpp_optarg); + } + } else { + usage( opt); + } + break; +#endif + +#if SYSTEM == SYS_MAC + case 'F': + framework[ num_framework++] = mcpp_optarg; + break; +#endif + + case 'h': + if (*(mcpp_optarg + 1) == EOS && isdigit( *mcpp_optarg)) + /* a digit */ + look_and_install( "__STDC_HOSTED__", DEF_NOARGS_PREDEF, null + , mcpp_optarg); + else + usage( opt); + break; + +#if COMPILER == MSC + case 'X': + unset_sys_dirs = TRUE; + break; +#endif + case 'I': /* Include directory */ + if (str_eq( mcpp_optarg, "-")) { /* -I- */ +#if COMPILER == GNUC + sys_dirp = incend; /* Split include directories */ + i_split = TRUE; +#else + unset_sys_dirs = TRUE; + /* Unset pre-specified include directories */ +#endif + } else if (*(mcpp_optarg + 1) == EOS && isdigit( *mcpp_optarg) + && (i = *mcpp_optarg - '0') != 0 + && (i & ~(CURRENT | SOURCE)) == 0) { + search_rule = i; /* -I1, -I2 or -I3 */ + } else { /* Not '-' nor a digit */ + set_a_dir( mcpp_optarg); /* User-defined dir */ + } + break; + +#if COMPILER == MSC + case 'F': + if (str_eq( mcpp_optarg, "l")) { /* -Fl */ + if (preinc_end >= &preinclude[ NPREINCLUDE]) { + mcpp_fputs( "Too many -Fl options.\n", ERR); + longjmp( error_exit, -1); + } + *preinc_end++ = argv[ mcpp_optind++]; + } else { + usage( opt); + } + break; +#endif + +#if COMPILER == GNUC + case 'i': + if (str_eq( mcpp_optarg, "nclude")) { /* -include */ + if (preinc_end >= &preinclude[ NPREINCLUDE]) { + mcpp_fputs( "Too many -include options.\n", ERR); + longjmp( error_exit, -1); + } + *preinc_end++ = argv[ mcpp_optind++]; + } else if (str_eq( mcpp_optarg, "system")) { /* -isystem */ + if (sysdir_end >= &sysdir[ NSYSDIR]) { + mcpp_fputs( "Too many -isystem options.\n", ERR); + longjmp( error_exit, -1); + } + *sysdir_end++ = argv[ mcpp_optind++]; + /* Add the directory before system include directory*/ + } else if (str_eq( mcpp_optarg, "quote")) { /* -iquote */ + if (quote_dir_end >= "e_dir[ N_QUOTE_DIR]) { + mcpp_fputs( "Too many -iquote options.\n", ERR); + longjmp( error_exit, -1); + } + *quote_dir_end++ = argv[ mcpp_optind++]; + /* Add the directory for #include "header" */ + } else if (memcmp( mcpp_optarg, "sysroot", 7) == 0) { + if (mcpp_optarg[ 7] == '=') /* -isysroot=DIR */ + sysroot = mcpp_optarg + 8; + else if (mcpp_optarg[ 7] == EOS) /* -isysroot DIR */ + sysroot = argv[ mcpp_optind++]; + else + usage( opt); + } else if (str_eq( mcpp_optarg, "prefix") /* -iprefix */ + || str_eq( mcpp_optarg, "withprefix") /* -iwithprefix */ + || str_eq( mcpp_optarg, "withprefixbefore") + /* -iwithprefixbefore */ + || str_eq( mcpp_optarg, "dirafter") /* -idirafter */ + || str_eq( mcpp_optarg, "multilib")) { /* -imultilib */ + mcpp_optind++; /* Skip the argument */ + /* Ignore these options */ + } else { + usage( opt); + } + break; +#endif + + case 'j': + option_flags.no_source_line = TRUE; + break; /* Do not output the source line in diagnostics */ + +#if COMPILER == MSC + case 'J': + look_and_install( "_CHAR_UNSIGNED", DEF_NOARGS_PREDEF, null, "1"); + break; +#endif + + case 'K': + mcpp_debug |= MACRO_CALL; + /* + * Putout macro expansion informations embedded in comments. + * Same with '#pragma MCPP debug macro_call'. + */ + /* Enable white spaces preservation, too */ + /* Fall through */ + case 'k': + option_flags.k = TRUE; + /* Keep white spaces of input lines as they are */ + break; + +#if COMPILER == GNUC + case 'l': + if (memcmp( mcpp_optarg, "ang-", 4) != 0) { + usage( opt); + } else if (str_eq( mcpp_optarg + 4, "c")) { /* -lang-c */ + ; /* Ignore this option */ + } else if (str_eq( mcpp_optarg + 4, "c99") /* -lang-c99*/ + || str_eq( mcpp_optarg + 4, "c9x")) { /* -lang-c9x*/ + if (! sflag) { + stdc_val = 1; /* Define __STDC__ to 1 */ + std_val = 199901L; + sflag = TRUE; + } + } else if (str_eq( mcpp_optarg + 4, "c89")) { /* -lang-c89*/ + if (! sflag) { + stdc_val = 1; /* Define __STDC__ to 1 */ + sflag = TRUE; + } + } else if (str_eq( mcpp_optarg + 4, "c++")) { /* -lang-c++*/ + goto plus; + } else if (str_eq( mcpp_optarg + 4, "asm")) { /* -lang-asm*/ + option_flags.lang_asm = TRUE; + } else { + usage( opt); + } + break; +#endif /* COMPILER == GNUC */ + + case 'M': /* Output source file dependency line */ + if (str_eq( mcpp_optarg, "M")) { /* -MM */ + ; + } else if (str_eq( mcpp_optarg, "D")) { /* -MD */ + mkdep |= (MD_SYSHEADER | MD_FILE); + } else if (str_eq( mcpp_optarg, "MD")) { /* -MMD */ + mkdep |= MD_FILE; + } else if (str_eq( mcpp_optarg, "P")) { /* -MP */ + mkdep |= MD_PHONY; + } else if (str_eq( mcpp_optarg, "Q")) { /* -MQ target */ + mkdep |= MD_QUOTE; + mkdep_mq = argv[ mcpp_optind++]; + } else if (str_eq( mcpp_optarg, "T")) { /* -MT target */ + mkdep_mt = argv[ mcpp_optind++]; + } else if (str_eq( mcpp_optarg, "F")) { /* -MF file */ + mkdep_mf = argv[ mcpp_optind++]; + } else if (argv[ mcpp_optind - 1] == mcpp_optarg) { /* -M */ + mkdep |= MD_SYSHEADER; + mcpp_optind--; + } else { + usage( opt); + } + if (str_eq( mcpp_optarg, "D") || str_eq( mcpp_optarg, "MD")) { + cp = argv[ mcpp_optind]; + if (cp && *cp != '-') /* -MD (-MMD) file */ + mkdep_md = argv[ mcpp_optind++]; + } + mkdep |= MD_MKDEP; + break; + +#if SYS_FAMILY == SYS_UNIX + case 'm': + if (str_eq( mcpp_optarg, "64")) { /* -m64 */ + if (str_eq( CPU, "i386")) + ACE_OS::strcpy( arch, "x86_64"); + else if (str_eq( CPU, "ppc")) + ACE_OS::strcpy( arch, "ppc64"); + /* Else ignore */ + break; + } else if (str_eq( mcpp_optarg, "32")) { /* -m32 */ + if (str_eq( CPU, "x86_64")) + ACE_OS::strcpy( arch, "i386"); + else if (str_eq( CPU, "ppc64")) + ACE_OS::strcpy( arch, "ppc"); + /* Else ignore */ + break; + } else if (str_eq( mcpp_optarg, "mmx")) { /* -mmmx */ + look_and_install( "__MMX__", DEF_NOARGS_PREDEF, null, "1"); + break; + } else if (str_eq( mcpp_optarg, "no-mmx")) { /* -mno-mmx */ + undef_list[ undef_cnt++] = "__MMX__"; + break; + } +#endif /* SYS_FAMILY == UNIX */ +#if COMPILER == GNUC +#if SYSTEM == SYS_CYGWIN + if (str_eq( mcpp_optarg, "no-cygwin")) { /* -mno-cygwin */ + no_cygwin = TRUE; + break; + } +#endif + if (! integrated_cpp) + usage( opt); + break; + + case 'u': + if (! str_eq( mcpp_optarg, "ndef")) /* -undef */ + usage( opt); /* Else fall through */ +#endif /* COMPILER == GNUC */ + +#if COMPILER == MSC + case 'u': +#endif + case 'N': + /* No predefines: remove "unix", "__unix__" and friends. */ + nflag = TRUE; + break; + +#if COMPILER == GNUC || NO_DIR + case 'n': +#if NO_DIR + if (str_eq( mcpp_optarg, "odir")) { /* -nodir */ + no_dir = TRUE; + } +#endif +#if COMPILER == GNUC + if (str_eq( mcpp_optarg, "ostdinc")) { /* -nostdinc */ + unset_sys_dirs = TRUE; /* Unset pre-specified directories */ + } else if (str_eq( mcpp_optarg, "ostdinc++")) { /* -nostdinc++ */ + set_cplus_dir = FALSE; /* Unset C++-specific directories */ + } else if (str_eq( mcpp_optarg, "oprecomp")) { /* -noprecomp */ + mcpp_fprintf( ERR, warning, opt, mcpp_optarg); + break; + } +#endif + else { + usage( opt); + } + break; +#endif + +#if COMPILER == GNUC + case 'O': + if (integrated_cpp) { + if (*mcpp_optarg == '-') /* No argument */ + mcpp_optind--; + else if ((isdigit( *mcpp_optarg) && *mcpp_optarg != '0') + || *mcpp_optarg == 's' || *mcpp_optarg == 'z') + /* -O1, -O2 -Os, -Oz */ + look_and_install( "__OPTIMIZE__", DEF_NOARGS_PREDEF, null + , "1"); + else if (! isdigit( *mcpp_optarg)) + usage( opt); + /* Else -O0: ignore */ + } else { + usage( opt); + } + break; /* Else ignore -Ox option */ +#elif COMPILER == LCC + case 'O': /* Define __LCCOPTIMLEVEL as 1 */ + defp = look_id( optim_name); + ACE_OS::strcpy( defp->repl, "1"); + break; +#endif + + case 'o': + *out_pp = mcpp_optarg; /* Output file name */ + break; + + case 'P': /* No #line output */ + option_flags.p = TRUE; + break; + +#if COMPILER == GNUC + case 'p': + if (str_eq( mcpp_optarg, "edantic") /* -pedantic */ + || str_eq( mcpp_optarg, "edantic-errors")) { + /* -pedantic-errors */ + /* This option does not imply -ansi */ + if (warn_level == -1) + warn_level = 0; + warn_level |= (1 | 2 | 4); + if (! sflag && ! cplus_val) { + stdc_val = 1; + sflag = TRUE; + } + } else { + usage( opt); + } + break; + case 'q': + if (str_eq( mcpp_optarg, "uiet")) + /* -quiet: GCC's undocumented, yet frequently specified opt */ + break; /* Ignore the option */ + else + usage( opt); + break; +#endif /* COMPILER == GNUC */ + + case 'Q': + option_flags.q = TRUE; + break; + +#if COMPILER == MSC + case 'R': /* -RTC1, -RTCc, -RTCs, -RTCu, etc. */ + if (memcmp( mcpp_optarg, "TC", 2) == 0 + && *(mcpp_optarg + 2) != EOS) + look_and_install( "__MSVC_RUNTIME_CHECKS", DEF_NOARGS_PREDEF + , null, "1"); + else + usage( opt); + break; +#endif + + case 'S': + if (cplus_val || sflag) { /* C++ or the second time */ + mcpp_fprintf( ERR, warning, opt, mcpp_optarg); + break; + } + i = *mcpp_optarg; + if (! isdigit( i) || *(mcpp_optarg + 1) != EOS) + usage( opt); + stdc_val = i - '0'; + sflag = TRUE; + break; + +#if COMPILER == GNUC + case 'r': + if (str_eq( mcpp_optarg, "emap")) + mcpp_fprintf( ERR, warning, opt, mcpp_optarg); + /* Ignore -remap option */ + else + usage( opt); + break; + + case 's': + if (memcmp( mcpp_optarg, "td=", 3) == 0 + && ACE_OS::strlen( mcpp_optarg) > 3) { /* -std=STANDARD*/ + cp = mcpp_optarg + 3; + if (str_eq( cp, "c89") /* std=c89 */ + || str_eq( cp, "c90") /* std=c90 */ + || str_eq( cp, "gnu89") /* std=gnu89 */ + || str_eq( cp, "iso9899:1990")) { + std_val = 0L; /* C90 + extensions */ + } else if (str_eq( cp, "c99") /* std=c99 */ + || str_eq( cp, "c9x") /* std=c9x */ + || str_eq( cp, "gnu99") /* std=gnu99 */ + || str_eq( cp, "gnu9x") /* std=gnu9x */ + || str_eq( cp, "iso9899:1999") + || str_eq( cp, "iso9899:199x")) { + std_val = 199901L; + } else if (str_eq( cp, "c++98")) { /* std=c++98 */ + cplus_val = std_val = 199711L; + } else if (memcmp( cp, "iso9899:", 8) == 0 + && ACE_OS::strlen( cp) >= 14) { /* std=iso9899:199409, etc. */ + mcpp_optarg = cp + 8; + look_and_install( "__STRICT_ANSI__", DEF_NOARGS_PREDEF + , null, "1"); + ansi = TRUE; + goto Version; + } else if (memcmp( cp, "iso14882", 8) == 0) { + cp += 8; + ansi = TRUE; + if (cp && *cp == ':' && ACE_OS::strlen( cp) >= 7) { + /* std=iso14882:199711, etc. */ + cplus_val = CPLUS; + mcpp_optarg = cp + 1; + goto Version; + } else { + goto plus; + } + } else { + usage( opt); + } + if (! cplus_val && memcmp( cp, "gnu", 3) != 0) { + /* 'std=gnu*' does not imply -ansi */ + look_and_install( "__STRICT_ANSI__", DEF_NOARGS_PREDEF + , null, "1"); + ansi = TRUE; + } + stdc_val = 1; + sflag = TRUE; + } else { + usage( opt); + } + break; + + case 't': + if (str_eq( mcpp_optarg, "raditional") + || str_eq( mcpp_optarg, "raditional-cpp")) { + /* -traditional, -traditional-cpp */ + trad = TRUE; + mcpp_mode = OLD_PREP; + } else if (str_eq( mcpp_optarg, "rigraphs")) { + option_flags.trig = TRUE; /* -trigraphs */ + } else { + usage( opt); + } + break; +#endif /* COMPILER == GNUC */ + +#if COMPILER == MSC + case 'T': + if (ACE_OS::strlen( mcpp_optarg) > 1) + usage( opt); + i = tolower( *mcpp_optarg); /* Fold case */ + if (i == 'c') { + ; /* Ignore this option */ + } else if (i == 'p') { + cplus_val = CPLUS; + } else { + usage( opt); + } + break; +#endif + + case 'U': /* Undefine macro */ + if (undef_cnt >= MAX_UNDEF) { + mcpp_fputs( "Too many -U options.\n", ERR); + longjmp( error_exit, -1); + } + undef_list[ undef_cnt++] = mcpp_optarg; + break; + + case 'V': +#if COMPILER == GNUC + Version: +#endif + valp = eval_num( mcpp_optarg); + if (valp->sign == VAL_ERROR) + usage( opt); + std_val = (long) valp->val; + break; + + case 'v': + option_flags.v = TRUE; + show_path = TRUE; + break; + + case 'W': /* warning level */ + if (warn_level == -1) /* Have to initialize */ + warn_level = 0; +#if COMPILER == GNUC + if (argv[ mcpp_optind - 1] == mcpp_optarg) { /* No argument */ + /* + * Note: -W without argument is not officially supported. + * It may cause an error. + */ + warn_level |= (1 | 2 | 4 | 16); + mcpp_optind--; + } else if (str_eq( mcpp_optarg, "comment") + || str_eq( mcpp_optarg, "comments") + || str_eq( mcpp_optarg, "sign-compare")) { + warn_level |= 1; + } else if (str_eq( mcpp_optarg, "undef")) { + warn_level |= 4; + } else if (str_eq( mcpp_optarg, "all")) { + warn_level |= (1 | 16); /* Convert -Wall to -W17*/ + } else if (str_eq( mcpp_optarg, "trigraphs")) { + warn_level |= 16; + } +#endif /* COMPILER == GNUC */ +#if COMPILER == MSC + if (str_eq( mcpp_optarg, "all")) { + warn_level |= (1 | 16); /* Convert -Wall to -W17*/ + } else if (str_eq( mcpp_optarg, "L")) { + option_flags.no_source_line = TRUE; + /* Single-line diagnostic */ + } +#endif + if (isdigit( *mcpp_optarg)) { + warn_level |= parse_warn_level( mcpp_optarg, opt); + if (warn_level > 31 || warn_level < 0) + usage( opt); + } + if (warn_level == 0) + warn_level = 0xFF; /* Remember this option */ + /* Else ignore the option */ + break; + +#if COMPILER == GNUC || COMPILER == MSC + case 'w': /* Same as -W0 */ + warn_level = 0xFF; /* Remenber this option */ + break; +#endif + +#if COMPILER == GNUC + case 'x': + if (str_eq( mcpp_optarg, "c")) { + break; /* -x c -- ignore this */ + } else if (str_eq( mcpp_optarg, "c++")) { + goto plus; + } else if (str_eq( mcpp_optarg, "assembler-with-cpp")) { + option_flags.lang_asm = TRUE; + break; + } else { + usage( opt); + } + break; +#endif + +#if COMPILER == MSC + case 'Z': + if (str_eq( mcpp_optarg, "c:wchar_t")) { /* -Zc:wchar_t */ + look_and_install( "_NATIVE_WCHAR_T_DEFINED", DEF_NOARGS_PREDEF + , null, "1"); + look_and_install( "_WCHAR_T_DEFINED", DEF_NOARGS_PREDEF, null + , "1"); + wchar_t_modified = TRUE; + } else if (str_eq( mcpp_optarg, "c:wchar_t-")) {/* -Zc:wchar_t- */ + wchar_t_modified = TRUE; /* Do not define the macros */ + } else if (str_eq( mcpp_optarg, "l")) { + look_and_install( "_VC_NODEFAULTLIB", DEF_NOARGS_PREDEF, null + , "1"); + } else if (str_eq( mcpp_optarg, "a")) { /* -Za */ + undefine( "_MSC_EXTENSIONS"); + option_flags.dollar_in_name = FALSE; + } else if (str_eq( mcpp_optarg, "e")) { + /* Ignore -Ze silently */ + break; + } else if (*(mcpp_optarg + 1) == EOS) { + /* -Z followed by one char */ + mcpp_fprintf( ERR, warning, opt, mcpp_optarg); + /* Ignore the option with warning */ + } else { + usage( opt); + } + break; +#endif + + case 'z': + option_flags.z = TRUE; /* No output of included file */ + break; + + default: /* What is this one? */ + usage( opt); + break; + } /* Switch on all options */ + + } /* For all arguments */ + + if (mcpp_optind < argc && set_files( argc, argv, in_pp, out_pp) != 0) + goto opt_search; /* More options after the filename */ + + /* Check consistency of specified options, set some variables */ + chk_opts( sflag, trad); + + if (warn_level == -1) /* No -W option */ + warn_level = 1; /* Default warning level */ + else if (warn_level == 0xFF) + warn_level = 0; /* -W0 has high precedence */ + +#if SYSTEM == SYS_MAC + set_a_dir( 0); /* Initialize incdir[] */ + to_search_framework = incend; + /* Search framework[] next to the directory */ +#endif + +#if COMPILER == GNUC && SYSTEM == SYS_MAC + if (arch[ 0]) { /* -arch option has been specified */ + if (((str_eq( CPU, "i386") || str_eq( CPU, "x86_64")) + && (! str_eq( arch, "i386") && ! str_eq( arch, "x86_64"))) + || ((str_eq( CPU, "ppc") || str_eq( CPU, "ppc64")) + && (! str_eq( arch, "ppc") && ! str_eq( arch, "ppc64")))) { + mcpp_fprintf( ERR, "Wrong argument of -arch option: %s\n", arch); + longjmp( error_exit, -1); + } + } +#endif + if (! arch[ 0]) { + /* None of -arch, -m32 or -m64 options has been specified. */ + /* The CPU-specific-macros will be defined in init_cpu_macro(). */ + ACE_OS::strcpy( arch, CPU); + } +#if COMPILER != GNUC + init_cpu_macro( gval, sse); +#endif + +#if COMPILER == GNUC + if (sysdir < sysdir_end) { + char ** dp = sysdir; + if (! sys_dirp || sys_dirp == incdir) + sys_dirp = dp; + while (dp < sysdir_end) + set_a_dir( *dp++); + } + if (*in_pp && str_eq( (*in_pp) + ACE_OS::strlen( *in_pp) - 2, ".S")) + option_flags.lang_asm = TRUE; /* Input file name is *.S */ + if (option_flags.lang_asm) { + look_and_install( "__ASSEMBLER__", DEF_NOARGS_PREDEF, null, "1"); + option_flags.dollar_in_name = FALSE; /* Disable '$' in name */ + } + if (! sys_dirp || sys_dirp == incdir) + sys_dirp = incend; +#endif +#if SYSTEM == SYS_MAC + init_framework(); /* After setting sys_dirp */ +#endif + set_env_dirs(); + if (! unset_sys_dirs) + set_sys_dirs( set_cplus_dir); + + if (mkdep_mf) { /* -MF overrides -MD */ + mkdep_fp = ACE_OS::fopen( mkdep_mf, "w"); + } else if (mkdep_md) { + mkdep_fp = ACE_OS::fopen( mkdep_md, "w"); + } + if (mkdep_mq) /* -MQ overrides -MT */ + mkdep_target = mkdep_mq; + else if (mkdep_mt) + mkdep_target = mkdep_mt; + + /* Normalize the path-list */ + if (*in_pp && ! str_eq( *in_pp, "-")) { + char * tmp = norm_path( null, *in_pp, FALSE, FALSE); + if (tmp) /* The file exists */ + *in_pp = tmp; + /* Else mcpp_main() will diagnose *in_pp and exit */ + } + if (! (mcpp_debug & MACRO_CALL)) { + /* -K option alters behavior of -v option */ + if (option_flags.v) + version(); + if (show_path) { + fp_debug = stderr; + dump_path(); + fp_debug = stdout; + } + } +} + +static void version( void) +/* + * Print version message. + */ +{ + const char * mes[] = { + +#ifdef MCPP_LIB + /* Write messages here, for example, "MySomeTool with ". */ +#endif + +#ifdef VERSION_MSG + "MCPP V.2.7.2 (2008/11) " +#else + "MCPP V.", VERSION, " (", DATE, ") " +#endif +#if COMPILER == INDEPENDENT + , "compiler-independent-build " +#else +#ifdef CMP_NAME + , "for ", CMP_NAME, " " +#endif +#endif + , "compiled by " +#ifdef VERSION_MSG + , VERSION_MSG +#else +#ifdef HOST_CMP_NAME + , HOST_CMP_NAME +#if HOST_COMPILER == GNUC + , " V.", GCC_MAJOR_VERSION, ".", GCC_MINOR_VERSION +#endif +#endif +#endif + , "\n", + 0 + }; + + const char ** mpp = mes; + while (*mpp) + mcpp_fputs( *mpp++, ERR); +} + +static void usage( + int opt + ) +/* + * Print usage. + */ +{ + const char * mes[] = { + + "Usage: ", + "mcpp", + " [-<opts> [-<opts>]] [<infile> [-<opts>] [<outfile>] [-<opts>]]\n", + " <infile> defaults to stdin and <outfile> defaults to stdout.\n", + + "\nCommonly used options:\n", + + "-@MODE Specify preprocessing mode. MODE should be one of these 4:\n", + " -@std Standard conforming mode. (default)\n", + " -@poststd, -@post special 'post-Standard' mode.\n", + " -@kr K&R 1st mode.\n", + " -@oldprep, -@old 'old_preprocessor' mode (i.e. 'Reiser model' cpp).\n", + +#if COMPILER == MSC + "-arch:SSE, -arch:SSE2 Define the macro _M_IX86_FP as 1, 2 respectively.\n", +#endif +#if SYSTEM == SYS_MAC && COMPILER == GNUC + "-arch <arch> Change the target to <arch> (i386, x86_64, ppc, ppc64).\n", +#endif + +#if ! STD_LINE_PREFIX + "-b Output #line lines in C source style.\n", +#endif + + "-C Output also comments.\n", + "-D <macro>[=<value>] Define <macro> as <value> (default:1).\n", + "-D <macro(args)>[=<replace>] Define <macro(args)> as <replace>.\n", + "-e <encoding> Change the default multi-byte character encoding to one of:\n", + " euc_jp, gb2312, ksc5601, big5, sjis, iso2022_jp, utf8.\n", + +#if SYSTEM == SYS_MAC + "-F <framework> Add <framework> to top of framework directory list.\n", +#endif +#if COMPILER == GNUC + "-finput-charset=<encoding> Same as -e <encoding>.\n", + " (Don't insert spaces around '=').\n", +#endif +#if COMPILER == MSC + "-Fl <file> Include the <file> prior to the main input file.\n", + "-G<n> Define the macro _M_IX86 according to <n>.\n", +#endif +#if COMPILER == LCC + "-g <n> Define the macro __LCCDEBUGLEVEL as <n>.\n", +#endif + + "-I <directory> Add <directory> to the #include search list.\n", + +#if COMPILER == GNUC + "-isysroot <dir> Change root of system header directory to <dir>.\n", + "-include <file> Include the <file> prior to the main input file.\n", +#else + "-I- Unset system or site specific include directories.\n", +#endif +#if COMPILER == MSC + "-J Define the macro _CHAR_UNSIGNED as 1.\n", +#endif + + "-j Don't output the source line in diagnostics.\n", + "-M, -MM, -MD, -MMD, -MP, -MQ target, -MT target, -MF file\n", + " Output source file dependency line for makefile.\n", +#if SYS_FAMILY == SYS_UNIX + "-m32 Change target CPU from x86_64, ppc64 to i386, ppc, respectively.\n", + "-m64 Change target CPU from i386, ppc to x86_64, ppc64, respectively.\n", +#endif + "-N Don't predefine any non-standard macros.\n", + +#if COMPILER == GNUC + "-nostdinc Unset system or site specific include directories.\n", +#endif +#if COMPILER == LCC + "-O Define the macro __LCCOPTIMLEVEL as 1.\n", +#endif + + "-o <file> Output to <file>.\n", + "-P Don't output #line lines.\n", + "-Q Output diagnostics to \"mcpp.err\" (default:stderr).\n", +#if COMPILER == MSC + "-RTC* Define the macro __MSVC_RUNTIME_CHECKS as 1.\n", +#endif +#if COMPILER == GNUC + "-traditional, -traditional-cpp Same as -@oldprep.\n", +#endif + "-U <macro> Undefine <macro>.\n", + +#if COMPILER == GNUC + "-undef Same as -N.\n", +#endif +#if COMPILER == MSC + "-u Same as -N.\n", +#endif + + "-v Show version and include directories of mcpp.\n", + "-W <level> Set warning level to <level> (OR of {0,1,2,4,8,16}, default:1).\n", + +#if COMPILER == MSC + "-WL Same as -j.\n", +#endif +#if COMPILER == MSC || COMPILER == GNUC + "-w Same as -W0.\n", +#endif +#if COMPILER == MSC + "-X Same as -I-.\n", + "-Zc:wchar_t Define _NATIVE_WCHAR_T_DEFINED and _WCHAR_T_DEFINED as 1.\n", + "-Zl Define the macro _VC_NODEFAULTLIB as 1.\n", +#endif + + "-z Don't output the included file, only defining macros.\n", + + "\nOptions available with -@std (default) or -@poststd options:\n", + + "-+ Process C++ source.\n", + +#if DIGRAPHS_INIT + "-2 Disable digraphs.\n", +#else + "-2 Enable digraphs.\n", +#endif +#if COMPILER == GNUC + "-digraphs Enable digraphs.\n", +#endif + + "-h <n> Re-define the pre-defined macro __STDC_HOSTED__ as <n>.\n", + +#if COMPILER == GNUC + "-lang-c89 Same as -S1.\n", + "-lang-c++ Same as -+.\n", + "-pedantic, -pedantic-errors Same as -W7.\n", + "-S <n> Redefine __STDC__ to <n>.\n", +#else + "-S <n> Redefine __STDC__ to <n>, undefine old style macros.\n", +#endif + +#if COMPILER == GNUC + "-std=<STANDARD> Specify the standard to which the code should conform.\n", + " <STANDARD> may be one of: c90, c99, iso9899:1990, iso14882, etc.\n", + " iso9899:<n>, iso14882:<n> : Same as -V <n> (long in decimals).\n", +#endif +#if COMPILER == MSC + "-Tp Same as -+.\n", +#endif + + "-V <n> Redefine __STDC_VERSION__ or __cplusplus to <n>.\n", + " C with -V199901L specifies C99 specs.\n", + " C++ with -V199901L specifies C99 compatible specs.\n", + +#if COMPILER == GNUC + "-x c++ Same as -+.\n", +#endif + + "\nOptions available with only -@std (default) option:\n", + + "-@compat Expand recursive macro more than Standard.\n", +#if TRIGRAPHS_INIT + "-3 Disable trigraphs.\n", +#else + "-3 Enable trigraphs.\n", +#endif + "-K Output macro annotations embedding in comments.\n", +#if COMPILER == GNUC + "-trigraphs Enable trigraphs.\n", +#endif + + "\nOptions available with -@std (default), -@kr or -@oldprep options:\n", + +#if COMPILER == GNUC + "-lang-asm Same as -x assembler-with-cpp.\n", + "-x assembler-with-cpp Process \"assembler\" source.\n", +#elif COMPILER == MSC + "-A Process \"assembler\" source.\n", +#else + "-a Process \"assembler\" source.\n", +#endif + + "-k Keep white spaces of input lines as they are.\n", + + "\nFor further details see mcpp-manual.html.\n", + 0, + }; + + const char * illegopt = "Incorrect option -%c%s\n"; + const char * const * mpp = mes; + + if (opt != '?') + mcpp_fprintf( ERR, illegopt, opt, mcpp_optarg ? mcpp_optarg : null); + version(); +#ifdef MCPP_LIB + mes[ 1] = argv0; +#endif + while (*mpp) + mcpp_fputs( *mpp++, ERR); + longjmp( error_exit, -1); +} + +static void set_opt_list( + char * optlist + ) +/* + * Set list of legal option characters. + */ +{ + const char * list[] = { + +#if ! STD_LINE_PREFIX + "b", +#endif + +#if SYS_FAMILY == SYS_UNIX + "m:", +#endif + +#if COMPILER == GNUC + "$A:a:cd:Ef:g:i:l:r:s:t:u:O:p:q:wx:", +#elif COMPILER == MSC + "Aa:F:G:JR:T:XZ:uw", +#elif COMPILER == LCC + "g:O", +#endif + +#if COMPILER != GNUC && COMPILER != MSC + "a", +#endif +#if SYSTEM == SYS_MAC + "F:-:", +#endif + + 0 + }; + + const char * const * lp = & list[ 0]; + + ACE_OS::strcpy( optlist, "23+@:e:h:jkn:o:vzCD:I:KM:NPQS:U:V:W:"); + /* Default options */ + while (*lp) + ACE_OS::strcat( optlist, *lp++); + if (ACE_OS::strlen( optlist) >= OPTLISTLEN) + cfatal( "Bug: Too long option list", 0, 0L, 0); /* _F_ */ +} + +static int parse_warn_level( + const char * mcpp_optarg, + int opt + ) +/* + * Parse warn level option. + * Warning level option is specified as '19' or '1|2|16' or even '3|16'. + * Even spaces are allowed as ' 1 | 2|16 '. + */ +{ + const char * cp = mcpp_optarg; + int w, i; + + w = i = 0; + while( *cp != EOS) { + while( *cp == ' ') + cp++; /* Skip spaces */ + if (! isdigit( *cp)) + break; /* Error */ + while (isdigit( *cp)) { + i *= 10; + i += (*cp++ - '0'); + } + while (*cp == ' ') + cp++; + if (*cp == '|') { /* Only digits or '|' are allowed */ + w |= i; /* Take OR of the args */ + i = 0; + cp++; + } + } + if (*cp != EOS) { /* Not ending with digit */ + mcpp_fprintf( ERR, "Illegal warning level option \"%s\"\n" + , mcpp_optarg); + usage( opt); + } + w |= i; /* Take the last arg */ + return w; +} + +static void def_a_macro(int opt, /* 'D' */ + char * def /* Argument of -D option */ + ) +/* + * Define a macro specified by -D option. + * The macro maybe either object-like or function-like (with parameter). + */ +{ + DEFBUF * defp; + char * definition; /* Argument of -D option */ + char * cp; + int i; + + /* Convert trigraphs for the environment which need trigraphs */ + if (mcpp_mode == STD && option_flags.trig) + cnv_trigraph( def); + if (mcpp_mode == POST_STD && option_flags.dig) + cnv_digraph( def); /* Convert prior to installing macro */ + definition = (char *)ACE_OS::malloc( ACE_OS::strlen( def) + 6); + ACE_OS::strcpy( definition, def); + if ((cp = ACE_OS::strchr( definition, '=')) != 0) { + *cp = ' '; /* Remove the '=' */ + // cp = "\n"; /* Append <newline> */ + *(cp + 0) = '\n'; + *(cp + 1) = '\0'; + } else { + cp = ACE_OS::strlen (def) + definition; + *(cp + 0) = ' '; + *(cp + 1) = '1'; + *(cp + 2) = '\n'; + *(cp + 3) = '\0'; + //cp = " 1\n"; /* With definition "1" */ + } + cp = definition; + while ((char_type[ *cp & UCHARMAX] & SPA) == 0) + cp++; + i = *cp; + *cp = EOS; + if ((defp = look_id( definition)) != 0) /* Pre-defined */ + undefine( definition); + *cp = i; + /* Now, save the definition. */ + unget_string( definition, 0); + if (do_define( FALSE, 0) == 0) /* Define a macro */ + usage( opt); + *cp = EOS; + if (str_eq( definition, "__STDC__")) { + defp = look_id( definition); + defp->nargs = DEF_NOARGS_STANDARD; + /* Restore Standard-predefinedness */ + } + ACE_OS::free( definition); + skip_nl(); /* Clear the appended <newline> */ +} + +static void chk_opts( + int sflag, /* Flag of Standard or post-Standard mode */ + int trad /* -traditional (GCC only) */ + ) +/* + * Check consistency between the specified options. + * Set default value of some variables for each 'mcpp_mode'. + */ +{ + int incompat = FALSE; + + switch (mcpp_mode) { + case STD : + case POST_STD : + if (trad) + incompat = TRUE; + if (! stdc_val) + stdc_val = STDC; + break; + case KR : + case OLD_PREP : +#if COMPILER == GNUC + if (sflag || cplus_val || ansi || std_val != -1L) +#else + if (sflag || cplus_val || std_val != -1L) +#endif + incompat = TRUE; + if (option_flags.dig) { + if (option_flags.dig != DIGRAPHS_INIT) + incompat = TRUE; + else + option_flags.dig = 0; + } + break; + } + + if (mcpp_mode == POST_STD + && (option_flags.lang_asm || compat_mode || option_flags.k)) + incompat = TRUE; + if (mcpp_mode != STD && option_flags.trig) { + if (option_flags.trig != TRIGRAPHS_INIT) + incompat = TRUE; + else + option_flags.trig = FALSE; + } + if (mcpp_mode != STD && (mcpp_debug & MACRO_CALL)) + incompat = TRUE; + if ((mcpp_debug & MACRO_CALL) + && (option_flags.lang_asm || option_flags.c)) { + mcpp_fputs( "Disabled -K option.\n", ERR); + mcpp_debug &= ~MACRO_CALL; + /* -a and -C options do not co-exist with -K */ + } + if (incompat) { + mcpp_fputs( "Incompatible options are specified.\n", ERR); + usage( '?'); + } + + standard = (mcpp_mode == STD || mcpp_mode == POST_STD); + /* Modify magic characters in character type table. */ + if (! standard) + char_type[ DEF_MAGIC] = 0; + if (mcpp_mode != STD) + char_type[ IN_SRC] = 0; + if (mcpp_mode == POST_STD || mcpp_mode == KR) + char_type[ TOK_SEP] = 0; /* TOK_SEP equals to COM_SEP */ + if (mcpp_mode != STD) + char_type[ MAC_INF] = 0; + + expand_init( compat_mode, ansi); + /* Set function pointer to macro expansion routine */ +} + +#if COMPILER != GNUC + +static void init_cpu_macro ( + int gval, /* Argument of -G option for MSC */ + int sse /* Argument of -sse: option for MSC */ + ) +/* + * Set predefined macros for CPU. + * This routine is called from do_options() only once. + * GCC-specific-build defines these macro by init_gcc_macro(). + */ +{ + ACE_UNUSED_ARG (gval); + ACE_UNUSED_ARG (sse); + + const char * cpu_macro[][ 7] = { +#if SYS_FAMILY == SYS_UNIX + { "__i386__" +#if SYSTEM == SYS_CYGWIN + , "_X86_" +#endif + , 0,}, + { "__x86_64__", "__amd64__", 0,}, + { "__ppc__", "__powerpc__", 0,}, + { "__ppc64__", "__powerpc64__", 0,} +#elif SYS_FAMILY == SYS_WIN + { "_WIN32", "__WIN32__", "_X86_" +#if SYSTEM == SYS_MINGW + , "__i386__" +#endif + , 0,}, + { "_WIN32", "_WIN64", "__WIN64__", "_M_AMD64", "_AMD64_", "_X64_" + , 0,}, /* "_WIN32" is defined even on Windows 64 */ + { 0,}, /* Not supported */ + { 0,} /* Not supported */ +#endif + }; + const char ** macro; + int index; + + if (str_eq( arch, "i386")) + index = 0; + else if (str_eq( arch, "x86_64")) + index = 1; + else if (str_eq( arch, "ppc")) + index = 2; + else if (str_eq( arch, "ppc64")) + index = 3; + else + index = 9; + + if (index == 9) { /* Unknown CPU */ + look_and_install( "__" CPU "__", DEF_NOARGS_PREDEF, null, "1"); + return; + } + macro = cpu_macro[ index]; + while (*macro) + look_and_install( *macro++, DEF_NOARGS_PREDEF, null, "1"); +#if SYS_FAMILY == SYS_WIN + if (index == 0) { + char val[] = "600"; + if (gval) + val[ 0] = gval; + look_and_install( "_M_IX86", DEF_NOARGS_PREDEF, null, val); + val[ 0] = '0' + sse; + val[ 1] = '\0'; + look_and_install( "_M_IX86_FP", DEF_NOARGS_PREDEF, null, val); + } +#endif +} +#endif /* COMPILER != GNUC */ + +static void init_predefines( void) +/* + * Set or unset predefined macros. + */ +{ + char tmp[ 16]; + + if (std_val != -1L) { /* Version is specified */ + if (cplus_val) + cplus_val = std_val; /* Value of __cplusplus */ + else + stdc_ver = std_val; /* Value of __STDC_VERSION__ */ + } else { + if (! cplus_val) + stdc_ver = stdc_val ? STDC_VERSION : 0L; + } + + if (nflag) { + un_predefine( TRUE); + } else if (stdc_val || cplus_val) { +#if COMPILER != GNUC + un_predefine( FALSE); /* Undefine "unix" or so */ +#endif + } + ACE_OS::sprintf( tmp, "%ldL", cplus_val ? cplus_val : stdc_ver); + if (cplus_val) { + look_and_install( "__cplusplus", DEF_NOARGS_STANDARD, null, tmp); + } else { + if (stdc_ver) + look_and_install( "__STDC_VERSION__", DEF_NOARGS_STANDARD, null + , tmp); +#ifdef COMPILER_CPLUS + if (! nflag) /* Undefine pre-defined macro for C++ */ + undefine( COMPILER_CPLUS); +#endif + } + set_limit(); + stdc2 = cplus_val || stdc_ver >= 199901L; + stdc3 = (cplus_val >= 199901L) || (stdc_ver >= 199901L); + /* (cplus_val >= 199901L) makes C++ C99-compatible specs */ + if (standard) + init_std_defines(); + if (stdc3) + set_pragma_op(); +} + +static void init_std_defines( void) +/* + * For STD and POST_STD modes. + * The magic pre-defines are initialized with magic argument counts. + * expand_macro() notices this and calls the appropriate routine. + * DEF_NOARGS is one greater than the first "magic" definition. + * 'DEF_NOARGS - n' are reserved for pre-defined macros. + * __STDC_VERSION__ and __cplusplus are defined by chk_opts() and set_cplus(). + */ +{ + char tmp[ 16]; + char timestr[ 14]; + time_t tvec; + char * tstring; + + look_and_install( "__LINE__", DEF_NOARGS_DYNAMIC - 1, null, "-1234567890"); + /* Room for 11 chars (10 for long and 1 for '-' in case of wrap round. */ + look_and_install( "__FILE__", DEF_NOARGS_DYNAMIC - 2, null, null); + /* Should be stuffed */ + + /* Define __DATE__, __TIME__ as present date and time. */ + ACE_OS::time( &tvec); + tstring = ACE_OS::ctime( &tvec); + ACE_OS::sprintf( timestr, "\"%.3s %c%c %.4s\"", + tstring + 4, + *(tstring + 8) == '0' ? ' ' : *(tstring + 8), + *(tstring + 9), + tstring + 20); + look_and_install( "__DATE__", DEF_NOARGS_DYNAMIC, null, timestr); + ACE_OS::sprintf( timestr, "\"%.8s\"", tstring + 11); + look_and_install( "__TIME__", DEF_NOARGS_DYNAMIC, null, timestr); + + if (! look_id( "__STDC_HOSTED__")) { + /* + * Some compilers, e.g. GCC older than 3.3, define this macro by + * -D option. + */ + ACE_OS::sprintf( tmp, "%d", STDC_HOSTED); + look_and_install( "__STDC_HOSTED__", DEF_NOARGS_PREDEF, null, tmp); + } +#if COMPILER != GNUC /* GCC do not undefine __STDC__ on C++ */ + if (cplus_val) + return; +#endif + /* Define __STDC__ as 1 or such for Standard conforming compiler. */ + if (! look_id( "__STDC__")) { + ACE_OS::sprintf( tmp, "%d", stdc_val); + look_and_install( "__STDC__", DEF_NOARGS_STANDARD, null, tmp); + } +} + +static void set_limit( void) +/* + * Set the minimum translation limits specified by the Standards. + */ +{ + if (cplus_val) { /* Specified by C++ 1998 Standard */ + std_limits.str_len = SLEN_CPLUS_MIN; + std_limits.id_len = IDLEN_CPLUS_MIN; + std_limits.n_mac_pars = NMACPARS_CPLUS_MIN; + std_limits.exp_nest = EXP_NEST_CPLUS_MIN; + std_limits.blk_nest = BLK_NEST_CPLUS_MIN; + std_limits.inc_nest = INCLUDE_NEST_CPLUS_MIN; + std_limits.n_macro = NMACRO_CPLUS_MIN; + std_limits.line_num = LINE_CPLUS_LIMIT; + } else if (stdc_ver >= 199901L) { /* Specified by C 1999 Standard */ + std_limits.str_len = SLEN99MIN; + std_limits.id_len = IDLEN99MIN; + std_limits.n_mac_pars = NMACPARS99MIN; + std_limits.exp_nest = EXP_NEST99MIN; + std_limits.blk_nest = BLK_NEST99MIN; + std_limits.inc_nest = INCLUDE_NEST99MIN; + std_limits.n_macro = NMACRO99MIN; + std_limits.line_num = LINE99LIMIT; + } else if (standard) { /* Specified by C 1990 Standard */ + std_limits.str_len = SLEN90MIN; + std_limits.id_len = IDLEN90MIN; + std_limits.n_mac_pars = NMACPARS90MIN; + std_limits.exp_nest = EXP_NEST90MIN; + std_limits.blk_nest = BLK_NEST90MIN; + std_limits.inc_nest = INCLUDE_NEST90MIN; + std_limits.n_macro = NMACRO90MIN; + std_limits.line_num = LINE90LIMIT; + } + /* Else pre-Standard mode */ +} + +static void set_pragma_op( void) +/* + * #define _Pragma(a) _Pragma ( a ) + * Define _Pragma() operator as a special macro so as to be searched + * easily. The unusual 'DEF_PRAGMA' is a marker of this psuedo + * macro. + */ +{ + const char * name = "_Pragma"; + char tmp[ 16]; + + ACE_OS::sprintf( tmp, "%c%s ( %c%c )", DEF_MAGIC, name, MAC_PARM, 1); + /* Replacement text */ + look_and_install( name, DEF_PRAGMA, "a", tmp); +} + +void init_sys_macro( void) +/* + * Define system-specific macros and some Standard required macros + * and undefine macros specified by -U options. + */ +{ + /* This order is important. */ + + def_macros(); /* Define macros specified by -D */ +#if COMPILER == GNUC + chk_env(); +#endif + init_predefines(); /* Define predefined macros */ +#if COMPILER == GNUC + init_gcc_macro(); +#elif COMPILER == MSC + init_msc_macro(); +#endif + undef_macros(); /* Undefine macros specified by -U */ + if (mcpp_debug & MACRO_CALL) + dump_def( FALSE, TRUE); /* Finally putout current macro names */ +} + +void at_start( void) +/* + * Do the commands prior to processing main source file after do_options(). + */ +{ + char * env; + FILEINFO * file_saved = infile; + + /* + * Set multi-byte character encoding according to environment variables + * LC_ALL, LC_CTYPE and LANG -- with preference in this order. + */ + if (! mb_changed) { /* -m option precedes */ + if ((env = ACE_OS::getenv( "LC_ALL")) != 0) + set_encoding( env, "LC_ALL", 0); + else if ((env = ACE_OS::getenv( "LC_CTYPE")) != 0) + set_encoding( env, "LC_CTYPE", 0); + else if ((env = ACE_OS::getenv( "LANG")) != 0) + set_encoding( env, "LANG", 0); + } + +#if COMPILER == GNUC || COMPILER == MSC + if (option_flags.dollar_in_name) + char_type[ 0x24] |= LET; /* Enable '$' in identifiers */ + /* + * Do the -include (-Fl for MSC) options in the specified order. + * Note: This functionality is implemented as nested #includes + * which results the same effect as sequential #includes. + */ + { + char ** preinc; + /* + * Note: Here, 'infile' is the main input file, which is pseudo- + * parent file of the files to pre-include. So, we must + * temporarily set the infile's directory to the current directory + * in order to preinclude the files relative to it. + */ + preinc = preinc_end; + while (preinclude <= --preinc && *preinc != 0) + open_file( &null, 0, *preinc, TRUE, TRUE, FALSE); + } +#endif + + put_info( file_saved); +} + +static void put_info( + FILEINFO * sharp_file + ) +/* + * Putout compiler-specific information. + */ +{ + if (no_output || option_flags.p) + return; + sharp_file->line++; + sharp( sharp_file, 0); + sharp_file->line--; +#if COMPILER == GNUC + if (gcc_work_dir) + mcpp_fprintf( OUT, "%s%ld \"%s%c\"\n" + , std_line_prefix ? "#line " : LINE_PREFIX + , 1, cur_work_dir, '/'); + /* Putout the current directory as a #line line as: */ + /* '# 1 "/abs-path/cur_dir//"'. */ + mcpp_fprintf( OUT, "%s%ld \"<built-in>\"\n" + , std_line_prefix ? "#line " : LINE_PREFIX , 1); + mcpp_fprintf( OUT, "%s%ld \"<command line>\"\n" + , std_line_prefix ? "#line " : LINE_PREFIX , 1); + mcpp_fprintf( OUT, "%s%ld \"%s\"%s\n" + , std_line_prefix ? "#line " : LINE_PREFIX, 1, cur_fullname + , ! str_eq( cur_fullname, sharp_file->full_fname) ? " 1" : null); + /* Suffix " 1" for the file specified by -include */ +#endif +} + +static char * set_files( + int argc, + char ** argv, + const char ** in_pp, + const char ** out_pp + ) +/* + * Set input and/or output files. + */ +{ + char * cp; + + if (*in_pp == 0) { /* Input file */ + cp = argv[ mcpp_optind++]; +#if SYS_FAMILY == SYS_WIN + cp = bsl2sl( cp); +#endif + *in_pp = cp; + } + if (mcpp_optind < argc && argv[ mcpp_optind][ 0] != '-' + && *out_pp == 0) { + cp = argv[ mcpp_optind++]; +#if SYS_FAMILY == SYS_WIN + cp = bsl2sl( cp); +#endif + *out_pp = cp; /* Output file */ + } + if (mcpp_optind >= argc) + return 0; /* Exhausted command line arguments */ + if (argv[ mcpp_optind][ 0] == '-') + return argv[ mcpp_optind]; /* More options */ + cfatal( "Excessive file argument \"%s\"", argv[ mcpp_optind], 0L , 0); + return 0; +} + +static void set_env_dirs( void) +/* + * Add to include path those specified by environment variables. + */ +{ + const char * env; + + if (cplus_val) { + if ((env = ACE_OS::getenv( ENV_CPLUS_INCLUDE_DIR)) != 0) + parse_env( env); + } + if ((env = ACE_OS::getenv( ENV_C_INCLUDE_DIR)) != 0) + parse_env( env); +} + +static void parse_env( + const char * env + ) +/* + * Parse environmental variable and append the path to include-dir-list. + */ +{ + char * save; + char * save_start; + char * p; + int sep; + + save = save_start = save_string( env); + while (*save) { + p = save; + while (*p && *p != ENV_SEP) + p++; + if (p != save) { /* Variable separator */ + sep = *p; + *p = EOS; + set_a_dir( save); + if (sep == EOS) + break; + save = ++p; + } + while (*save == ENV_SEP) + ++save; + } + ACE_OS::free( save_start); +} + +static void set_sys_dirs( + int set_cplus_dir /* Set C++ include-directory too */ + ) +/* + * Set site-specific and system-specific directories to the include directory + * list. + */ +{ + if (cplus_val && set_cplus_dir) { +#ifdef CPLUS_INCLUDE_DIR1 + set_a_dir( CPLUS_INCLUDE_DIR1); +#endif +#ifdef CPLUS_INCLUDE_DIR2 + set_a_dir( CPLUS_INCLUDE_DIR2); +#endif +#ifdef CPLUS_INCLUDE_DIR3 + set_a_dir( CPLUS_INCLUDE_DIR3); +#endif +#ifdef CPLUS_INCLUDE_DIR4 + set_a_dir( CPLUS_INCLUDE_DIR4); +#endif + } + +#if SYS_FAMILY == SYS_UNIX + set_a_dir( "/usr/local/include"); +#endif + +#ifdef C_INCLUDE_DIR1 + set_a_dir( C_INCLUDE_DIR1); +#endif +#ifdef C_INCLUDE_DIR2 + set_a_dir( C_INCLUDE_DIR2); +#endif + +#if SYS_FAMILY == SYS_UNIX +#if SYSTEM == SYS_CYGWIN + if (no_cygwin) /* -mno-cygwin */ + set_a_dir( "/usr/include/mingw"); + else + set_a_dir( "/usr/include"); +#else + set_a_dir( "/usr/include"); /* Should be placed after C_INCLUDE_DIR? */ +#endif +#endif +} + +static void set_a_dir( + const char * dirname /* The path-name */ + ) +/* + * Append an include directory. + * This routine is called from the following routines (in this order). + * 1. do_options() by -I option. + * 2. do_options() by -isystem option (for GNUC). + * 3. set_env_dirs() by environment variables. + * 4. set_sys_dirs() by CPLUS_INCLUDE_DIR?, C_INCLUDE_DIR? and system- + * specifics (unless -I- or -nostdinc option is specified). + * Ignore non-existent directory. + * Note that this routine should be called only in initializing steps, + * because increase of include dirs causes reallocation of incdir[]. + * Note: a trailing PATH-DELIM is appended by norm_path(). + */ +{ + char * norm_name; + const char ** ip; + + if (incdir == 0) { /* Should be initialized */ + max_inc = INIT_NUM_INCLUDE; + incdir = (const char **) ACE_OS::malloc( sizeof (char *) * max_inc); + incend = &incdir[ 0]; + } else if (incend - incdir >= max_inc) { /* Buffer full */ +#if SYSTEM == SYS_MAC + size_t framework_pos = to_search_framework - incdir; +#endif +#if COMPILER == GNUC + size_t sys_pos = 0; + if (sys_dirp) + sys_pos = sys_dirp - incdir; +#endif + incdir = (const char **) ACE_OS::realloc( reinterpret_cast <char *> (incdir), sizeof (char *) * max_inc * 2); + incend = &incdir[ max_inc]; +#if COMPILER == GNUC + if (sys_pos) + sys_dirp = &incdir[ sys_pos]; +#endif +#if SYSTEM == SYS_MAC + to_search_framework = &incdir[ framework_pos]; +#endif + max_inc *= 2; + } + + if (dirname == 0) + return; /* Only to initialize incdir[] */ + norm_name = norm_dir( dirname, FALSE); + if (! norm_name) /* Non-existent */ + return; + for (ip = incdir; ip < incend; ip++) { + if (str_case_eq( *ip, norm_name)) { + if (option_flags.v && ! (mcpp_debug & MACRO_CALL)) + mcpp_fprintf( ERR, "Duplicate directory \"%s\" is ignored\n" + , norm_name); + ACE_OS::free( norm_name); /* Already registered */ + return; + } + } + /* Register new directory */ + *incend++ = norm_name; +} + +#if SYSTEM == SYS_MAC && COMPILER == GNUC +/* Definitions for "header map" file of Xcode / Apple-GCC. */ +/* These definitions were taken from cpplib.h of Apple-GCC-4.0.1 */ + +#define HMAP_SAME_ENDIANNESS_MAGIC \ + (((((('h' << 8) | 'm') << 8) | 'a') << 8) | 'p') + +typedef unsigned short uint16; +typedef unsigned int uint32; + +struct hmap_bucket +{ + uint32 key; /* Offset (into strings) of key */ + struct { + uint32 prefix; /* Offset (into strings) of value prefix */ + uint32 suffix; /* Offset (into strings) of value suffix */ + } value; /* Value (prefix- and suffix-strings) */ +}; + +struct hmap_header_map +{ + uint32 magic; /* Magic word, also indicates byte order */ + uint16 version; /* Version number -- currently 1 */ + uint16 _reserved; /* Reserved for future use -- zero for now */ + uint32 strings_offset; /* Offset to start of string pool */ + uint32 count; /* Number of entries in the string table */ + uint32 capacity; /* Number of buckets (always a power of 2) */ + uint32 max_value_length; + /* Length of longest result path (excl. '\0') */ + struct hmap_bucket buckets[1]; + /* Inline array of 'capacity' maptable buckets */ + /* Strings follow the buckets, at strings_offset. */ +}; +#endif + +static char * norm_dir( + const char * dirname, /* Directory path to normalize */ + int /*framework*/ /* Setting a framework directory*/ + ) +/* + * Normalize include directory path. + * Handle -isysroot option for GCC, including framework directory for SYS_MAC. + */ +{ + char * norm_name; + +#if COMPILER == GNUC + if (sysroot && sys_dirp) { + /* Logical system root specified and dirname is system header dir */ + char delim[ 2] = { EOS, EOS}; + char * dir; +#if SYSTEM == SYS_MAC + if (! framework && memcmp( dirname, "/usr/", 5) != 0) + return 0; /* /Developer/usr/lib/gcc/ */ +#endif + if (dirname[ 0] != PATH_DELIM) + delim[ 0] = PATH_DELIM; + dir = ACE_OS::malloc( ACE_OS::strlen( sysroot) + ACE_OS::strlen( dirname) + 2); + ACE_OS::sprintf( dir, "%s%s%s", sysroot, delim, dirname); + dirname = dir; + } +#endif +#if SYSTEM == SYS_MAC && COMPILER == GNUC + if (ACE_OS::strlen( dirname) > 5 + && str_case_eq( dirname + ACE_OS::strlen( dirname) - 5, ".hmap")) { + /* "header map" file (not an include directory) */ + norm_name = norm_path( null, dirname, FALSE, TRUE); + if (! norm_name && option_flags.v) + mcpp_fprintf( ERR, "Invalid header map file \"%s\" is ignored\n" + , dirname); + } else +#endif + { + norm_name = norm_path( dirname, 0, FALSE, FALSE); + /* Normalize the pathname to compare */ + if (! norm_name && option_flags.v && ! (mcpp_debug & MACRO_CALL)) + mcpp_fprintf( ERR, "Non-existent directory \"%s\" is ignored\n" + , dirname); + } +#if COMPILER == GNUC + if (sysroot && sys_dirp) + ACE_OS::free( dirname); +#endif + + return norm_name; +} + +static char * norm_path( + const char * dir, /* Include directory (maybe "", never 0) */ + const char * fname, + /* Filename (possibly has directory part, or maybe 0) */ + int inf, /* If TRUE, output some infs when (mcpp_debug & PATH) */ + int /*hmap*/ /* "header map" file of Apple-GCC */ + ) +/* + * Normalize the pathname removing redundant components such as + * "foo/../", "./" and trailing "/.". + * Append trailing "/" if 'fname' is 0. + * Change relative path to absolute path. + * Dereference a symbolic linked file (or directory) to a real directory/file. + * Return a malloc'ed buffer, if the directory/file exists. + * Return 0, if the specified directory/file does not exist or 'dir' is + * not a directory or 'fname' is not a regular file. + * This routine is called from set_a_dir(), init_gcc_macro(), do_once() and + * open_file(). + */ +{ + char * norm_name; /* The path-list converted */ + char * start; + char * cp1; + char * cp2; + char * abs_path; + int len; /* Should not be size_t */ + size_t start_pos = 0; + char slbuf1[ PATHMAX+1]; /* Working buffer */ +#if SYS_FAMILY == SYS_UNIX + char slbuf2[ PATHMAX+1]; /* Working buffer for dereferencing */ +#endif +#if SYSTEM == SYS_CYGWIN || SYSTEM == SYS_MINGW + static char * root_dir; + /* System's root directory in Windows file system */ + static size_t root_dir_len; +#if SYSTEM == SYS_CYGWIN + static char * cygdrive = "/cygdrive/"; /* Prefix for drive letter */ +#else + static char * mingw_dir; /* "/mingw" dir in Windows */ + static size_t mingw_dir_len; +#endif +#endif +#if HOST_COMPILER == MSC + struct _stat st_buf; +#else + ACE_stat st_buf; +#endif + + if (! dir || (*dir && is_full_path( fname))) + cfatal( "Bug: Wrong argument to norm_path()" /* _F_ */ + , 0, 0L, 0); + inf = inf && (mcpp_debug & PATH); /* Output information */ + + ACE_OS::strcpy( slbuf1, dir); /* Include directory */ + len = ACE_OS::strlen( slbuf1); + if (fname && len && slbuf1[ len - 1] != PATH_DELIM) { + slbuf1[ len] = PATH_DELIM; /* Append PATH_DELIM */ + slbuf1[ ++len] = EOS; + } else if (! fname && len && slbuf1[ len - 1] == PATH_DELIM) { + /* stat() of some systems do not like trailing '/' */ + slbuf1[ --len] = EOS; + } + if (fname) + ACE_OS::strcat( slbuf1, fname); + if (ACE_OS::stat( slbuf1, & st_buf) != 0 /* Non-existent */ + || (! fname && ! S_ISDIR( st_buf.st_mode)) + /* Not a directory though 'fname' is not specified */ + || (fname && ! S_ISREG( st_buf.st_mode))) + /* Not a regular file though 'fname' is specified */ + return 0; +#if SYSTEM == SYS_MAC && COMPILER == GNUC + if (hmap) { /* Dirty "header map" file */ + struct hmap_header_map hmap; + size_t cnt; + FILE * fp; + fp = fopen( fname, "r"); + cnt = fread( & hmap, sizeof (struct hmap_header_map), 1, fp); + fclose( fp); + if (cnt == 0 || hmap.magic != HMAP_SAME_ENDIANNESS_MAGIC) + return 0; + } +#endif + if (! fname) { + slbuf1[ len] = PATH_DELIM; /* Append PATH_DELIM */ + slbuf1[ ++len] = EOS; + } +#if SYS_FAMILY == SYS_UNIX + /* Dereference symbolic linked directory or file, if any */ + slbuf1[ len] = EOS; /* Truncate PATH_DELIM and 'fname' part, if any */ + slbuf2[ 0] = EOS; + if (*dir && ! fname) { /* Registering include directory */ + /* Symbolic link check of directories are required */ + deref_syml( slbuf1, slbuf2, slbuf1); + } else if (fname) { /* Regular file */ + len = ACE_OS::strlen( slbuf1); + ACE_OS::strcat( slbuf1, fname); + deref_syml( slbuf1, slbuf2, slbuf1 + len); + /* Symbolic link check of directory */ + if ((len = ACE_OS::readlink( slbuf1, slbuf2, PATHMAX)) > 0) { + /* Dereference symbolic linked file (not directory) */ + *(slbuf2 + len) = EOS; + cp1 = slbuf1; + if (slbuf2[ 0] != PATH_DELIM) { /* Relative path */ + cp2 = ACE_OS::strrchr( slbuf1, PATH_DELIM); + if (cp2) /* Append to the source directory */ + cp1 = cp2 + 1; + } + ACE_OS::strcpy( cp1, slbuf2); + } + } + if (inf) { + if (slbuf2[ 0]) + mcpp_fprintf( DBG, "Dereferenced \"%s%s\" to \"%s\"\n" + , dir, fname ? fname : null, slbuf1); + } +#endif + len = ACE_OS::strlen( slbuf1); + start = norm_name = (char *)ACE_OS::malloc( len + 1); /* Need a new buffer */ + ACE_OS::strcpy( norm_name, slbuf1); +#if SYS_FAMILY == SYS_WIN + bsl2sl( norm_name); +#endif +#if SPECIAL_PATH_DELIM /* ':' ? */ + for (cp1 = norm_name; *cp1 != EOS; cp1++) { + if (*cp1 == PATH_DELIM) + *cp1 = '/'; + } +#endif + cp1 = norm_name; + +#if SYSTEM == SYS_CYGWIN + /* Convert to "/cygdirve/x/dir" style of absolute path-list */ + if (len >= 8 && (memcmp( cp1, "/usr/bin", 8) == 0 + || memcmp( cp1, "/usr/lib", 8) == 0)) { + memmove( cp1, cp1 + 4, len - 4 + 1); /* Remove "/usr" */ + len -= 4; + } + if (*cp1 == '/' && (len < 10 || memcmp( cp1, cygdrive, 10) != 0)) { + /* /dir, not /cygdrive/ */ + if (! root_dir_len) { /* Should be initialized */ + /* Convert "X:\DIR-list" to "/cygdrive/x/dir-list" */ + root_dir = ACE_OS::malloc( ACE_OS::strlen( CYGWIN_ROOT_DIRECTORY) + 1); + ACE_OS::strcpy( root_dir, CYGWIN_ROOT_DIRECTORY); + *(root_dir + 1) = *root_dir; /* "x:/" to " x/" */ + cp1 = ACE_OS::malloc( ACE_OS::strlen( cygdrive) + ACE_OS::strlen( root_dir)); + ACE_OS::strcpy( cp1, cygdrive); + ACE_OS::strcat( cp1, root_dir + 1); + ACE_OS::free( root_dir); + root_dir = cp1; + root_dir_len = ACE_OS::strlen( root_dir); + } + cp1 = ACE_OS::malloc( root_dir_len + len + 1); + ACE_OS::strcpy( cp1, root_dir); + ACE_OS::strcat( cp1, norm_name); /* Convert to absolute path */ + ACE_OS::free( norm_name); + norm_name = start = cp1; + len += root_dir_len; + } +#endif + +#if SYSTEM == SYS_MINGW + /* Handle the mess of MinGW's path-list */ + /* Convert to "x:/dir" style of absolute path-list */ + if (*cp1 == PATH_DELIM && isalpha( *(cp1 + 1)) + && *(cp1 + 2) == PATH_DELIM) { /* /c/, /d/, etc*/ + *cp1 = *(cp1 + 1); + *(cp1 + 1) = ':'; /* Convert to c:/, d:/, etc */ + } else if (memcmp( cp1, "/mingw", 6) == 0) { + if (! mingw_dir_len) { /* Should be initialized */ + mingw_dir_len = ACE_OS::strlen( MINGW_DIRECTORY); + mingw_dir = ACE_OS::malloc( mingw_dir_len + 1); + ACE_OS::strcpy( mingw_dir, MINGW_DIRECTORY); + } + cp1 = ACE_OS::malloc( mingw_dir_len + len + 1); + ACE_OS::strcpy( cp1, mingw_dir); + ACE_OS::strcat( cp1, norm_name + 6); /* Convert to absolute path */ + ACE_OS::free( norm_name); + norm_name = start = cp1; + len += mingw_dir_len; + } else if (memcmp( cp1, "/usr", 4) == 0) { + memmove( cp1, cp1 + 4, len - 4 + 1); /* Remove "/usr" */ + len -= 4; + } + if (*cp1 == '/') { /* /dir or / */ + if (! root_dir_len) { /* Should be initialized */ + root_dir_len = ACE_OS::strlen( MSYS_ROOT_DIRECTORY); + root_dir = ACE_OS::malloc( root_dir_len + 1); + ACE_OS::strcpy( root_dir, MSYS_ROOT_DIRECTORY); + } + cp1 = ACE_OS::malloc( root_dir_len + len + 1); + ACE_OS::strcpy( cp1, root_dir); + ACE_OS::strcat( cp1, norm_name); /* Convert to absolute path */ + ACE_OS::free( norm_name); + norm_name = start = cp1; + len += root_dir_len; + } +#endif + +#if SYS_FAMILY == SYS_WIN + if (*(cp1 + 1) == ':') + start = cp1 += 2; /* Next to the drive letter */ + start_pos = 2; +#endif + if (len == 1 && *norm_name == '/') /* Only "/" */ + return norm_name; + + if (ACE_OS::strncmp( cp1, "./", 2) == 0) /* Remove beginning "./" */ + ACE_OS::memmove( cp1, cp1 + 2, ACE_OS::strlen( cp1 + 2) + 1); /* +1 for EOS */ + if (*start != '/') { /* Relative path to current directory */ + /* Make absolute path */ + abs_path = (char *)ACE_OS::malloc( len + ACE_OS::strlen( cur_work_dir) + 1); + cp1 = mcpp_stpcpy( abs_path, cur_work_dir); + ACE_OS::strcpy( cp1, start); + ACE_OS::free( norm_name); + norm_name = abs_path; + start = cp1 = norm_name + start_pos; + } + + while ((cp1 = ACE_OS::strstr( cp1, "/./")) != 0) + ACE_OS::memmove( cp1, cp1 + 2, ACE_OS::strlen( cp1 + 2) + 1); + /* Remove "/." of "/./" */ + cp1 = start; + /* Remove redundant "foo/../" */ + while ((cp1 = ACE_OS::strstr( cp1, "/../")) != 0) { + *cp1 = EOS; + if ((cp2 = ACE_OS::strrchr( start, '/')) != 0) { + if (*(cp1 - 1) != '.') { + ACE_OS::memmove( cp2 + 1, cp1 + 4, ACE_OS::strlen( cp1 + 4) + 1); + /* Remove "foo/../" */ + cp1 = cp2; + } else { /* Impossible */ + break; + } + } else { /* Impossible */ + break; + } + } + +#if SPECIAL_PATH_DELIM + for (cp1 = start; *cp1 != EOS; cp1++) { + if (*cp1 == '/') + *cp1 = PATH_DELIM; + } +#endif + if (inf) { + char debug_buf[ PATHMAX+1]; + ACE_OS::strcpy( debug_buf, dir); + ACE_OS::strcat( debug_buf, fname ? fname : null); +#if SYS_FAMILY == SYS_WIN + bsl2sl( debug_buf); +#endif + if (! str_eq( debug_buf, norm_name)) + mcpp_fprintf( DBG, "Normalized the path \"%s\" to \"%s\"\n" + , debug_buf, norm_name); + } + + return norm_name; +} + +#if SYS_FAMILY == SYS_UNIX + +static void deref_syml( + char * slbuf1, /* Original path-list */ + char * slbuf2, /* Working buffer */ + char * chk_start /* Pointer into slbuf1 */ + ) +/* Dereference symbolic linked directory */ +{ + char * cp2; + int len; /* Should be int, not size_t */ + + while ((chk_start = ACE_OS::strchr( chk_start, PATH_DELIM)) != 0) { + *chk_start = EOS; + if ((len = ACE_OS::readlink( slbuf1, slbuf2, PATHMAX)) > 0) { + /* Dereference symbolic linked directory */ + cp2 = ACE_OS::strrchr( slbuf1, PATH_DELIM); /* Previous delimiter */ + *chk_start = PATH_DELIM; + ACE_OS::strcpy( slbuf2 + len, chk_start); + if (slbuf2[ 0] == PATH_DELIM) { /* Absolute path */ + ACE_OS::strcpy( slbuf1, slbuf2); + chk_start = slbuf1 + len + 1; + } else { + if (cp2) + chk_start = cp2 + 1; + else + chk_start = slbuf1; + ACE_OS::strcpy( chk_start, slbuf2); /* Rewrite the path */ + chk_start += len; + } + } else { + *chk_start++ = PATH_DELIM; + } + } +} +#endif + +#if COMPILER == GNUC + +static void init_gcc_macro( void) +/* + * Predefine GCC macros. + * This routine should be called after opening output file in order to putout + * macro informations by -K option into the file. + * Also this routine should be called before undef_macros() in order to + * permit undefining a macro by -U option. + */ +{ + char fname[ BUFSIZ]; + char lbuf[ BUFSIZ]; + char * include_dir; /* The version-specific include directory */ + char * tmp; + FILE * fp; + DEFBUF * defp; + const char * cp; + char * tp; + int i; + + if (nflag) /* -undef option */ + goto undef_special; + + tmp = ACE_OS::malloc( ACE_OS::strlen( INC_DIR) + ACE_OS::strlen( "/mingw/mcpp-gcc-") + + ACE_OS::strlen( arch) + 1); +#if SYSTEM == SYS_CYGWIN + if (no_cygwin) { + ACE_OS::sprintf( tmp, "%s/mingw/mcpp-gcc-%s", INC_DIR, arch); + } else { + ACE_OS::sprintf( tmp, "%s/mcpp-gcc-%s", INC_DIR, arch); + } +#else + ACE_OS::sprintf( tmp, "%s/mcpp-gcc-%s", INC_DIR, arch); +#endif + include_dir = norm_path( tmp, 0, TRUE, FALSE); + ACE_OS::free( tmp); + + for (i = 0; i <= 1; i++) { + int nargs; + + if ((mcpp_mode == POST_STD || ansi) && i == 0) + continue; /* POST_STD or __STRICT_ANSI__ does not */ + /* predefine non-conforming macros */ + /* The predefined macro file */ + cp = i ? "std" : "old"; + ACE_OS::sprintf( fname, "%sg%s%d%d_predef_%s.h" + , include_dir, cplus_val ? "xx" : "cc" + , gcc_maj_ver, gcc_min_ver, cp); + /* Note that norm_path() append a PATH_DELIM. */ + if ((fp = fopen( fname, "r")) == 0) { + mcpp_fprintf( ERR, "The mode for %s has not been installed.\n" + , arch); + longjmp( error_exit, -1); + } + nargs = i ? 0 : DEF_NOARGS_PREDEF_OLD; + /* g*_predef_std.h has DEF_NOARGS_PREDEF or non-negative args */ + /* while g*_predef_old.h has only DEF_NOARGS_PREDEF_OLD args */ + while (fgets( lbuf, BUFSIZ, fp) != 0) { + unget_string( lbuf, "gcc_predefine"); + if (skip_ws() == '#' + && scan_token( skip_ws(), (tp = work_buf, &tp), work_end) + == NAM + && str_eq( work_buf, "define")) { + defp = do_define( TRUE, nargs); /* Ignore re-definition */ + } + skip_nl(); + } + } + ACE_OS::free( include_dir); + + undef_special: + if (look_id( "__OPTIMIZE__")) /* -O option is specified */ + undefine( "__NO_INLINE__"); +} + +static void chk_env( void) +/* + * Check the environment variables to specify output of dependency lines. + */ +{ + char * env; + char * cp; + + /* Output of dependency lines */ + if ((env = ACE_OS::getenv( "DEPENDENCIES_OUTPUT")) == 0) { + if ((env = ACE_OS::getenv( "SUNPRO_DEPENDENCIES")) == 0) + return; + else + mkdep |= MD_SYSHEADER; + } + mkdep |= MD_MKDEP; + if ((cp = ACE_OS::strchr( env, ' ')) != 0) { + *cp++ = EOS; + while (*cp == ' ') + cp++; + } + if (! mkdep_fp) /* Command line option precedes */ + mkdep_fp = fopen( env, "a"); + if (! mkdep_target) + mkdep_target = cp; +} + +#elif COMPILER == MSC + +static void init_msc_macro( void) +/* + * Define a few MSC-specific predefined macros. + */ +{ + DEFBUF * defp; + int i; + + defp = look_id( "_MSC_VER"); + i = atoi( defp->repl); + if (i >= 1400) { /* _MSC_VER >= 1400 */ + look_and_install( "_MT", DEF_NOARGS_PREDEF, null, "1"); + if (cplus_val && ! wchar_t_modified) { + /* -Zc:wchar_t- was not specified */ + look_and_install( "_NATIVE_WCHAR_T_DEFINED", DEF_NOARGS_PREDEF + , null, "1"); + look_and_install( "_WCHAR_T_DEFINED", DEF_NOARGS_PREDEF, null + , "1"); + } + } +} + +#endif + +static void def_macros( void) +/* + * Define macros specified by -D option. + * This routine should be called before undef_macros(). + */ +{ + size_t i(0); + + for (i = 0; i < def_cnt; i++) + { + def_a_macro( 'D', def_list[ i]); + } + +} + +static void undef_macros( void) +/* + * Undefine macros specified by -U option. + * This routine should be called after init_predefine(). + */ +{ + const char * name; + size_t i; + + for (i = 0; i < undef_cnt; i++) { + name = undef_list[ i]; + if (look_id( name) != 0) + undefine( name); + else if (warn_level & 8) + mcpp_fprintf( ERR, "\"%s\" wasn't defined\n", name); + } +} + +void put_depend( + const char * filename + ) +/* + * Append a header name to the source file dependency line. + */ +{ +#define MAX_OUT_LEN 76 /* Maximum length of output line */ +#define MKDEP_INITLEN (MKDEP_INIT * 0x100) +#define MKDEP_MAX (MKDEP_INIT * 0x10) +#define MKDEP_MAXLEN (MKDEP_INITLEN * 0x10) + + static char * output = 0; /* File names */ + static size_t * pos = 0; /* Offset to filenames */ + static unsigned int pos_num; /* Index of pos[] */ + static char * out_p; /* Pointer to output[] */ + static size_t mkdep_len; /* Size of output[] */ + static size_t pos_max; /* Size of pos[] */ + static FILE * fp; /* Path to output dependency line */ + static size_t llen; /* Length of current physical output line */ + size_t * pos_p; /* Index into pos[] */ + size_t fnamlen; /* Length of filename */ + + if (fp == 0) { /* Main source file. Have to initialize. */ +#ifdef MCPP_LIB + if (output != 0) { + ACE_OS::free( output); + ACE_OS::free( pos); + } +#endif + output = (char *) ACE_OS::malloc( mkdep_len = MKDEP_INITLEN); + pos = (size_t *) ACE_OS::malloc( (pos_max = MKDEP_INIT) * sizeof (size_t)); + out_p = md_init( filename, output); + fp = mkdep_fp; + llen = ACE_OS::strlen( output); + pos_num = 0; /* Initialize for MCPP_LIB build */ + } else if (filename == 0) { /* End of input */ + out_p = mcpp_stpcpy( out_p, "\n\n"); + if (mkdep & MD_PHONY) { + /* Output the phony target line for each recorded header files. */ + char * cp; + int c; + + if (ACE_OS::strlen( output) * 2 + (pos_num * 2) >= MKDEP_MAXLEN) { + cerror( "Too long dependency line" /* _E_ */ + , 0, 0L, 0); + if (fp == fp_out) + mcpp_fputs( output, OUT); + else + ACE_OS::fputs( output, fp); + return; + } else if (ACE_OS::strlen( output) * 2 + (pos_num * 2) >= mkdep_len) { + /* Enlarge the buffer */ + size_t len = out_p - output; + output = (char *) ACE_OS::realloc( output, mkdep_len *= 2); + out_p = output + len; + } + pos_num--; + for (pos_p = &pos[ 0]; pos_p <= &pos[ pos_num]; pos_p++) { + if (pos_p == &pos[ pos_num]) { /* End of output */ + for (cp = output + *pos_p; *cp != '\n'; cp++) + ; + c = '\n'; /* Append newline */ + } else { + cp = output + *(pos_p + 1) - 1; + while( *cp == ' ' || *cp == '\\' || *cp == '\n') + cp--; /* Remove trailing spaces */ + c = *(++cp); + } + *cp = EOS; + out_p = mcpp_stpcpy( out_p, output + *pos_p); + out_p = mcpp_stpcpy( out_p, ":\n\n"); + *cp = c; + } + } + if (fp == fp_out) { /* To the same path with normal preprocessing */ + mcpp_fputs( output, OUT); + } else { /* To the file specified by -MF, -MD, -MMD options */ + ACE_OS::fputs( output, fp); + ACE_OS::fclose( fp); + } + fp = 0; /* Clear for the next call in MCPP_LIB build */ + return; + } + + fnamlen = ACE_OS::strlen( filename); + /* Check the recorded filename */ + for (pos_p = pos; pos_p < &pos[ pos_num]; pos_p++) { + if (ACE_OS::memcmp( output + *pos_p, filename, fnamlen) == 0) + return; /* Already recorded filename */ + } + /* Any new header. Append its name to output. */ + if (llen + fnamlen > MAX_OUT_LEN) { /* Line is long */ + out_p = mcpp_stpcpy( out_p, " \\\n "); /* Fold it */ + llen = 1; + } + llen += fnamlen + 1; + if (pos_num >= MKDEP_MAX + || out_p + fnamlen + 1 >= output + MKDEP_MAXLEN) + cfatal( "Too long dependency line: %s", output, 0L, 0); + /* Need to enlarge the buffer */ + if (pos_num >= pos_max) { + pos = (size_t *) ACE_OS::realloc( (char *) pos + , (pos_max *= 2) * sizeof (size_t *)); + } + if (output + mkdep_len <= out_p + fnamlen + 1) { + size_t len = out_p - output; + output = (char *) ACE_OS::realloc( output, mkdep_len *= 2); + out_p = output + len; + } + *out_p++ = ' '; + pos[ pos_num++] = out_p - output; /* Remember the offset */ + /* Don't use pointer, since 'output' may be reallocated later. */ + out_p = mcpp_stpcpy( out_p, filename); +} + +static char * md_init( + const char * filename, /* The source file name */ + char * output /* Output to dependency file */ + ) +/* + * Initialize output file and target. + */ +{ + char prefix[ PATHMAX]; + char * cp = 0; + size_t len; + char * out_p; + const char * target = filename; + const char * cp0; + + if (! mkdep_target || ! mkdep_fp) { /* Make target name */ +#ifdef PATH_DELIM + if ((cp0 = ACE_OS::strrchr( target, PATH_DELIM)) != 0) + target = cp0 + 1; +#endif + if ((cp0 = ACE_OS::strrchr( target, '.')) == 0) + len = ACE_OS::strlen( target); + else + len = (size_t) (cp0 - target); + ACE_OS::memcpy( prefix, target, len); + cp = prefix + len; + *cp++ = '.'; + } + + if (! mkdep_fp) { /* Unless already opened by -MF, -MD, -MMD options */ + if (mkdep & MD_FILE) { + ACE_OS::strcpy( cp, "d"); + mkdep_fp = ACE_OS::fopen( prefix, "w"); + } else { + mkdep_fp = fp_out; /* Output dependency line to normal output */ + no_output++; /* Without normal output */ + } + } + + if (mkdep_target) { /* -MT or -MQ option is specified */ + if (mkdep & MD_QUOTE) { /* 'Quote' $, \t and space */ + out_p = md_quote( output); + } else { + out_p = mcpp_stpcpy( output, mkdep_target); + } + } else { + ACE_OS::strcpy( cp, OBJEXT); + out_p = mcpp_stpcpy( output, prefix); + } + + *out_p++ = ':'; + *out_p = EOS; + return out_p; +} + +static char * md_quote( + char * output + ) +/* + * 'Quote' $, tab and space. + * This function was written referring to GCC V.3.2 source. + */ +{ + char * p; + char * q; + + for (p = mkdep_target; *p; p++, output++) { + switch (*p) { + case ' ': + case '\t': + /* GNU-make treats backslash-space sequence peculiarly */ + for (q = p - 1; mkdep_target <= q && *q == '\\'; q--) + *output++ = '\\'; + *output++ = '\\'; + break; + case '$': + *output++ = '$'; + break; + default: + break; + } + *output = *p; + } + *output = EOS; + return output; +} + +static const char * toolong_fname = + "Too long header name \"%s%.0ld%s\""; /* _F_ */ +static const char * excess_token = + "Excessive token sequence \"%s\""; /* _E_, _W1_ */ + +int do_include( + int next /* TRUE if the directive is #include_next */ + ) +/* + * Process the #include line. + * There are three variations: + * #include "file" search somewhere relative to the + * current (or source) directory, if not + * found, treat as #include <file>. + * #include <file> Search in an implementation-dependent + * list of places. + * #include macro-call Expand the macro call, it must be one of + * "file" or <file>, process as such. + * On success : return TRUE; + * On failure of syntax : return FALSE; + * On failure of file opening : return FALSE. + * do_include() always absorbs the line (including the <newline>). + */ +{ + const char * const no_name = "No header name"; /* _E_ */ + char header[ PATHMAX + 16]; + int token_type; + char * fname; + char * filename; + int delim; /* " or <, > */ + + if ((delim = skip_ws()) == '\n') { /* No argument */ + cerror( no_name, 0, 0L, 0); + return FALSE; + } + fname = infile->bptr - 1; /* Current token for diagnosis */ + + if (standard && (char_type[ delim] & LET)) { /* Maybe macro */ + int c; + char *hp; + + hp = header; + *hp = EOS; + c = delim; + while (get_unexpandable( c, FALSE) != NO_TOKEN) { + /* Expand any macros in the line */ + if (header + PATHMAX < hp + (int) (workp - work_buf)) + cfatal( toolong_fname, header, 0L, work_buf); + hp = mcpp_stpcpy( hp, work_buf); + while (char_type[ c = get_ch()] & HSP) + *hp++ = c; + } + *hp = EOS; /* Ensure to terminate */ + if (macro_line == MACRO_ERROR) /* Unterminated macro */ + return FALSE; /* already diagnosed. */ + unget_string( header, 0); /* To re-read */ + delim = skip_ws(); + if (delim == '\n') { + cerror( no_name, 0, 0L, 0); /* Expanded to */ + return FALSE; /* 0 token. */ + } + } + + token_type = scan_token( delim, (workp = work_buf, &workp) + , work_buf + PATHMAX); + if (token_type == STR) /* String literal form */ + goto found_name; + else if (token_type == OPE && openum == OP_LT) /* '<' */ + workp = scan_quote( delim, work_buf, work_buf + PATHMAX, TRUE); + /* Re-construct or diagnose */ + else /* Any other token in- */ + goto not_header; /* cluding <=, <<, <% */ + + if (workp == 0) /* Missing closing '>' */ + goto syntax_error; + + found_name: + *--workp = EOS; /* Remove the closing and */ + fname = save_string( &work_buf[ 1]); /* the starting delimiter. */ + + if (skip_ws() != '\n') { + if (standard) { + cerror( excess_token, infile->bptr-1, 0L, 0); + skip_nl(); + goto error; + } else if (mcpp_mode == OLD_PREP) { + skip_nl(); + } else { + if (warn_level & 1) + cwarn( excess_token, infile->bptr-1, 0L, 0); + skip_nl(); + } + } + +#if SYS_FAMILY == SYS_WIN + bsl2sl( fname); +#endif + filename = fname; +#if NO_DIR /* Unofficial feature */ + if (no_dir) { /* Strip directory components */ + char src_dir[ PATHMAX] = { EOS, }; + if (has_directory( fname, src_dir)) + filename = fname + ACE_OS::strlen( src_dir); + delim = '"'; /* Even a system header is handled as a local one */ + } +#endif + if (open_include( filename, (delim == '"'), next)) { + /* 'fname' should not be ACE_OS::free()ed, it is used as file-> */ + /* real_fname and has been registered into fnamelist[] */ + return TRUE; + } + + cerror( "Can't open include file \"%s\"", filename, 0L, 0); /* _E_ */ + error: + ACE_OS::free( fname); + return FALSE; + + not_header: + cerror( "Not a header name \"%s\"", fname, 0L, 0); /* _E_ */ + syntax_error: + skip_nl(); + return FALSE; +} + +static int open_include( + char * filename, /* File name to include */ + int searchlocal, /* TRUE if #include "file" */ + int next /* TRUE if #include_next */ + ) +/* + * Open an include file. This routine is only called from do_include() above. + * It searches the list of directories via search_dir() and opens the file + * via open_file(), linking it into the list of active files. + * Returns TRUE if the file was opened, FALSE if it fails. + */ +{ + char src_dir[ PATHMAX] = { EOS, }; /* Directory part of includer */ + int full_path; /* Filename is full-path-list */ + int has_dir = FALSE; /* Includer has directory part */ + int has_dir_src = FALSE; + int has_dir_fname = FALSE; + + full_path = is_full_path( filename); + + if (!full_path && searchlocal && (search_rule & SOURCE)) { + has_dir_src = has_directory( infile->src_dir, src_dir); + has_dir_fname = has_directory( infile->real_fname + , src_dir + ACE_OS::strlen( src_dir)); + /* Get directory part of the parent file of the file to include.*/ + /* Note that infile->dirp of main input file is set to "" and */ + /* remains the same even if -include options are processed. */ + has_dir = has_dir_src || has_dir_fname + || (**(infile->dirp) != EOS); + } + if (mcpp_debug & PATH) + mcpp_fprintf( DBG, "filename: %s\n", filename); + +#if COMPILER == GNUC + if (! full_path) { + if (i_split /* -I- option is specified */ + || next) /* or #include_next */ + goto search_dirs; + } +#endif + + if ((searchlocal && ((search_rule & CURRENT) || !has_dir)) || full_path) { + /* + * Look in local directory first. + * Try to open filename relative to the "current directory". + */ + if (open_file( &null, 0, filename, searchlocal && !full_path + , FALSE, FALSE)) + return TRUE; + if (full_path) + return FALSE; + } + + if (searchlocal && (search_rule & SOURCE) && has_dir) { + /* + * Look in local directory of source file. + * Try to open filename relative to the "source directory". + */ + if (open_file( infile->dirp, src_dir, filename, TRUE, FALSE, FALSE)) + return TRUE; + } + +#if COMPILER == MSC + if (searchlocal) { + /* Visual C searches ancestor source's directory, too. */ + FILEINFO * file = infile; + while ((file = file->parent) != 0) { + /* Search each parent includer's directory */ + if (open_file( file->dirp, src_dir, filename, TRUE, FALSE, FALSE)) + return TRUE; + } + } +#endif +#if COMPILER == GNUC + search_dirs: + if (searchlocal) { + /* Search the directories specified by -iquote option, if any. */ + const char ** qdir; + for (qdir = quote_dir; qdir < quote_dir_end; qdir++) { + if (open_file( qdir, 0, filename, FALSE, FALSE, FALSE)) + return TRUE; + } + } +#endif + /* Search the include directories */ + if (search_dir( filename, searchlocal, next)) + return TRUE; + + return FALSE; +} + +static int has_directory( + const char * source, /* Filename to examine */ + char * directory /* Put directory stuff here */ + ) +/* + * If a directory is found in the 'source' filename string (i.e. "includer"), + * the directory part of the string is copied to 'directory' and + * has_directory() returns TRUE. + * Else, nothing is copied and it returns FALSE. + */ +{ + const char * sp; + size_t len; + + if (! source) + return FALSE; + if ((sp = ACE_OS::strrchr( source, PATH_DELIM)) == 0) { + return FALSE; + } else { + len = (size_t)(sp - source) + 1; /* With path-delimiter */ + ACE_OS::memcpy( directory, source, len); + directory[ len] = EOS; + return TRUE; + } +} + +static int is_full_path( + const char * path + ) +/* + * Check whether the path is a full (absolute) path list or not. + */ +{ + if (! path) + return FALSE; +#if SYS_FAMILY == SYS_UNIX + if (path[0] == PATH_DELIM) +#elif SYS_FAMILY == SYS_WIN + if ((path[1] == ':' && path[2] == PATH_DELIM) /* "C:/path" */ + || path[0] == PATH_DELIM) /* Root dir of current drive */ +#elif 1 + /* For other systems you should write code here. */ + if (path[0] == PATH_DELIM) +#endif + return TRUE; + else + return FALSE; +} + +static int search_dir( + char * filename, /* File name to include */ + int /*searchlocal*/, /* #include "header.h" */ + int /*next*/ /* TRUE if #include_next */ + ) +/* + * Look in any directories specified by -I command line arguments, + * specified by environment variable, then in the builtin search list. + */ +{ + const char ** incptr; /* -> inlcude directory */ + + incptr = incdir; +#if COMPILER == GNUC + if (next && **inc_dirp != EOS) + incptr = inc_dirp + 1; + /* In case of include_next search after the includer's directory */ +#endif + + for ( ; incptr < incend; incptr++) { + if (ACE_OS::strlen( *incptr) + ACE_OS::strlen( filename) >= PATHMAX) + cfatal( toolong_fname, *incptr, 0L, filename); /* _F_ */ +#if SYSTEM == SYS_MAC + if (incptr == to_search_framework && ! searchlocal) { + /* Now search the framework dirs */ + if (search_framework( filename)) { /* Found */ + if (in_import) /* "#import"ed file is once only */ + do_once( infile->full_fname); + return TRUE; + } + /* Else continue to search incptr */ + } +#endif + if (open_file( incptr, 0, filename, FALSE, FALSE, FALSE)) + /* Now infile has been renewed */ + return TRUE; + } + + return FALSE; +} + +static int open_file( + const char ** dirp, /* Pointer to include directory */ + const char * src_dir, /* Source directory of includer */ + const char * filename, /* Filename (possibly has directory) */ + int /*local*/, /* #include "file" */ + int include_opt, /* Specified by -include option */ + int /*sys_frame*/ /* System framework header (for SYS_MAC)*/ + ) +/* + * Open a file, add it to the linked list of open files, close the includer + * if nessesary and truncate the includer's buffer. + * This is called from open_include() and at_start(). + */ +{ + char dir_fname[ PATHMAX] = { EOS, }; +#if HOST_COMPILER == BORLANDC + /* Borland's ACE_OS::fopen() does not set errno. */ + static int max_open = FOPEN_MAX - 5; +#else + static int max_open; +#endif + int len; + FILEINFO * file = infile; + FILE * fp; + char * fullname; + const char * fname; + + errno = 0; /* Clear errno possibly set by path searching */ +#if SYSTEM == SYS_MAC && COMPILER == GNUC + if (ACE_OS::strlen( *dirp) > 5 + && str_case_eq( *dirp + ACE_OS::strlen( *dirp) - 5, ".hmap")) { + /* Search header map file for a header */ + if (! search_header_map( *dirp, filename, dir_fname)) + return 0; + fname = dir_fname; /* Found a path-list */ + dirp = &null; + goto search; + } else +#endif + { + if (mcpp_debug & PATH) + mcpp_fprintf( DBG, "Searching %s%s%s\n", *dirp + , src_dir ? src_dir : null, filename); + } + /* src_dir is usually 0. This is specified to */ + /* search the source directory of the includer. */ + if (src_dir && *src_dir != EOS) { + ACE_OS::strcpy( dir_fname, src_dir); + ACE_OS::strcat( dir_fname, filename); + fname = dir_fname; + } else { + fname = filename; + } + //search: + fullname = norm_path( *dirp, fname, TRUE, FALSE); + /* Convert to absolute path */ + if (! fullname) /* Non-existent or directory */ + return FALSE; + if (standard && included( fullname)) /* Once included */ + goto true_label; + + if ((max_open != 0 && max_open <= include_nest) + /* Exceed the known limit of open files */ + || ((fp = ACE_OS::fopen( fullname, "r")) == 0 && errno == EMFILE)) { + /* Reached the limit for the first time */ + if (mcpp_debug & PATH) { +#if HOST_COMPILER == BORLANDC + if (include_nest == FOPEN_MAX - 5) +#else + if (max_open == 0) +#endif + mcpp_fprintf( DBG, + "#include nest reached at the maximum of system: %d, returned errno: %d\n" + , include_nest, errno); + } + /* + * Table of open files is full. + * Remember the file position and close the includer. + * The state will be restored by get_line() on end of the included. + */ + file->pos = ACE_OS::ftell( file->fp); + ACE_OS::fclose( file->fp); + /* In case of failure, re-open the includer */ + if ((fp = ACE_OS::fopen( fullname, "r")) == 0) { + file->fp = ACE_OS::fopen( cur_fullname, "r"); + ACE_OS::fseek( file->fp, file->pos, SEEK_SET); + goto false_label; + } + if (max_open == 0) /* Remember the limit of the system */ + max_open = include_nest; + } else if (fp == 0) /* No read permission */ + goto false_label; + /* Truncate buffer of the includer to save memory */ + len = (int) (file->bptr - file->buffer); + if (len) { + file->buffer = (char *) ACE_OS::realloc( file->buffer, len + 1); + file->bptr = file->buffer + len; + } + + if (! include_opt) + sharp( 0, 0); /* Print includer's line num and fname */ + add_file( fp, src_dir, filename, fullname, include_opt); + /* Add file-info to the linked list. 'infile' has been just renewed */ + /* + * Remember the directory for #include_next. + * Note: inc_dirp is restored to the parent includer's directory + * by get_ch() when the current includer is finished. + */ + infile->dirp = inc_dirp = dirp; +#if 0 /* This part is only for debugging */ + chk_dirp( dirp); +#endif +#if COMPILER == GNUC + if ((**dirp != EOS && sys_dirp <= dirp && dirp <= incend) +#if SYSTEM == SYS_MAC + || sys_frame +#endif + ) + infile->sys_header = TRUE; /* Found in a system header dir */ + else + infile->sys_header = FALSE; +#endif + cur_fullname = fullname; + + if (option_flags.z) { + no_output++; /* Don't output the included file */ + if (include_nest == 2) + mcpp_fprintf( OUT, "#include \"%s\"\n", fullname); + /* Output #include line instead, if it is in main source file */ + } else if (! include_opt) { /* Do not sharp() on -include */ + src_line = 1; /* Working on line 1 now */ + sharp( 0, 1); /* Print out the included file name */ + } + src_line = 0; /* To read the first line */ + + if (mkdep && ((mkdep & MD_SYSHEADER) || ! infile->sys_header)) + put_depend( fullname); /* Output dependency line */ + + true_label: + return TRUE; + false_label: + ACE_OS::free( fullname); + return FALSE; +} + +void add_file( + FILE * fp, /* Open file pointer */ + const char * ,/*src_dir*/ /* Directory of source */ + const char * filename, /* Name of the file */ + const char * fullname, /* Full path list */ + int include_opt /* File specified by -include option */ + ) +/* + * Initialize tables for this open file. This is called from open_file() + * (for #include files), and from the entry to MCPP to open the main input + * file. It calls a common routine get_file() to build the FILEINFO + * structure which is used to read characters. + */ +{ + FILEINFO * file; + const char * too_many_include_nest = + "More than %.0s%ld nesting of #include"; /* _F_ _W4_ */ + + filename = set_fname( filename); /* Search or append to fnamelist[] */ + fullname = set_fname( fullname); /* Search or append to fnamelist[] */ + file = get_file( filename, 0 /*src_dir*/, fullname, (size_t) NBUFF, include_opt); + + /* file == infile */ + file->fp = fp; /* Better remember FILE * */ + cur_fname = fullname; + + if (include_nest >= INCLUDE_NEST) /* Probably recursive #include */ + cfatal( too_many_include_nest, 0, (long) INCLUDE_NEST, 0); + if (standard && (warn_level & 4) + && include_nest == std_limits.inc_nest + 1) + cwarn( too_many_include_nest, 0, (long) std_limits.inc_nest, 0); + include_nest++; +} + +static const char * set_fname( + const char * filename + ) +/* + * Register the source filename to fnamelist[]. + * Search fnamelist[] for filename or append filename to fnamelist[]. + * Returns the pointer. + * file->real_fname and file->full_fname points into fnamelist[]. + */ +{ + INC_LIST * fnamep; + size_t fnamelen; + + if (fnamelist == 0) { /* Should be initialized */ + max_fnamelist = INIT_NUM_FNAMELIST; + fnamelist = (INC_LIST *) ACE_OS::malloc( sizeof (INC_LIST) * max_fnamelist); + fname_end = &fnamelist[ 0]; + } else if (fname_end - fnamelist >= max_fnamelist) { + /* Buffer full: double the elements */ + fnamelist = (INC_LIST *) ACE_OS::realloc( reinterpret_cast<char *> (fnamelist), sizeof (INC_LIST) * max_fnamelist * 2); + fname_end = &fnamelist[ max_fnamelist]; + max_fnamelist *= 2; + } + + /* Register the filename in fnamelist[] */ + fnamelen = ACE_OS::strlen( filename); + for (fnamep = fnamelist; fnamep < fname_end; fnamep++) { + if (fnamep->len == fnamelen && str_case_eq( fnamep->name, filename)) + { + return filename; /* Already registered */ + } + } + fname_end->name = (char *) ACE_OS::malloc( fnamelen + 1); + filename = ACE_OS::strcpy( fname_end->name, filename); + /* Global pointer for get_file() */ + fname_end->len = fnamelen; + fname_end++; + + return filename; +} + +#if SYSTEM == SYS_MAC +#if COMPILER == GNUC + +/* Routines to search "header map" file of Xcode / Apple-GCC. */ +/* search_header_map() and hmap_hash() were written referring to */ +/* c-incpath.c of Apple-GCC-4.0.1. */ + +static char * search_header_map( + const char * hmap_file, /* Header map file */ + const char * filename, /* Filename to search */ + char * pathlist /* Buffer for a found pathlist */ + ) +/* + * Search a table in "header map" file for a header. + */ +{ + struct stat stat_buf; + FILE * fp; + size_t fsize; + const char * contents; + struct hmap_header_map * hmap; + struct hmap_bucket * buckets; + const char * strings; + uint32 mask; + uint32 key_offs; + uint32 i; + + stat( hmap_file, &stat_buf); /* Get size of the file */ + fsize = stat_buf.st_size; + contents = ACE_OS::malloc( fsize + 1); + fp = ACE_OS::fopen( hmap_file, "r"); + fread( contents, fsize, 1, fp); /* Read whole of the file at once */ + hmap = (struct hmap_header_map *) contents; + + strings = ((const char *) hmap) + hmap->strings_offset; + buckets = hmap->buckets; + mask = hmap->capacity - 1; + i = hmap_hash( filename) & mask; + while ((key_offs = buckets[ i].key) != 0) { + if (str_case_eq( filename, strings + key_offs)) { + /* The names match. Make path-list. */ + char * cp = mcpp_stpcpy( pathlist, strings + buckets[ i].value.prefix); + ACE_OS::strcpy( cp, strings + buckets[ i].value.suffix); + break; + } + i = ++i & mask; + } + ACE_OS::free( contents); + return key_offs ? pathlist : 0; +} + +static unsigned hmap_hash( + const char * fname /* header name */ + ) +/* + * Get hash value for the fname. + */ +{ + const char * sp; + unsigned hash_code = 0; + + for (sp = fname; *sp; sp++) + hash_code += tolower( *sp & 0xFF) * 13; + return hash_code; +} +#endif /* COMPILER == GNUC */ + +static void init_framework( void) +/* + * Initialize framework[]. + */ +{ + char * framework_dir; + /* Some frameworks may have been already specified by -F option. */ + sys_framework = num_framework; /* These are system frameworks */ +#ifdef FRAMEWORK1 + framework_dir = norm_dir( FRAMEWORK1, TRUE); + if (framework_dir) + framework[ num_framework++] = framework_dir; +#endif +#ifdef FRAMEWORK2 + framework_dir = norm_dir( FRAMEWORK2, TRUE); + if (framework_dir) + framework[ num_framework++] = framework_dir; +#endif +#ifdef FRAMEWORK3 + framework_dir = norm_dir( FRAMEWORK3, TRUE); + if (framework_dir) + framework[ num_framework++] = framework_dir; +#endif + if (num_framework >= MAX_FRAMEWORK) { + mcpp_fputs( "Too many Framework directories.", ERR); + longjmp( error_exit, -1); + } +} + +static const char * dot_frame = ".framework"; + +static int search_framework( + char * filename + ) +/* + * Search "Framework" directories. + * 'frame/header.h' is converted to + * '/System/Library/Frameworks/frame.framework/Headers/header.h', + * '/System/Library/Frameworks/frame.framework/PrivateHeaders/header.h', + * and so on. + */ +{ + char fullname[ PATHMAX + 1]; + FILEINFO * file; + char * frame, * fname, * cp1, * cp2; + int sys_frame = FALSE; + int i; + + cp1 = cp2 = ACE_OS::strchr( filename, PATH_DELIM); + /* + * 'filename' should be <frame/header> format or sometimes + * <frame/dir/header>. + * e.g.: <Foundation/Foundation.h>, <CarbonCore/OSUtils.h> + * or <IOKit/pwr_mgt/IOPMLib.h>. + */ + if (! cp1) + return FALSE; + *cp1 = EOS; + frame = filename; + fname = cp1 + 1; + + /* Search framework[] directories */ + for (i = 0; i < num_framework; i++) { + cp1 = mcpp_stpcpy( fullname, framework[ i]); + /* 'fullname' e.g.: /System/Library/Frameworks/ */ + if (search_subdir( fullname, cp1, frame, fname, sys_framework <= i)) + return TRUE; + } + + /* + * Search subframework dirs searching its possible parent framework + * starting from current file's directory to its ancestors. + * Header file in subframework directories should be included only + * by its parent or sibling framework headers. + */ + for (i = sys_framework; i < num_framework; i++) { + size_t frame_len, fname_len; + frame_len = ACE_OS::strlen( framework[ i]); + fname_len = ACE_OS::strlen( infile->real_fname); + if (fname_len <= frame_len) + continue; + if (ACE_OS::memcmp( framework[ i], infile->real_fname, frame_len) == 0) { + sys_frame = TRUE; + break; + } + } + for (file = infile; file; file = file->parent) { + const char * dot; + size_t len; + + if (! file->fp) + continue; + dot = strstr( file->real_fname, dot_frame); + if (! dot) + continue; + len = dot - file->real_fname + ACE_OS::strlen( dot_frame) + 1; + ACE_OS::memcpy( fullname, file->real_fname, len); + cp1 = fullname + len; + cp1 = mcpp_stpcpy( cp1, "Frameworks/"); + /* 'fullname' e.g.: */ + /* /System/Library/Frameworks/Foundation.framework/Frameworks/ */ + if (search_subdir( fullname, cp1, frame, fname, sys_frame)) + return TRUE; + } + + *cp2 = PATH_DELIM; /* Restore original include file format */ + + return FALSE; +} + +static int search_subdir( + char * fullname, /* Buffer for path-list to open */ + char * cp, /* Latter half of 'fullname' */ + char * frame, /* 'frame' of <frame/header> */ + char * fname, /* 'header' of <frame/header> */ + /* or sometimes 'dir/header' of <frame/dir/header> */ + int sys_frame /* System framework header ? */ + ) +/* + * Make path-list and try to open. + */ +{ + static const char * subdir[] = { "Headers", "PrivateHeaders", 0}; + int j, n; + + cp += ACE_OS::sprintf( cp, "%s%s%c", frame, dot_frame, PATH_DELIM); + for (j = 0; subdir[ j] != 0; j++) { + n = ACE_OS::sprintf( cp, "%s%c%s", subdir[ j], PATH_DELIM, fname); + /* + * 'fullname' is for example: + * /System/Library/Frameworks/Foundation.framework/Headers/ + * Foundation.h, + * /System/Library/Frameworks/Foundation.framework/Frameworks/ + * CarbonCore.framework/Headers/OSUtils.h, + * or /System/Library/Frameworks/IOKit.framework/Headers/ + * pwr_mgt/IOPMLib.h. + * Pass this as one filename argument to open_file() rather than + * deviding to directory part and file part. The first argument to + * open_file() which is a pointer to the directory part is remembered + * by FILEINFO struct. But, 'fullname' is over-written each time, + * and the former path-list is lost soon. Therefore, it cannot be + * passed as the first argument. In addition, though the first + * argument to open_file() is needed for #include_next, this directive + * has no meaning in framework. + */ + if ((cp - fullname) + n > PATHMAX) + cfatal( "Too long framework path", 0, 0L, 0); /* _F_ */ + if (open_file( &null, 0, fullname, FALSE, FALSE, sys_frame)) + return TRUE; + } + return FALSE; +} + +#endif /* SYSTEM == SYS_MAC */ + +#if 0 /* This part is only for debugging */ +static int chk_dirp( + const char ** dirp + ) +/* + * Check the validity of include directory specified for open_file(). + * Called only from open_file(). + */ +{ + const char ** ip; + + if (dirp == &null) + return TRUE; + + for (ip = incdir; ip < incend; ip++) + if (dirp == ip) + break; + if (ip == incend) { +#if COMPILER == MSC + FILEINFO * pfile = infile->parent; + if (pfile) { + while ((pfile = pfile->parent) != 0) { + /* Search each parent includer's directory */ + if (dirp == pfile->dirp) + break; + } + } + if (! pfile) +#endif +#if COMPILER == GNUC + const char ** qdir; + for (qdir = quote_dir; qdir < quote_dir_end; qdir++) { + if (dirp == qdir) + break; + } + if (qdir == quote_dir_end) +#endif + { + cfatal( "Bug: *dirp:%s is invalid", *dirp, 0L, 0); + return FALSE; + } + } + return TRUE; +} +#endif + +void sharp( + FILEINFO * sharp_file, + int flag /* Flag to append to the line for GCC */ + ) +/* + * Output a line number line. + * 'file' is 'sharp_file' if specified, + * else (i.e. 'sharp_file' is 0) 'infile'. + */ +{ + static FILEINFO * sh_file; + static int sh_line; + FILEINFO * file; + int line; + + file = sharp_file ? sharp_file : infile; + if (! file) + return; + while (! file->fp) + file = file->parent; + line = sharp_file ? sharp_file->line : src_line; + if (no_output || option_flags.p || file == 0 + || (file == sh_file && line == sh_line)) + goto sharp_exit; + sh_file = file; + sh_line = line; + if (keep_comments) + mcpp_fputc( '\n', OUT); /* Ensure to be on line top */ + if (std_line_prefix) + mcpp_fprintf( OUT, "#line %ld", line); + else + mcpp_fprintf( OUT, "%s%ld", LINE_PREFIX, line); + cur_file( file, sharp_file, flag); + mcpp_fputc( '\n', OUT); + sharp_exit: + wrong_line = FALSE; +} + +static void cur_file( + FILEINFO * file, /* infile or sharp_file */ + FILEINFO * sharp_file, /* The 'file' or 0 */ + int /*flag*/ /* Flag to append for GCC */ + ) +/* + * Output current source file name and line number. + * Called only from sharp() above. + */ +{ + const char * name; + + if (mcpp_debug & MACRO_CALL) { /* In macro notification mode */ + if (sharp_file) /* Main input file */ + { + name = file->filename; + } + else + {/* Output full-path-list, normalized */ + name = cur_fullname; + } + } else { /* Usually, the path not "normalized" */ + if (sharp_file) { /* Main input file */ + name = file->filename; + } else if (str_eq( file->filename, file->real_fname)) { + ACE_OS::sprintf( work_buf, "%s%s", "" /* *(file->dirp)*/, cur_fname); + name = work_buf; + } else { /* Changed by '#line fname' directive */ + name = file->filename; + } + } + if (sharp_filename == 0 || ! str_eq( name, sharp_filename)) { + if (sharp_filename != 0) + ACE_OS::free( sharp_filename); + sharp_filename = save_string( name); + } + mcpp_fprintf( OUT, " \"%s\"", name); +#if COMPILER == GNUC + if (! std_line_prefix) { + if (flag) { + mcpp_fputc( ' ', OUT); + mcpp_fputc( '0' + flag, OUT); + } + if (file->sys_header) + mcpp_fputs( " 3", OUT); + } +#endif +} + +#if SYS_FAMILY == SYS_WIN + +static char * bsl2sl( + char * filename + ) +/* + * Convert '\\' in the path-list to '/'. + */ +{ + static int diagnosed = FALSE; + char * cp; + + cp = filename; + + while (*cp) { + if (bsl_in_mbchar) { + int c; + c = *cp & UCHARMAX; + if (char_type[ c] & mbchk) { /* First byte of MBCHAR */ + char tmp[ PATHMAX]; + char * tp = tmp; + *tp++ = *cp++; + mb_read( c, &cp, &tp); + /* Read over the multi-byte characters */ + continue; + } + } + if (*cp == '\\') { + *cp++ = PATH_DELIM; + if (!diagnosed && (warn_level & 2) && (warn_level != -1)) { + /* Backslash in source program */ + cwarn( "Converted \\ to %s", "/", 0L, 0); /* _W2_ */ + diagnosed = TRUE; /* Diagnose only once */ + } + } else { + cp++; + } + } + + return filename; +} + +#endif /* SYS_FAMILY == SYS_WIN */ + +static const char * const unknown_arg = + "Unknown argument \"%s\""; /*_W1_*/ +static const char * const not_ident = + "Not an identifier \"%s\""; /*_W1_*/ + +static int is_junk( void) +/* + * Check the trailing junk in a directive line. + * This routine is never called in OLD_PREP mode. + */ +{ + int c; + + c = skip_ws(); + unget_ch(); + if (c != '\n') { /* Trailing junk */ + if (warn_level & 1) + cwarn( unknown_arg, infile->bptr, 0L, 0); + return TRUE; + } else { + return FALSE; + } +} + +#define PUSH 1 +#define POP -1 + +#define __SETLOCALE 1 /* #pragma __setlocale( "encoding") */ +#define SETLOCALE 2 /* #pragma setlocale( "encoding") */ + +void do_pragma( void) +/* + * Process the #pragma lines. + * 1. Process the sub-directive for MCPP. + * 2. Pass the line to the compiler-proper. + * #pragma MCPP put_defines, #pragma MCPP preprocess, + * #pragma MCPP preprocessed and #pragma once are, however, not put + * out so as not to duplicate output when re-preprocessed. + * When EXPAND_PRAGMA == TRUE and (__STDC_VERSION__ >= 199901L or + * __cplusplus >= 199901L), the line is subject to macro expansion unless + * the next to 'pragma' token is one of 'STDC', 'GCC' or 'MCPP'. + */ +{ + int c; + int warn = FALSE; /* Necessity of warning */ + int token_type; + char * bp; /* Pointer to argument */ + char * tp; + FILEINFO * file; + + wrong_line = TRUE; /* In case of error */ + c = skip_ws(); + bp = infile->bptr - 1; /* Remember token to pass to compiler */ + if (c == '\n') { + if (warn_level & 1) + cwarn( "No sub-directive", 0, 0L, 0); /* _W1_ */ + unget_ch(); + return; + } + token_type = scan_token( c, (tp = work_buf, &tp), work_end); +#if EXPAND_PRAGMA +#if COMPILER == MSC + if (token_type == NAM + && !str_eq( identifier, "STDC") && !str_eq( identifier, "MCPP")) { +#else + if (stdc3 && token_type == NAM + && !str_eq( identifier, "STDC") && !str_eq( identifier, "MCPP")) { +#endif + DEFBUF * defp; + char * mp; + char * mp_end; + LINE_COL line_col = { 0L, 0}; + + bp = mp = ACE_OS::malloc( (size_t)(NMACWORK + IDMAX)); + /* Buffer for macro expansion */ + mp_end = mp + NMACWORK; + tp = mcpp_stpcpy( mp, identifier); + do { /* Expand all the macros in the line */ + int has_pragma; + if (token_type == NAM && (defp = is_macro( &tp)) != 0) { + tp = expand_macro( defp, bp, mp_end, line_col, & has_pragma); + if (has_pragma) + cerror( "_Pragma operator found in #pragma line" /* _E_ */ + , 0, 0L, 0); + if (! stdc3 && (warn_level & 2)) + cwarn( + "\"%s\" is macro expanded in other than C99 mode" /* _W2_ */ + , identifier, 0L, 0); + } + token_type = scan_token( c = get_ch(), (bp = tp, &tp), mp_end); + } while (c != '\n'); + unget_string( mp, 0); /* To re-read */ + ACE_OS::free( mp); + c = skip_ws(); + bp = infile->bptr - 1; + token_type = scan_token( c, (tp = work_buf, &tp), work_end); + } +#endif + if (token_type != NAM) { + if (warn_level & 1) + cwarn( not_ident, work_buf, 0L, 0); + goto skip_nl; + } else if (str_eq( identifier, "once")) { /* #pragma once */ + if (! is_junk()) { + file = infile; + while (file->fp == 0) + file = file->parent; + do_once( file->full_fname); + goto skip_nl; + } + } else if (str_eq( identifier, "MCPP")) { + if (scan_token( skip_ws(), (tp = work_buf, &tp), work_end) != NAM) { + if (warn_level & 1) + cwarn( not_ident, work_buf, 0L, 0); + } + if (str_eq( identifier, "put_defines")) { + if (! is_junk()) + dump_def( TRUE, FALSE); /* #pragma MCPP put_defines */ + } else if (str_eq( identifier, "preprocess")) { + if (! is_junk()) /* #pragma MCPP preprocess */ + mcpp_fputs( "#pragma MCPP preprocessed\n", OUT); + /* Just putout the directive */ + } else if (str_eq( identifier, "preprocessed")) { + if (! is_junk()) { /* #pragma MCPP preprocessed*/ + skip_nl(); + do_preprocessed(); + return; + } + } else if (str_eq( identifier, "warning")) { + /* #pragma MCPP warning */ + cwarn( infile->buffer, 0, 0L, 0); + } else if (str_eq( identifier, "push_macro")) { + push_or_pop( PUSH); /* #pragma MCPP push_macro */ + } else if (str_eq( identifier, "pop_macro")) { + push_or_pop( POP); /* #pragma MCPP pop_macro */ + } else if (str_eq( identifier, "debug")) { + do_debug( TRUE); /* #pragma MCPP debug */ + } else if (str_eq( identifier, "end_debug")) { + do_debug( FALSE); /* #pragma MCPP end_debug */ + } else { + warn = TRUE; + } + if (warn && (warn_level & 1)) + cwarn( unknown_arg, identifier, 0L, 0); + goto skip_nl; /* Do not putout the line */ +#if COMPILER == GNUC + /* The #pragma lines for GCC is skipped not to confuse cc1. */ + } else if (str_eq( identifier, "GCC")) { /* #pragma GCC * */ + if (scan_token( skip_ws(), (tp = work_buf, &tp), work_end) == NAM) { + if (str_eq( identifier, "poison") + || str_eq( identifier, "dependency")) { + if (warn_level & 2) + cwarn( "Skipped the #pragma line" /*_W2_ */ + , 0, 0L, 0); + goto skip_nl; + } else if (str_eq( identifier, "system_header")) { + infile->sys_header = TRUE; /* Mark as a system header */ + goto skip_nl; + } + } +#endif + +#if COMPILER == MSC + } else if (str_eq( identifier, "setlocale")) { + if (skip_ws() == '(' + && scan_token( skip_ws(), (tp = work_buf, &tp), work_end) + == STR + && skip_ws() == ')') { + if (! is_junk()) { + work_buf[ 0] = *(tp - 1) = '\0'; + set_encoding( work_buf + 1, 0, SETLOCALE); + work_buf[ 0] = *(tp - 1) = '"'; + } /* else warned by is_junk() */ + } else { + warn = TRUE; + } +#else /* COMPILER != MSC */ + } else if (str_eq( identifier, "__setlocale")) { + if (skip_ws() == '(' + && scan_token( skip_ws(), (tp = work_buf, &tp), work_end) + == STR + && skip_ws() == ')') { + if (! is_junk()) { /* #pragma __setlocale */ + work_buf[ 0] = *(tp - 1) = '\0'; + set_encoding( work_buf + 1, 0, __SETLOCALE); + work_buf[ 0] = *(tp - 1) = '"'; + } /* else warned by is_junk() */ + } else { + warn = TRUE; + } +#endif + +#if COMPILER == MSC + } else if (str_eq( identifier, "push_macro")) { + push_or_pop( PUSH); + goto skip_nl; + } else if (str_eq( identifier, "pop_macro")) { + push_or_pop( POP); + goto skip_nl; +#endif + +#if COMPILER == LCC + } else if (str_eq( identifier, "optimize") + && (skip_ws() == '(') + && (char_type[ (c = skip_ws()) & UCHARMAX] == DIG) + && (skip_ws() == ')')) { + char tmp[ 2]; + + tmp[ 0] = c; + tmp[ 1] = EOS; + look_and_install( optim_name, DEF_NOARGS_PREDEF, null, tmp); +#endif + +#if COMPILER == COMPILER_UNKNOWN + /* + * Write here any compiler-specific #pragma sub-directive which should + * be processed by preprocessor. + */ +#endif + } + + if (warn) { + if (warn_level & 1) + cwarn( unknown_arg, identifier, 0L, 0); + goto skip_nl; /* Do not putout the line */ + } + + sharp( 0, 0); /* Synchronize line number before output */ + if (! no_output) { + mcpp_fputs( "#pragma ", OUT); + mcpp_fputs( bp, OUT); /* Line is put out */ + } + skip_nl: /* Don't use skip_nl() which skips to the newline in source file */ + while (get_ch() != '\n') + ; + } + + static void do_once( + const char * fullname /* Full-path-list of the header */ + ) + /* + * Process #pragma once so as not to re-include the file later. + * This directive has been imported from GCC V.1.* / cpp as an extension. + */ + { + if (once_list == 0) { /* Should initialize */ + max_once = INIT_NUM_ONCE; + once_list = (INC_LIST *) ACE_OS::malloc( sizeof (INC_LIST) * max_once); + once_end = &once_list[ 0]; + } else if (once_end - once_list >= max_once) { + /* Double the elements */ + once_list = (INC_LIST *) ACE_OS::realloc( reinterpret_cast <char *> (once_list), sizeof (INC_LIST) * max_once * 2); + once_end = &once_list[ max_once]; + max_once *= 2; + } + once_end->name = const_cast <char *> (fullname); + once_end->len = ACE_OS::strlen( fullname); + once_end++; + } + + static int included( + const char * fullname + ) + /* + * Has the file been once included ? + * This routine is only called from open_file(). + */ + { + INC_LIST * inc; + size_t fnamelen; + + if (once_list == 0) /* No once file registered */ + return FALSE; + fnamelen = ACE_OS::strlen( fullname); + for (inc = once_list; inc < once_end; inc++) { + if (inc->len == fnamelen && str_case_eq( inc->name, fullname)) { + /* Already included */ + if (mcpp_debug & PATH) + mcpp_fprintf( DBG, "Once included \"%s\"\n", fullname); + return TRUE; + } + } + return FALSE; /* Not yet included */ + } + + static void push_or_pop( + int direction + ) + /* Process #pragma MCPP push_macro( "MACRO"), + * #pragma MCPP pop_macro( "MACRO") for other compilers than Visual C, + * and #pragma push_macro( "MACRO"), #pragma pop_macro( "MACRO") for Visual C. + * Note:1. "push" count is set in defp->push. + * 2. pushed definitions are inserted immediatly after the current + * definition of the same name. + * 3. the definitions of a same name macro can be pushed multiple times. + */ + { + char * tp; + DEFBUF ** prevp; + DEFBUF * defp; + DEFBUF * dp; + int cmp; + size_t s_name, s_def; + + if (skip_ws() == '(' + && scan_token( skip_ws(), (tp = work_buf, &tp), work_end) == STR + && skip_ws() == ')') { /* Correct syntax */ + + if (is_junk()) + return; + s_name = ACE_OS::strlen( work_buf) - 2; + *(work_buf + s_name + 1) = '\0'; + ACE_OS::memcpy( identifier, work_buf + 1, s_name + 1); + /* Remove enclosing '"' */ + prevp = look_prev( identifier, &cmp); + if (cmp == 0) { /* Current definition or pushed definition exists */ + defp = *prevp; + if (direction == PUSH) {/* #pragma push_macro( "MACRO") */ + if (defp->push) { /* No current definition*/ + if (warn_level & 1) + cwarn( "\"%s\" is already pushed" /* _W1_ */ + , identifier, 0L, 0); + return; + } + /* Else the current definition exists. Push it */ + s_def = sizeof (DEFBUF) + 3 + s_name + + ACE_OS::strlen( defp->repl) + ACE_OS::strlen( defp->fname); + if (mcpp_mode == STD) + s_def += ACE_OS::strlen( defp->parmnames); + dp = (DEFBUF *) ACE_OS::malloc( s_def); + ACE_OS::memcpy( dp, defp, s_def); /* Copy the definition */ + dp->link = *prevp; /* Insert to linked-list*/ + *prevp = dp; /* the pushed def */ + prevp = &dp->link; /* Next link to search */ + } else { /* #pragma pop_macro( "MACRO") */ + if (defp->push == 0) { /* Current definition */ + if (defp->link == 0 + || ! str_eq( identifier, defp->link->name)) { + if (warn_level & 1) + cwarn( "\"%s\" has not been pushed" /* _W1_ */ + , identifier, 0L, 0); + return; + } else { + *prevp = defp->link; + /* Link the previous and the next */ + ACE_OS::free( defp); + /* Delete the definition to enable popped def */ + } + } /* Else no current definition exists */ + } + while ((defp = *prevp) != 0) { + /* Increment or decrement "push" count of all pushed defs */ + if ((cmp = ACE_OS::memcmp( defp->name, identifier, s_name)) > 0) + break; + defp->push += direction; /* Increment or decrement */ + prevp = &defp->link; + } + } else { /* No current definition nor pushed definition */ + if (warn_level & 1) + cwarn( "\"%s\" has not been defined" /* _W1_ */ + , identifier, 0L, 0); + } + } else { /* Wrong syntax */ + if (warn_level & 1) + cwarn( "Bad %s syntax", direction == PUSH /* _W1_ */ + ? "push_macro" : "pop_macro", 0L, 0); + } + } + + static void do_asm( + int asm_start /* #asm ? */ + ) + /* + * #asm, #endasm + * Originally written for OS-9/09 Microware C. + */ + { + if (! compiling) + return; + if (asm_start == (in_asm != 0L)) { + if (in_asm) + cerror( "In #asm block started at line %.0s%ld" /* _E_ */ + , 0, in_asm, 0); + else + cerror( "Without #asm", 0, 0L, 0); /* _E_ */ + skip_nl(); + unget_ch(); + return; + } + in_asm = asm_start ? src_line : 0L; + } + + void do_old( void) + /* + * Process the out-of-standard directives. + * GCC permits #include_next and #warning even in STANDARD mode. + */ + { + static const char * const unknown + = "Unknown #directive \"%s\"%.0ld%s"; /* _E_ _W8_ */ + // static const char * const ext + // = "%s is not allowed by Standard%.0ld%s"; /* _W2_ _W8_*/ + +#if COMPILER == GNUC + if (str_eq( identifier, "include_next")) { + if ((compiling && (warn_level & 2)) + || (! compiling && (warn_level & 8))) + cwarn( ext, "#include_next", 0L + , compiling ? 0 : " (in skipped block)"); + if (! compiling) + return; + in_include = TRUE; + do_include( TRUE); + in_include = FALSE; + return; + } else if (str_eq( identifier, "warning")) { + if ((compiling && (warn_level & 2)) + || (! compiling && (warn_level & 8))) + cwarn( ext, "#warning", 0L + , compiling ? 0 : " (in skipped block)"); + if (! compiling) + return; + cwarn( infile->buffer, 0, 0L, 0); + /* Always output the warning */ + skip_nl(); + unget_ch(); + return; + } else if (str_eq( identifier, "ident") || str_eq( identifier, "sccs")) { + if ((compiling && (warn_level & 1)) + || (! compiling && (warn_level & 8))) { + if (str_eq( identifier, "ident")) + cwarn( + compiling ? "Ignored #ident" : "#ident (in skipped block)" /* _W1_ _W8_*/ + , 0, 0L, 0); + else + cwarn( + compiling ? "Ignored #sccs" : "#sccs (in skipped block)" /* _W1_ _W8_*/ + , 0, 0L, 0); + } + if (! compiling) + return; + skip_nl(); + unget_ch(); + return; + } +#endif /* COMPILER == GNUC */ + +#if COMPILER == MSC + if (str_eq( identifier, "using") || str_eq( identifier, "import")) { + /* #using or #import */ + if (! compiling) + return; + mcpp_fputs( infile->buffer, OUT); /* Putout the line as is*/ + skip_nl(); + unget_ch(); + return; + } +#endif + +#if SYSTEM == SYS_MAC + if (str_eq( identifier, "import")) { + if ((compiling && (warn_level & 2)) + || (! compiling && (warn_level & 8))) + cwarn( ext, "#import", 0L + , compiling ? 0 : " (in skipped block)"); + if (! compiling) + return; + in_import = in_include = TRUE; + do_include( FALSE); + in_import = in_include = FALSE; + return; + } +#endif + + if (! standard && do_prestd_directive()) + return; + + if (compiling) { + if (option_flags.lang_asm) { /* "Assembler" source */ + if (warn_level & 1) + cwarn( unknown, identifier, 0L, 0); + mcpp_fputs( infile->buffer, OUT); /* Putout the line */ + } else { + cerror( unknown, identifier, 0L, 0); + } + } else if (warn_level & 8) { + cwarn( unknown, identifier, 0L, " (in skipped block)"); + } + skip_nl(); + unget_ch(); + return; + } + + static int do_prestd_directive( void) + /* + * Process directives for pre-Standard mode. + */ + { +#if COMPILER != GNUC + if (str_eq( identifier, "assert")) { /* #assert */ + if (! compiling) /* Only validity check */ + return TRUE; + if (eval_if() == 0L) { /* Assert expression */ + cerror( "Preprocessing assertion failed" /* _E_ */ + , 0, 0L, 0); + skip_nl(); + unget_ch(); + } + return TRUE; + } else +#endif + if (str_eq( identifier, "put_defines")) { + if (! compiling) /* Only validity check */ + return TRUE; + if (mcpp_mode != OLD_PREP && ! is_junk()) + dump_def( TRUE, FALSE); /* #put_defines */ + skip_nl(); + unget_ch(); + return TRUE; + } else if (str_eq( identifier, "preprocess")) { + if (! compiling) /* Only validity check */ + return TRUE; + if (mcpp_mode != OLD_PREP && ! is_junk()) + /* Just putout the directive for the succeding preprocessor */ + mcpp_fputs( "#preprocessed\n", OUT); + skip_nl(); + unget_ch(); + return TRUE; + } else if (str_eq( identifier, "preprocessed")) { + if (! compiling) /* Only validity check */ + return TRUE; + if (mcpp_mode != OLD_PREP && ! is_junk()) { + skip_nl(); + do_preprocessed(); /* #preprocessed */ + return TRUE; + } + skip_nl(); + unget_ch(); + return TRUE; + } + + if (str_eq( identifier, "debug")) { /* #debug <args> */ + if (! compiling) /* Only validity check */ + return TRUE; + do_debug( TRUE); + return TRUE; + } else if (str_eq( identifier, "end_debug")) { + if (! compiling) + return TRUE; + do_debug( FALSE); /* #end_debug <args> */ + return TRUE; + } + + if (str_eq( identifier, "asm")) { /* #asm */ + do_asm( TRUE); + return TRUE; + } + if (str_eq( identifier, "endasm")) { /* #endasm */ + do_asm( FALSE); + skip_nl(); /* Skip comments, etc. */ + unget_ch(); + return TRUE; + } + + return FALSE; /* Unknown directive */ + } + + static void do_preprocessed( void) + /* + * The source file has been already preprocessed. + * Copy the lines to output. + * Install macros according the #define directives. + */ + { + const char * corrupted = + "This preprocessed file is corrupted"; /* _F_ */ + FILEINFO * file; + char * lbuf; + char * cp; + const char ** incptr; + char * comment = 0; + char * colon = 0; + const char * dir; +#if STD_LINE_PREFIX == FALSE + char conv[ NBUFF]; + char * arg; + + /* + * Compiler cannot accept C source style #line. + * Convert it to the compiler-specific format. + */ + ACE_OS::strcpy( conv, LINE_PREFIX); + arg = conv + ACE_OS::strlen( conv); +#endif + file = infile; + lbuf = file->bptr = file->buffer; /* Reset file->bptr */ + + /* Copy the input to output until a comment line appears. */ + while (ACE_OS::fgets( lbuf, NBUFF, file->fp) != 0 + && ACE_OS::memcmp( lbuf, "/*", 2) != 0) { +#if STD_LINE_PREFIX == FALSE + if (ACE_OS::memcmp( lbuf, "#line ", 6) == 0) { + ACE_OS::strcpy( arg, lbuf + 6); + mcpp_fputs( conv, OUT); + } else +#endif + { + mcpp_fputs( lbuf, OUT); + } + } + if (! str_eq( lbuf, "/* Currently defined macros. */\n")) + cfatal( "This is not a preprocessed source" /* _F_ */ + , 0, 0L, 0); + + /* Define macros according to the #define lines. */ + while (ACE_OS::fgets( lbuf, NWORK, file->fp) != 0) { + if (ACE_OS::memcmp( lbuf, "/*", 2) == 0) { + /* Standard predefined macro */ + continue; + } + if (ACE_OS::memcmp( lbuf, "#define ", 8) != 0) { + if (ACE_OS::memcmp( lbuf, "#line", 5) == 0) + continue; + else + cfatal( corrupted, 0, 0L, 0); + } + /* Filename and line-number information in comment as: */ + /* dir/fname:1234\t*/ + cp = lbuf + ACE_OS::strlen( lbuf); + if ((ACE_OS::memcmp( cp - 4, "\t*/\n", 4) != 0) + || (*(cp - 4) = EOS + , (comment = ACE_OS::strrchr( lbuf, '*')) == 0) + || (ACE_OS::memcmp( --comment, "/* ", 3) != 0) + || ((colon = ACE_OS::strrchr( comment, ':')) == 0)) + cfatal( corrupted, 0, 0L, 0); + src_line = ACE_OS::atol( colon + 1); /* Pseudo line number */ + *colon = EOS; + dir = comment + 3; + inc_dirp = &null; + /* Search the include directory list */ + for (incptr = incdir ; incptr < incend; incptr++) { + if (ACE_OS::memcmp( *incptr, dir, ACE_OS::strlen( *incptr)) == 0) { + inc_dirp = incptr; + break; + } + } + /* Register the filename to fnamelist[] */ + /* inc_dirp may be 0, and cur_fname may be "(predefined)" */ + cur_fname = set_fname( dir + ACE_OS::strlen( *inc_dirp)); + + ACE_OS::strcpy( comment - 2, "\n"); /* Remove the comment */ + unget_string( lbuf + 8, 0); + do_define( FALSE, 0); + get_ch(); /* '\n' */ + get_ch(); /* Clear the "file" */ + unget_ch(); /* infile == file */ + } + file->bptr = file->buffer + ACE_OS::strlen( file->buffer); + } + + static int do_debug( + int set /* TRUE to set debugging */ + ) + /* + * #pragma MCPP debug, #pragma MCPP end_debug, #debug, #end_debug + * Return TRUE when diagnostic is issued else return FALSE. + */ + { + struct Debug_arg { + const char * arg_name; /* Name of option */ + int arg_num; /* Value of 'debug' */ + }; + static struct Debug_arg debug_args[] = { + { "path", PATH }, + { "token", TOKEN }, + { "expand", EXPAND }, + { "macro_call", MACRO_CALL }, /* Implemented only in STD mode */ + { "if", IF }, + { "expression", EXPRESSION }, + { "getc", GETC }, + { "memory", MEMORY }, + { 0, 0 }, + }; + struct Debug_arg *argp; + int num = 0; + int c; + + c = skip_ws(); + if (c == '\n') { + unget_ch(); + if (set) { + if (warn_level & 1) + cwarn( "No argument", 0, 0L, 0); /* _W1_ */ + return TRUE; + } else { + mcpp_debug = 0; /* Clear all the flags */ + return FALSE; + } + } + while (scan_token( c, (workp = work_buf, &workp), work_end) == NAM) { + argp = debug_args; + while (argp->arg_name) { + if (str_eq( argp->arg_name, work_buf)) + break; + argp++; + } + if (argp->arg_name == 0) { + if (warn_level & 1) + cwarn( unknown_arg, work_buf, 0L, 0); + goto diagnosed; + } else { + num = argp->arg_num; + if (set) { + mcpp_debug |= num; + if (num == PATH) + dump_path(); + else if (num == MEMORY) + print_heap(); + else if (num == MACRO_CALL) + option_flags.k = TRUE; /* This pragma needs this mode */ + } else { + mcpp_debug &= ~num; + } + } + c = skip_ws(); + } + if ((mcpp_mode != STD && (mcpp_debug & MACRO_CALL)) || c != '\n') { + if (warn_level & 1) { + if (c != '\n') { + cwarn( not_ident, work_buf, 0L, 0); + } else { + cwarn( unknown_arg, work_buf, 0L, 0); + mcpp_debug &= ~num; /* Disable */ + } + } + skip_nl(); + unget_ch(); + goto diagnosed; + } + unget_ch(); + return FALSE; + diagnosed: + return TRUE; + } + + void put_asm( void) + /* + * Put out source line as it is. + */ + { +#if 0 + mcpp_fputs( "#2\n", OUT); + mcpp_fputs( infile->buffer, OUT); + skip_nl(); +#endif + } + + static void dump_path( void) + /* + * Show the include directories. + */ + { + const char ** incptr; + const char * inc_dir; + const char * dir = "./"; + // int i; + + mcpp_fputs( "Include paths are as follows --\n", DBG); + for (incptr = incdir; incptr < incend; incptr++) { + inc_dir = *incptr; + if (*inc_dir == '\0') + inc_dir = dir; + mcpp_fprintf( DBG, " %s\n", inc_dir); + } + mcpp_fputs( "End of include path list.\n", DBG); +#if SYSTEM == SYS_MAC + mcpp_fputs( "Framework paths are as follows --\n", DBG); + for (i = 0; i < num_framework; i++ ) + mcpp_fprintf( DBG, " %s\n", framework[ i]); + mcpp_fputs( "End of framework path list.\n", DBG); +#endif + } + + /* + * Note: The getopt() of glibc should not be used since the specification + * differs from the standard one. + * Use this mcpp_getopt() for mcpp. + */ + + /* Based on the public-domain-software released by AT&T in 1985. */ + +#define OPTERR( s, c) if (mcpp_opterr) { \ + mcpp_fputs( argv[0], ERR); \ + mcpp_fputs( s, ERR); \ + mcpp_fputc( c, ERR); \ + mcpp_fputc( '\n', ERR); \ + } + + static int mcpp_getopt( + int argc, + char * const * argv, + const char * opts + ) + /* + * Get the next option (and it's argument) from the command line. + */ + { + const char * const error1 = ": option requires an argument --"; + const char * const error2 = ": illegal option --"; + static int sp = 1; + int c; + const char * cp; + + if (sp == 1) { + if (argc <= mcpp_optind || + argv[ mcpp_optind][ 0] != '-' + || argv[ mcpp_optind][ 1] == '\0') { + return EOF; + } else if (ACE_OS::strcmp( argv[ mcpp_optind], "--") == 0) { + mcpp_optind++; + return EOF; + } + } + /* mcpp_optopt = c = (unsigned char) argv[ mcpp_optind][ sp]; */ + mcpp_optopt = c = argv[ mcpp_optind][ sp] & UCHARMAX; + if (c == ':' || (cp = ACE_OS::strchr( opts, c)) == 0) { + OPTERR( error2, c) + if (argv[ mcpp_optind][ ++sp] == '\0') { + mcpp_optind++; + sp = 1; + } + return '?'; + } + if (*++cp == ':') { + if (argv[ mcpp_optind][ sp+1] != '\0') { + mcpp_optarg = &argv[ mcpp_optind++][ sp+1]; + } else if (argc <= ++mcpp_optind) { + OPTERR( error1, c) + sp = 1; + return '?'; + } else { + mcpp_optarg = argv[ mcpp_optind++]; + } + sp = 1; + } else { + if (argv[ mcpp_optind][ ++sp] == '\0') { + sp = 1; + mcpp_optind++; + } + mcpp_optarg = 0; + } + return c; + } + +#if defined(HOST_HAVE_STPCPY) && HOST_HAVE_STPCPY == FALSE + char * mcpp_stpcpy( + char * dest, + const char * src + ) + /* + * Copy the string and return the advanced pointer. + */ + { + const char * s; + char * d; + + for (s = src, d = dest; (*d++ = *s++) != '\0'; ) + ; + return d - 1; + } +#endif + + /* + * list_heap() is a function to print out information of heap-memory. + * See "kmmalloc-2.5.3.zip" by kmatsui. + */ +#if KMMALLOC + int list_heap( int); +#elif BSD_MALLOC + int list_heap( char *); +#elif DB_MALLOC || DMALLOC + int list_heap( FILE *); +#endif + + void print_heap( void) + { +#if KMMALLOC + list_heap( 1); +#elif BSD_MALLOC + list_heap( ":cpp"); +#elif DB_MALLOC || DMALLOC || PHK_MALLOC || DLMALLOC + list_heap( fp_debug); +#endif + } + + void at_end( void) + /* + * Handle the commands to be executed at the end of processing. + */ + { +#if COMPILER == GNUC + if (dMflag || dDflag) + dump_def( FALSE, FALSE); +#endif + } + +#ifdef MCPP_LIB + void clear_filelist( void) + /* + * Free malloced memory for filename-list and directory-list. + */ + { + const char ** incp; + INC_LIST * namep; + + for (incp = incdir; incp < incend; incp++) + ACE_OS::free( (void *) *incp); + ACE_OS::free( (void *) incdir); + for (namep = fnamelist; namep < fname_end; namep++) + ACE_OS::free( (void *) namep->name); + ACE_OS::free( (void *) fnamelist); + if (standard) + ACE_OS::free( (void *) once_list); + } +#endif + |