1 /*-
2  * Copyright (c) 1998, 2002-2008 Kiyoshi Matsui <kmatsui@t3.rim.or.jp>
3  * All rights reserved.
4  *
5  * Some parts of this code are derived from the public domain software
6  * DECUS cpp (1984,1985) written by Martin Minow.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  *                          S Y S T E M . C
32  *          S y s t e m   D e p e n d e n t   R o u t i n e s
33  *
34  * Routines dependent on O.S., compiler or compiler-driver.
35  * To port MCPP for the systems not yet ported, you must
36  *      1. specify the constants in "configed.H" or "noconfig.H",
37  *      2. append the system-dependent routines in this file.
38  */
39 #if PREPROCESSED
40 #include    "mcpp.H"
41 #else
42 #include    "system.H"
43 #include    "internal.H"
44 #endif
45 
46 #if     HOST_SYS_FAMILY == SYS_UNIX
47 #include    "unistd.h"              /* For getcwd(), readlink() */
48 #elif   HOST_COMPILER == MSC || HOST_COMPILER == LCC
49 #include    "direct.h"
50 #define getcwd( buf, size)  _getcwd( buf, size)
51 #elif   HOST_COMPILER == BORLANDC
52 #include    "dir.h"
53 #endif
54 
55 #include    "sys/types.h"
56 #include    "sys/stat.h"                        /* For stat()       */
57 #if     ! defined( S_ISREG)
58 #define S_ISREG( mode)  (mode & S_IFREG)
59 #define S_ISDIR( mode)  (mode & S_IFDIR)
60 #endif
61 #if     HOST_COMPILER == MSC
62 #define S_IFREG     _S_IFREG
63 #define S_IFDIR     _S_IFDIR
64 #define stat( path, stbuf)  _stat( path, stbuf)
65 #endif
66 
67 /* Function to compare path-list    */
68 #if     FNAME_FOLD
69 #if     HOST_COMPILER == GNUC   /* CYGWIN, MINGW, MAC   */
70 #include    <strings.h>         /* POSIX 1, 2001        */
71 #define str_case_eq( str1, str2)    (strcasecmp( str1, str2) == 0)
72 #else   /* MSC, BORLANDC, LCC   */
73 #if     HOST_COMPILER == MSC
74 #define stricmp( str1, str2)        _stricmp( str1, str2)
75 #endif
76 #define str_case_eq( str1, str2)    (stricmp( str1, str2) == 0)
77 #endif
78 #else   /* ! FNAME_FOLD */
79 #define str_case_eq( str1, str2)    (strcmp( str1, str2) == 0)
80 #endif
81 
82 /*
83  * PATH_DELIM is defined for the O.S. which has single byte path-delimiter.
84  * Note: '\\' or any other character identical to second byte of MBCHAR should
85  * not be used for PATH_DELIM for convenience of path-list parsing.
86  */
87 #if SYS_FAMILY == SYS_UNIX || SYS_FAMILY == SYS_WIN || SYSTEM == SYS_UNKNOWN
88 #define PATH_DELIM      '/'
89 #define SPECIAL_PATH_DELIM  FALSE
90 #else   /* Any other path-delimiter, define PATH_DELIM by yourself  */
91 #define SPECIAL_PATH_DELIM  TRUE    /* Any path-delimiter other than '/'    */
92 #endif
93 
94 /*
95  * OBJEXT is the suffix to denote "object" file.
96  */
97 #ifndef OBJEXT
98 #if     SYS_FAMILY == SYS_UNIX || HOST_COMPILER == GNUC
99 #define OBJEXT     "o"
100 #elif   SYS_FAMILY == SYS_WIN
101 #define OBJEXT     "obj"
102 #elif   1
103 /* Add here appropriate definitions for other systems.  */
104 #endif
105 #endif
106 
107 static void     version( void);
108                 /* Print version message            */
109 static void     usage( int opt);
110                 /* Putout usage of MCPP             */
111 static void     set_opt_list( char * optlist);
112                 /* Set list of legal option chars   */
113 static int      parse_warn_level( const char * mcpp_optarg, int opt);
114                 /* Parse warning level option       */
115 static void     def_a_macro( int opt, char * def);
116                 /* Do a -D option                   */
117 static void     chk_opts( int sflag, int trad);
118                 /* Check consistency of options     */
119 #if COMPILER != GNUC
120 static void     init_cpu_macro( int gval, int sse);
121                 /* Predefine CPU-dependent macros   */
122 #endif
123 static void     init_predefines( void);
124                 /* Set and unset predefined macros  */
125 static void     init_std_defines( void);
126                 /* Predefine Standard macros        */
127 static void     set_limit( void);
128                 /* Set minimum translation limits   */
129 static void     set_pragma_op( void);
130                 /* Set the _Pragma() operator       */
131 static void     put_info( FILEINFO * sharp_file);
132                 /* Print compiler-specific-inf      */
133 static char *   set_files( int argc, char ** argv, char ** in_pp
134         , char ** out_pp);
135                 /* Set input, output, diagnostic    */
136 static void     set_sys_dirs( int set_cplus_dir);
137                 /* Set system-specific include dirs */
138 static void     set_env_dirs( void);
139                 /* Set user-defined include dirs    */
140 static void     parse_env( const char * env);
141                 /* Parse environment variables      */
142 static void     set_a_dir( const char * dirname);
143                 /* Append an include directory      */
144 static char *   norm_dir( const char * dirname, int framework);
145                 /* Normalize include directory path */
146 static char *   norm_path( const char * dir, const char * fname, int inf
147         , int hmap);    /* Normalize pathname to compare    */
148 #if SYS_FAMILY == SYS_UNIX
149 static void     deref_syml( char * slbuf1, char * slbuf2, char * chk_start);
150                 /* Dereference symbolic linked directory and file   */
151 #endif
152 #if COMPILER == GNUC
153 static void     init_gcc_macro( void);
154                 /* Predefine GCC-specific macros    */
155 static void     chk_env( void);
156                 /* Check the environment variables  */
157 #elif   COMPILER == MSC
158 static void     init_msc_macro( void);
159                 /* Predefine Visual C-specific macros       */
160 #endif
161 static void     def_macros( void);
162                 /* Define macros specified by -D    */
163 static void     undef_macros( void);
164                 /* Undefine macros specified by -U  */
165 static char *   md_init( const char * filename, char * output);
166                 /* Initialize makefile dependency   */
167 static char *   md_quote( char * output);
168                 /* 'Quote' special characters       */
169 static int      open_include( char * filename, int searchlocal, int next);
170                 /* Open the file to include         */
171 static int      has_directory( const char * source, char * directory);
172                 /* Get directory part of fname      */
173 static int      is_full_path( const char * path);
174                 /* The path is absolute path list ? */
175 static int      search_dir( char * filename, int searchlocal, int next);
176                 /* Search the include directories   */
177 static int      open_file( const char ** dirp, const char * src_dir
178         , const char * filename, int local, int include_opt, int sys_frame);
179                 /* Open a source file       */
180 static const char *     set_fname( const char * filename);
181                 /* Remember the source filename     */
182 #if SYSTEM == SYS_MAC
183 #if COMPILER == GNUC
184 static char *   search_header_map( const char * hmap_file
185         , const char * filename, char * pathlist);
186                 /* Search header map file for a header  */
187 static unsigned hmap_hash( const char * fname);
188                 /* Get hash value for the fname     */
189 #endif
190 static void     init_framework( void);
191                 /* Initialize framework[]           */
192 static int      search_framework( char * filename);
193                 /* Search "Framework" directories   */
194 static int      search_subdir( char * fullname, char * cp, char * frame
195         , char * fname, int sys_frame);
196                 /* Search "Headers" and other dirs  */
197 #endif  /* SYSTEM == SYS_MAC    */
198 #if 0   /* This function is only for debugging use  */
199 static int      chk_dirp( const char ** dirp);
200                 /* Check validity of dirp arg for open_file()   */
201 #endif
202 static void     cur_file( FILEINFO * file, FILEINFO * sharp_file, int marker);
203                 /* Output current source file name  */
204 #if SYS_FAMILY == SYS_WIN
205 static char *   bsl2sl( char * filename);
206                 /* Convert \ to / in path-list      */
207 #endif
208 static int      is_junk( void);
209                 /* The directive has trailing junk? */
210 static void     do_once( const char * fullname);
211                 /* Process #pragma once             */
212 static int      included( const char * fullname);
213                 /* The file has been once included? */
214 static void     push_or_pop( int direction);
215                 /* Push or pop a macro definition   */
216 static int      do_prestd_directive( void);
217                 /* Process pre-Standard directives  */
218 static void     do_preprocessed( void);
219                 /* Process preprocessed file        */
220 static int      do_debug( int set);
221                 /* #pragma MCPP debug, #debug       */
222 static void     dump_path( void);
223                 /* Print include search path        */
224 static void     do_asm( int asm_start);
225                 /* Process #asm, #endasm            */
226 static int      mcpp_getopt( int argc, char * const * argv, const char * opts);
227                 /* getopt() to prevent linking of glibc getopt  */
228 
229 /* for mcpp_getopt()    */
230 static int      mcpp_optind = 1;
231 static int      mcpp_opterr = 1;
232 static int      mcpp_optopt;
233 static char *   mcpp_optarg;
234 
235 static int      mb_changed = FALSE;     /* Flag of -e option        */
236 static char     cur_work_dir[ PATHMAX + 1];     /* Current working directory*/
237 
238 /*
239  * incdir[] stores the -I directories (and the system-specific #include <...>
240  * directories).  This is set by set_a_dir().  A trailing PATH_DELIM is
241  * appended if absent.
242  */
243 static const char **    incdir;         /* Include directories      */
244 static const char **    incend;         /* -> active end of incdir  */
245 static int          max_inc;            /* Number of incdir[]       */
246 
247 typedef struct inc_list {       /* List of directories or files     */
248     char *      name;           /* Filename or directory-name       */
249     size_t      len;                    /* Length of 'name'         */
250 } INC_LIST;
251 
252 /*
253  * fnamelist[] stores the souce file names opened by #include directive for
254  * debugging information.
255  */
256 static INC_LIST *   fnamelist;          /* Source file names        */
257 static INC_LIST *   fname_end;          /* -> active end of fnamelist   */
258 static int          max_fnamelist;      /* Number of fnamelist[]    */
259 
260 /* once_list[] stores the #pragma once file names.  */
261 static INC_LIST *   once_list;          /* Once opened file         */
262 static INC_LIST *   once_end;           /* -> active end of once_list   */
263 static int          max_once;           /* Number of once_list[]    */
264 
265 #define INIT_NUM_INCLUDE    32          /* Initial number of incdir[]   */
266 #define INIT_NUM_FNAMELIST  256         /* Initial number of fnamelist[]    */
267 #define INIT_NUM_ONCE       64          /* Initial number of once_list[]    */
268 
269 /*
270  * 'search_rule' holds searching rule of #include "header.h" to search first
271  * before searching user specified or system-specific include directories.
272  * 'search_rule' is initialized to SEARCH_INIT.  It can be changed by -I1, -I2
273  * or -I3 option.  -I1 specifies CURRENT, -I2 SOURCE and -I3 both.
274  */
275 
276 static int      search_rule = SEARCH_INIT;  /* Rule to search include file  */
277 
278 static int      nflag = FALSE;          /* Flag of -N (-undef) option       */
279 static long     std_val = -1L;  /* Value of __STDC_VERSION__ or __cplusplus */
280 
281 #define MAX_DEF   256
282 #define MAX_UNDEF (MAX_DEF/4)
283 static char *   def_list[ MAX_DEF];     /* Macros to be defined     */
284 static char *   undef_list[ MAX_UNDEF]; /* Macros to be undefined   */
285 static int      def_cnt;                /* Count of def_list        */
286 static int      undef_cnt;              /* Count of undef_list      */
287 
288 /* Values of mkdep. */
289 #define MD_MKDEP        1   /* Output source file dependency line   */
290 #define MD_SYSHEADER    2   /* Print also system-header names       */
291 #define MD_FILE         4   /* Output to the file named *.d         */
292 #define MD_PHONY        8   /* Print also phony targets for each header */
293 #define MD_QUOTE        16  /* 'Quote' $ and space in target name   */
294 
295 static FILE *   mkdep_fp;                       /* For -Mx option   */
296 static char *   mkdep_target;
297     /* For -MT TARGET option and for GCC's queer environment variables.     */
298 static char *   mkdep_mf;               /* Argument of -MF option   */
299 static char *   mkdep_md;               /* Argument of -MD option   */
300 static char *   mkdep_mq;               /* Argument of -MQ option   */
301 static char *   mkdep_mt;               /* Argument of -MT option   */
302 
303 /* sharp_filename is filename for #line line, used only in cur_file()   */
304 static char *   sharp_filename = NULL;
305 static char *   argv0;      /* argv[ 0] for usage() and version()   */
306 static int      ansi;           /* __STRICT_ANSI__ flag for GNUC    */
307 static int      compat_mode;
308                 /* "Compatible" mode of recursive macro expansion   */
309 #define MAX_ARCH_LEN    16
310 static char     arch[ MAX_ARCH_LEN];    /* -arch or -m64, -m32 options      */
311 
312 #if COMPILER == GNUC
313 #define N_QUOTE_DIR     8
314 /* quote_dir[]:     Include directories for "header" specified by -iquote   */
315 /* quote_dir_end:   Active end of quote_dir */
316 static const char *     quote_dir[ N_QUOTE_DIR];
317 static const char **    quote_dir_end = quote_dir;
318 /* sys_dirp indicates the first directory to search for system headers.     */
319 static const char **    sys_dirp = NULL;        /* System header directory  */
320 static const char *     sysroot = NULL; /* Logical root directory of header */
321 static int      i_split = FALSE;                /* For -I- option   */
322 static int      gcc_work_dir = FALSE;           /* For -fworking-directory  */
323 static int      gcc_maj_ver;                    /* __GNUC__         */
324 static int      gcc_min_ver;                    /* __GNUC_MINOR__   */
325 static int      dDflag = FALSE;         /* Flag of -dD option       */
326 static int      dMflag = FALSE;         /* Flag of -dM option       */
327 #endif
328 
329 #if COMPILER == GNUC || COMPILER == MSC
330 /*
331  * preinclude points to the file specified by -include (-Fl for MSC) option,
332  * which is included prior to the main input file.
333  */
334 #define         NPREINCLUDE 8
335 static char *   preinclude[ NPREINCLUDE];       /* File to pre-include      */
336 static char **  preinc_end = preinclude;    /* -> active end of preinclude  */
337 #endif
338 
339 #if COMPILER == MSC
340 static int      wchar_t_modified = FALSE;   /* -Zc:wchar_t flag     */
341 #endif
342 
343 #if COMPILER == LCC
344 static const char *     optim_name = "__LCCOPTIMLEVEL";
345 #endif
346 
347 #if SYSTEM == SYS_CYGWIN
348 static int      no_cygwin = FALSE;          /* -mno-cygwin          */
349 
350 #elif   SYSTEM == SYS_MAC
351 #define         MAX_FRAMEWORK   8
352 static char *   framework[ MAX_FRAMEWORK];  /* Framework directories*/
353 static int      num_framework;          /* Current number of framework[]    */
354 static int      sys_framework;          /* System framework dir     */
355 static const char **    to_search_framework;
356                         /* Search framework[] next to the directory */
357 static int      in_import;          /* #import rather than #include */
358 #endif
359 
360 #define NO_DIR  FALSE
361 #if NO_DIR
362 /* Unofficial feature to strip directory part of include file   */
363 static int      no_dir;
364 #endif
365 
366 #if MCPP_LIB
init_system(void)367 void    init_system( void)
368 /* Initialize static variables  */
369 {
370     if (sharp_filename)
371         free( sharp_filename);
372     sharp_filename = NULL;
373     incend = incdir = NULL;
374     fnamelist = once_list = NULL;
375     search_rule = SEARCH_INIT;
376     mb_changed = nflag = ansi = compat_mode = FALSE;
377     mkdep_fp = NULL;
378     mkdep_target = mkdep_mf = mkdep_md = mkdep_mq = mkdep_mt = NULL;
379     std_val = -1L;
380     def_cnt = undef_cnt = 0;
381     mcpp_optind = mcpp_opterr = 1;
382 #if COMPILER == GNUC
383     sys_dirp = NULL;
384     sysroot = NULL;
385     gcc_work_dir = i_split = FALSE;
386     quote_dir_end = quote_dir;
387     dDflag = dMflag = FALSE;
388 #endif
389 #if COMPILER == MSC
390     wchar_t_modified = FALSE;
391 #endif
392 #if COMPILER == GNUC || COMPILER == MSC
393     preinc_end = preinclude;
394 #endif
395 #if SYSTEM == SYS_CYGWIN
396     no_cygwin = FALSE;
397 #elif   SYSTEM == SYS_MAC
398     num_framework = sys_framework = 0;
399     to_search_framework = NULL;
400 #endif
401 #if NO_DIR
402     no_dir = FALSE;
403 #endif
404 }
405 
406 #endif
407 
408 #define OPTLISTLEN  80
409 
do_options(int argc,char ** argv,char ** in_pp,char ** out_pp)410 void    do_options(
411     int         argc,
412     char **     argv,
413     char **     in_pp,                      /* Input file name      */
414     char **     out_pp                      /* Output file name     */
415 )
416 /*
417  * Process command line arguments, called only at MCPP startup.
418  */
419 {
420     char        optlist[ OPTLISTLEN];       /* List of option letter*/
421     const char *    warning = "warning: -%c%s option is ignored\n";
422     int         opt;
423     int         unset_sys_dirs;
424         /* Unset system-specific and site-specific include directories ?    */
425     int         set_cplus_dir;  /* Set C++ include directory ? (for GCC)*/
426     int         show_path;          /* Show include directory list  */
427     DEFBUF *    defp;
428     VAL_SIGN *  valp;
429     int         sflag;                      /* -S option or similar */
430     int         trad;                       /* -traditional         */
431     int         old_mode;                   /* backup of 'mcpp_mode'*/
432     int         gval, sse;
433     char *      cp;
434     int         i;
435 #if COMPILER == GNUC
436 #define NSYSDIR   8
437     /* System include directory specified by -isystem   */
438     char *      sysdir[ NSYSDIR] = { NULL, };
439     char **     sysdir_end = sysdir;
440     int         integrated_cpp; /* Flag of cc1 which integrates cpp in it   */
441 #elif   COMPILER == LCC
442     const char *    debug_name = "__LCCDEBUGLEVEL";
443 #endif
444 
445     argv0 = argv[ 0];
446     nflag = unset_sys_dirs = show_path = sflag = trad = FALSE;
447     arch[ 0] = 0;
448     gval = sse = 0;
449     set_cplus_dir = TRUE;
450 
451     /* Get current directory for -I option and #pragma once */
452     getcwd( cur_work_dir, PATHMAX);
453 #if SYS_FAMILY == SYS_WIN
454     bsl2sl( cur_work_dir);
455 #endif
456     sprintf( cur_work_dir + strlen( cur_work_dir), "%c%c", PATH_DELIM, EOS);
457         /* Append trailing path-delimiter   */
458 
459 #if COMPILER == GNUC
460     defp = look_id( "__GNUC__");    /* Already defined by init_defines()    */
461     gcc_maj_ver = atoi( defp->repl);
462     defp = look_id( "__GNUC_MINOR__");
463     gcc_min_ver = atoi( defp->repl);
464     integrated_cpp = ((gcc_maj_ver == 3 && gcc_min_ver >= 3)
465             || gcc_maj_ver == 4);
466 #endif
467 #if COMPILER == GNUC || COMPILER == MSC
468     option_flags.dollar_in_name = TRUE;
469     /* GCC and Visual C allows '$' in name by default   */
470 #endif
471 
472     set_opt_list( optlist);
473 
474 opt_search: ;
475     while (mcpp_optind < argc
476             && (opt = mcpp_getopt( argc, argv, optlist)) != EOF) {
477 
478         switch (opt) {          /* Command line option character    */
479 
480 #if COMPILER == GNUC
481         case '$':                       /* Forbid '$' in identifier */
482             option_flags.dollar_in_name = FALSE;
483             break;
484 #endif
485 
486         case '+':
487 #if COMPILER == GNUC
488 plus:
489 #endif
490             if (cplus_val || sflag) {
491                 mcpp_fputs( "warning: -+ option is ignored\n", ERR);
492                 break;
493             }
494             cplus_val = CPLUS;
495             break;
496 #if COMPILER == GNUC
497         case '-':
498             if (memcmp( mcpp_optarg, "sysroot", 7) == 0) {
499                 if (mcpp_optarg[ 7] == '=')             /* --sysroot=DIR    */
500                     sysroot = mcpp_optarg + 8;
501                 else if (mcpp_optarg[ 7] == EOS)        /* --sysroot DIR    */
502                     sysroot = argv[ mcpp_optind++];
503                 else
504                     usage( opt);
505                 break;
506             } else {
507                 usage( opt);
508             }
509 #endif
510         case '2':                   /* Reverse digraphs recognition */
511             option_flags.dig = ! option_flags.dig;
512             break;
513         case '3':                   /* Reverse trigraph recogniion  */
514             option_flags.trig = ! option_flags.trig;
515             break;
516 
517         case '@':                   /* Special preprocessing mode   */
518             old_mode = mcpp_mode;
519             if (str_eq( mcpp_optarg, "post")
520                     || str_eq( mcpp_optarg, "poststd"))
521                 mcpp_mode = POST_STD;   /* 'post-Standard' mode     */
522             else if (str_eq( mcpp_optarg, "old")
523                     || str_eq( mcpp_optarg, "oldprep"))
524                 mcpp_mode = OLD_PREP;   /* 'old-Preprocessor' mode  */
525             else if (str_eq( mcpp_optarg, "kr"))
526                 mcpp_mode = KR;         /* 'K&R 1st' mode           */
527             else if (str_eq( mcpp_optarg, "std"))
528                 mcpp_mode = STD;        /* 'Standard' mode (default)*/
529             else if (str_eq( mcpp_optarg, "compat")) {
530                 compat_mode = TRUE;     /* 'compatible' mode        */
531                 mcpp_mode = STD;
532             }
533             else
534                 usage( opt);
535             standard = (mcpp_mode == STD || mcpp_mode == POST_STD);
536             if (old_mode != STD && old_mode != mcpp_mode)
537                 mcpp_fprintf( ERR, "Mode is redefined to: %s\n", mcpp_optarg);
538             break;
539 
540 #if COMPILER == GNUC
541         case 'A':       /* Ignore -A system(gnu), -A cpu(vax) or so */
542             break;
543         case 'a':
544             if (str_eq( mcpp_optarg, "nsi")) {      /* -ansi                */
545                 look_and_install( "__STRICT_ANSI__", DEF_NOARGS_PREDEF, null
546                         , "1");
547                 ansi = TRUE;
548                 break;
549             } else if (memcmp( mcpp_optarg, "uxbase", 6) == 0) {
550                 mcpp_optind++;
551                 break;  /* Ignore '-auxbase some' or such nonsence  */
552 #if SYSTEM == SYS_MAC
553             } else if (str_eq( mcpp_optarg, "rch")) {   /* -arch    */
554                 strcpy( arch, argv[ mcpp_optind++]);
555                 if (str_eq( arch, "ppc") || str_eq( arch, "ppc7400")
556                         || str_eq( arch, "ppc64")
557                         || str_eq( arch, "i386") || str_eq( arch, "i686")
558                         || str_eq( arch, "x86_64") || str_eq( arch, "amd64")) {
559                     if (str_eq( arch, "i686"))
560                         strcpy( arch, "i386");
561                     else if (str_eq( arch, "amd64"))
562                         strcpy( arch, "x86_64");
563                     else if (str_eq( arch, "ppc7400"))
564                         strcpy( arch, "ppc");
565                     break;
566                 }   /* Else usage() */
567 #endif
568             }
569             usage( opt);
570 #elif   COMPILER == MSC
571         case 'a':
572             if (memcmp( mcpp_optarg, "rch", 3) == 0) {
573                 if (str_eq( mcpp_optarg + 3, ":SSE")        /* -arch:SSE    */
574                         || str_eq( mcpp_optarg + 3, ":sse"))
575                     sse = 1;
576                 else if (str_eq( mcpp_optarg + 3, ":SSE2")  /* -arch:SSE2   */
577                         || str_eq( mcpp_optarg + 3, ":sse2"))
578                     sse = 2;
579                 /* Else ignore  */
580             } else {
581                 usage( opt);
582             }
583             break;
584 
585         case 'A':
586             option_flags.lang_asm = TRUE;   /* "assembler" source   */
587             break;
588 #else
589         case 'a':
590             option_flags.lang_asm = TRUE;   /* "assembler" source   */
591             break;
592 #endif
593 
594 #if ! STD_LINE_PREFIX
595         case 'b':
596             std_line_prefix = TRUE; /* Putout line and file infor-  */
597             break;                  /*   mation in C source style.  */
598 #endif
599 
600         case 'C':                           /* Keep comments        */
601             option_flags.c = TRUE;
602             break;
603 
604 #if COMPILER == GNUC
605         case 'c':
606             if (! integrated_cpp)
607                 usage( opt);
608             break;                  /* Else ignore this option      */
609         case 'd':
610             if (str_eq( mcpp_optarg, "M")) {                /* -dM          */
611                 dMflag = TRUE;
612                 no_output++;
613             } else if (str_eq( mcpp_optarg, "D")) {         /* -dD          */
614                 dDflag = TRUE;
615             } else if (str_eq( mcpp_optarg, "igraphs")) {   /* -digraphs    */
616                 option_flags.dig = TRUE;
617             } else if (str_eq( mcpp_optarg, "umpbase")) {   /* -dumpbase    */
618                 ;                                           /* Ignore       */
619             } else {
620                 usage( opt);
621             }
622             break;
623 #endif  /* COMPILER == GNUC */
624 
625         case 'D':                           /* Define symbol        */
626             if (def_cnt >= MAX_DEF) {
627                 mcpp_fputs( "Too many -D options.\n", ERR);
628                 longjmp( error_exit, -1);
629             }
630             def_list[ def_cnt++] = mcpp_optarg;
631             break;
632 
633         case 'e':
634             /* Change the default MBCHAR encoding   */
635             if (set_encoding( mcpp_optarg, FALSE, 0) == NULL)
636                 usage( opt);
637             mb_changed = TRUE;
638             break;
639 
640 #if COMPILER == GNUC
641         case 'E':
642             if (! integrated_cpp)
643                 usage( opt);
644             break;                          /* Ignore this option   */
645         case 'f':
646             if (memcmp( mcpp_optarg, "input-charset=", 14) == 0) {
647                 /* Treat -finput-charset= as the same option as -e  */
648                 if (set_encoding( mcpp_optarg + 14, FALSE, 0) == NULL)
649                     usage( opt);
650                 mb_changed = TRUE;
651             } else if (str_eq( mcpp_optarg, "working-directory")) {
652                 gcc_work_dir = TRUE;
653             } else if (str_eq( mcpp_optarg, "no-working-directory")) {
654                 gcc_work_dir = FALSE;
655             } else if (str_eq( mcpp_optarg, "stack-protector")) {
656                 look_and_install( "__SSP__", DEF_NOARGS_PREDEF, null, "1");
657             } else if (str_eq( mcpp_optarg, "stack-protector-all")) {
658                 look_and_install( "__SSP_ALL__", DEF_NOARGS_PREDEF, null, "2");
659             } else if (str_eq( mcpp_optarg, "exceptions")) {
660                 look_and_install( "__EXCEPTIONS", DEF_NOARGS_PREDEF, null
661                         , "1");
662             } else if (str_eq( mcpp_optarg, "no-exceptions")) {
663                 undef_list[ undef_cnt++] = "__EXCEPTIONS";
664             } else if (str_eq( mcpp_optarg, "PIC")
665                     || str_eq( mcpp_optarg, "pic")
666                     || str_eq( mcpp_optarg, "PIE")
667                     || str_eq( mcpp_optarg, "pie")) {
668                 look_and_install( "__PIC__", DEF_NOARGS_PREDEF, null, "1");
669                 look_and_install( "__pic__", DEF_NOARGS_PREDEF, null, "1");
670             } else if (str_eq( mcpp_optarg, "no-dollars-in-identifiers")) {
671                 option_flags.dollar_in_name = FALSE;
672             } else if (str_eq( mcpp_optarg, "no-show-column")) {
673                 ;                           /* Ignore this option   */
674             } else if (! integrated_cpp) {
675                 usage( opt);
676             }
677             break;
678 
679         case 'g':
680             if (!isdigit( *mcpp_optarg)
681                     && str_eq( argv[ mcpp_optind - 2], "-g"))
682                 /* Neither '-g 0' nor '-ggdb' -- No argument    */
683                 mcpp_optind--;
684             break;                          /* Ignore the option    */
685 #elif COMPILER == LCC
686         case 'g':               /* Define __LCCDEBUGLEVEL as <n>    */
687             if (*(mcpp_optarg + 1) == EOS && isdigit( *mcpp_optarg)) {
688                 defp = look_id( debug_name);
689                 strcpy( defp->repl, mcpp_optarg);
690             } else {
691                 usage( opt);
692             }
693             break;
694 #elif COMPILER == MSC
695         case 'G':
696             if (*(mcpp_optarg + 1) == EOS) {    /* -Gx              */
697                 switch (*mcpp_optarg) {
698                 case '3':   case '4':   case '5':   case '6':
699                     gval = *mcpp_optarg;
700                     break;
701                 case 'B':                   /* -GB                  */
702                     gval = '6';
703                     break;
704                 case 'R':
705                     look_and_install( "_CPPRTTI", DEF_NOARGS_PREDEF, null
706                             , "1");
707                     break;
708                 case 'X':
709                     look_and_install( "_CPPUNWIND", DEF_NOARGS_PREDEF, null
710                             , "1");
711                     break;
712                 case 'Z':
713                     look_and_install( "__MSVC_RUNTIME_CHECKS"
714                             , DEF_NOARGS_PREDEF, null, "1");
715                     break;
716                 default :
717                     mcpp_fprintf( ERR, warning, opt, mcpp_optarg);
718                 }
719             } else {
720                 usage( opt);
721             }
722             break;
723 #endif
724 
725 #if SYSTEM == SYS_MAC
726         case 'F':
727             framework[ num_framework++] = mcpp_optarg;
728             break;
729 #endif
730 
731         case 'h':
732             if (*(mcpp_optarg + 1) == EOS && isdigit( *mcpp_optarg))
733                 /* a digit  */
734                 look_and_install( "__STDC_HOSTED__", DEF_NOARGS_PREDEF, null
735                         , mcpp_optarg);
736             else
737                 usage( opt);
738             break;
739 
740 #if COMPILER == MSC
741         case 'X':
742                 unset_sys_dirs = TRUE;
743                 break;
744 #endif
745         case 'I':                           /* Include directory    */
746             if (str_eq( mcpp_optarg, "-")) {        /* -I-                  */
747 #if COMPILER == GNUC
748                 sys_dirp = incend;  /* Split include directories    */
749                 i_split = TRUE;
750 #else
751                 unset_sys_dirs = TRUE;
752                         /* Unset pre-specified include directories  */
753 #endif
754             } else if (*(mcpp_optarg + 1) == EOS && isdigit( *mcpp_optarg)
755                     && (i = *mcpp_optarg - '0') != 0
756                     && (i & ~(CURRENT | SOURCE)) == 0) {
757                 search_rule = i;            /* -I1, -I2 or -I3      */
758             } else {                        /* Not '-' nor a digit  */
759                 set_a_dir( mcpp_optarg);    /* User-defined dir     */
760             }
761             break;
762 
763 #if COMPILER == MSC
764         case 'F':
765             if (str_eq( mcpp_optarg, "l")) {        /* -Fl          */
766                 if (preinc_end >= &preinclude[ NPREINCLUDE]) {
767                     mcpp_fputs( "Too many -Fl options.\n", ERR);
768                     longjmp( error_exit, -1);
769                 }
770                 *preinc_end++ = argv[ mcpp_optind++];
771             } else {
772                 usage( opt);
773             }
774             break;
775 #endif
776 
777 #if COMPILER == GNUC
778         case 'i':
779             if (str_eq( mcpp_optarg, "nclude")) {   /* -include     */
780                 if (preinc_end >= &preinclude[ NPREINCLUDE]) {
781                     mcpp_fputs( "Too many -include options.\n", ERR);
782                     longjmp( error_exit, -1);
783                 }
784                 *preinc_end++ = argv[ mcpp_optind++];
785             } else if (str_eq( mcpp_optarg, "system")) {    /* -isystem     */
786                 if (sysdir_end >= &sysdir[ NSYSDIR]) {
787                     mcpp_fputs( "Too many -isystem options.\n", ERR);
788                     longjmp( error_exit, -1);
789                 }
790                 *sysdir_end++ = argv[ mcpp_optind++];
791                 /* Add the directory before system include directory*/
792             } else if (str_eq( mcpp_optarg, "quote")) {     /* -iquote      */
793                 if (quote_dir_end >= &quote_dir[ N_QUOTE_DIR]) {
794                     mcpp_fputs( "Too many -iquote options.\n", ERR);
795                     longjmp( error_exit, -1);
796                 }
797                 *quote_dir_end++ = argv[ mcpp_optind++];
798                 /* Add the directory for #include "header"          */
799             } else if (memcmp( mcpp_optarg, "sysroot", 7) == 0) {
800                 if (mcpp_optarg[ 7] == '=')     /* -isysroot=DIR    */
801                     sysroot = mcpp_optarg + 8;
802                 else if (mcpp_optarg[ 7] == EOS)        /* -isysroot DIR    */
803                     sysroot = argv[ mcpp_optind++];
804                 else
805                     usage( opt);
806             } else if (str_eq( mcpp_optarg, "prefix")       /* -iprefix     */
807                     || str_eq( mcpp_optarg, "withprefix")   /* -iwithprefix */
808                     || str_eq( mcpp_optarg, "withprefixbefore")
809                                             /* -iwithprefixbefore   */
810                     || str_eq( mcpp_optarg, "dirafter")     /* -idirafter   */
811                     || str_eq( mcpp_optarg, "multilib")) {  /* -imultilib   */
812                 mcpp_optind++;              /* Skip the argument    */
813                 /* Ignore these options */
814             } else {
815                 usage( opt);
816             }
817             break;
818 #endif
819 
820         case 'j':
821             option_flags.no_source_line = TRUE;
822             break;  /* Do not output the source line in diagnostics */
823 
824 #if COMPILER == MSC
825         case 'J':
826             look_and_install( "_CHAR_UNSIGNED", DEF_NOARGS_PREDEF, null, "1");
827             break;
828 #endif
829 
830         case 'K':
831             mcpp_debug |= MACRO_CALL;
832             /*
833              * Putout macro expansion informations embedded in comments.
834              * Same with '#pragma MCPP debug macro_call'.
835              */
836             /* Enable white spaces preservation, too    */
837             /* Fall through */
838         case 'k':
839             option_flags.k = TRUE;
840             /* Keep white spaces of input lines as they are */
841             break;
842 
843 #if COMPILER == GNUC
844         case 'l':
845             if (memcmp( mcpp_optarg, "ang-", 4) != 0) {
846                 usage( opt);
847             } else if (str_eq( mcpp_optarg + 4, "c")) {     /* -lang-c  */
848                 ;                           /* Ignore this option   */
849             } else if (str_eq( mcpp_optarg + 4, "c99")      /* -lang-c99*/
850                         || str_eq( mcpp_optarg + 4, "c9x")) {   /* -lang-c9x*/
851                 if (! sflag) {
852                     stdc_val = 1;           /* Define __STDC__ to 1 */
853                     std_val = 199901L;
854                     sflag = TRUE;
855                 }
856             } else if (str_eq( mcpp_optarg + 4, "c89")) {   /* -lang-c89*/
857                 if (! sflag) {
858                     stdc_val = 1;           /* Define __STDC__ to 1 */
859                     sflag = TRUE;
860                 }
861             } else if (str_eq( mcpp_optarg + 4, "c++")) {   /* -lang-c++*/
862                 goto  plus;
863             } else if (str_eq( mcpp_optarg + 4, "asm")) {   /* -lang-asm*/
864                 option_flags.lang_asm = TRUE;
865             } else {
866                 usage( opt);
867             }
868             break;
869 #endif  /* COMPILER == GNUC */
870 
871         case 'M':           /* Output source file dependency line   */
872             if (str_eq( mcpp_optarg, "M")) {                /* -MM  */
873                 ;
874             } else if (str_eq( mcpp_optarg, "D")) {         /* -MD  */
875                 mkdep |= (MD_SYSHEADER | MD_FILE);
876             } else if (str_eq( mcpp_optarg, "MD")) {         /* -MMD */
877                 mkdep |= MD_FILE;
878             } else if (str_eq( mcpp_optarg, "P")) {          /* -MP  */
879                 mkdep |= MD_PHONY;
880             } else if (str_eq( mcpp_optarg, "Q")) {  /* -MQ target   */
881                 mkdep |= MD_QUOTE;
882                 mkdep_mq = argv[ mcpp_optind++];
883             } else if (str_eq( mcpp_optarg, "T")) {  /* -MT target   */
884                 mkdep_mt = argv[ mcpp_optind++];
885             } else if (str_eq( mcpp_optarg, "F")) {  /* -MF file     */
886                 mkdep_mf = argv[ mcpp_optind++];
887             } else if (argv[ mcpp_optind - 1] == mcpp_optarg) {     /* -M   */
888                 mkdep |= MD_SYSHEADER;
889                 mcpp_optind--;
890             } else {
891                 usage( opt);
892             }
893             if (str_eq( mcpp_optarg, "D") || str_eq( mcpp_optarg, "MD")) {
894                 cp = argv[ mcpp_optind];
895                 if (cp && *cp != '-')           /* -MD (-MMD) file  */
896                     mkdep_md = argv[ mcpp_optind++];
897             }
898             mkdep |= MD_MKDEP;
899             break;
900 
901 #if SYS_FAMILY == SYS_UNIX
902         case 'm':
903             if (str_eq( mcpp_optarg, "64")) {               /* -m64 */
904                 if (str_eq( CPU, "i386"))
905                     strcpy( arch, "x86_64");
906                 else if (str_eq( CPU, "ppc"))
907                     strcpy( arch, "ppc64");
908                 /* Else ignore  */
909                 break;
910             } else if (str_eq( mcpp_optarg, "32")) {        /* -m32 */
911                 if (str_eq( CPU, "x86_64"))
912                     strcpy( arch, "i386");
913                 else if (str_eq( CPU, "ppc64"))
914                     strcpy( arch, "ppc");
915                 /* Else ignore  */
916                 break;
917             } else if (str_eq( mcpp_optarg, "mmx")) {   /* -mmmx    */
918                 look_and_install( "__MMX__", DEF_NOARGS_PREDEF, null, "1");
919                 break;
920             } else if (str_eq( mcpp_optarg, "no-mmx")) {    /* -mno-mmx     */
921                 undef_list[ undef_cnt++] = "__MMX__";
922                 break;
923             }
924 #endif  /* SYS_FAMILY == UNIX   */
925 #if COMPILER == GNUC
926 #if SYSTEM == SYS_CYGWIN
927             if (str_eq( mcpp_optarg, "no-cygwin")) {    /* -mno-cygwin      */
928                 no_cygwin = TRUE;
929                 break;
930             }
931 #endif
932             if (! integrated_cpp)
933                 usage( opt);
934             break;
935 
936         case 'u':
937             if (! str_eq( mcpp_optarg, "ndef"))     /* -undef       */
938                 usage( opt);                /* Else fall through    */
939 #endif  /* COMPILER == GNUC */
940 
941 #if COMPILER == MSC
942         case 'u':
943 #endif
944         case 'N':
945             /* No predefines:   remove "unix", "__unix__" and friends.  */
946             nflag = TRUE;
947             break;
948 
949 #if COMPILER == GNUC || NO_DIR
950         case 'n':
951 #if NO_DIR
952             if (str_eq( mcpp_optarg, "odir")) {     /* -nodir       */
953                 no_dir = TRUE;
954             }
955 #endif
956 #if COMPILER == GNUC
957             if (str_eq( mcpp_optarg, "ostdinc")) {  /* -nostdinc    */
958                 unset_sys_dirs = TRUE;  /* Unset pre-specified directories  */
959             } else if (str_eq( mcpp_optarg, "ostdinc++")) { /* -nostdinc++  */
960                 set_cplus_dir = FALSE;  /* Unset C++-specific directories   */
961             } else if (str_eq( mcpp_optarg, "oprecomp")) {  /* -noprecomp   */
962                 mcpp_fprintf( ERR, warning, opt, mcpp_optarg);
963                 break;
964             }
965 #endif
966             else {
967                 usage( opt);
968             }
969             break;
970 #endif
971 
972 #if COMPILER == GNUC
973         case 'O':
974             if (integrated_cpp) {
975                 if (*mcpp_optarg == '-')            /* No argument  */
976                     mcpp_optind--;
977                 else if ((isdigit( *mcpp_optarg) && *mcpp_optarg != '0')
978                         || *mcpp_optarg == 's' || *mcpp_optarg == 'z')
979                                             /* -O1, -O2 -Os, -Oz    */
980                     look_and_install( "__OPTIMIZE__", DEF_NOARGS_PREDEF, null
981                             , "1");
982                 else if (! isdigit( *mcpp_optarg))
983                     usage( opt);
984                 /* Else -O0: ignore */
985             } else {
986                 usage( opt);
987             }
988             break;                  /* Else ignore -Ox option       */
989 #elif COMPILER == LCC
990         case 'O':                   /* Define __LCCOPTIMLEVEL as 1  */
991             defp = look_id( optim_name);
992             strcpy( defp->repl, "1");
993             break;
994 #endif
995 
996         case 'o':
997             *out_pp = mcpp_optarg;          /* Output file name     */
998             break;
999 
1000         case 'P':                           /* No #line output      */
1001             option_flags.p = TRUE;
1002             break;
1003 
1004 #if COMPILER == GNUC
1005         case 'p':
1006             if (str_eq( mcpp_optarg, "edantic")     /* -pedantic    */
1007                     || str_eq( mcpp_optarg, "edantic-errors")) {
1008                                             /* -pedantic-errors     */
1009                 /* This option does not imply -ansi */
1010                 if (warn_level == -1)
1011                     warn_level = 0;
1012                 warn_level |= (1 | 2 | 4);
1013                 if (! sflag && ! cplus_val) {
1014                     stdc_val = 1;
1015                     sflag = TRUE;
1016                 }
1017             } else {
1018                 usage( opt);
1019             }
1020             break;
1021         case 'q':
1022             if (str_eq( mcpp_optarg, "uiet"))
1023                 /* -quiet: GCC's undocumented, yet frequently specified opt */
1024                 break;                      /* Ignore the option    */
1025             else
1026                 usage( opt);
1027             break;
1028 #endif  /* COMPILER == GNUC */
1029 
1030         case 'Q':
1031             option_flags.q = TRUE;
1032             break;
1033 
1034 #if COMPILER == MSC
1035         case 'R':               /* -RTC1, -RTCc, -RTCs, -RTCu, etc. */
1036             if (memcmp( mcpp_optarg, "TC", 2) == 0
1037                     && *(mcpp_optarg + 2) != EOS)
1038                 look_and_install( "__MSVC_RUNTIME_CHECKS", DEF_NOARGS_PREDEF
1039                         , null, "1");
1040             else
1041                 usage( opt);
1042             break;
1043 #endif
1044 
1045         case 'S':
1046             if (cplus_val || sflag) {   /* C++ or the second time   */
1047                 mcpp_fprintf( ERR, warning, opt, mcpp_optarg);
1048                 break;
1049             }
1050             i = *mcpp_optarg;
1051             if (! isdigit( i) || *(mcpp_optarg + 1) != EOS)
1052                 usage( opt);
1053             stdc_val = i - '0';
1054             sflag = TRUE;
1055             break;
1056 
1057 #if COMPILER == GNUC
1058         case 'r':
1059             if (str_eq( mcpp_optarg, "emap"))
1060                 mcpp_fprintf( ERR, warning, opt, mcpp_optarg);
1061                                             /* Ignore -remap option */
1062             else
1063                 usage( opt);
1064             break;
1065 
1066         case 's':
1067             if (memcmp( mcpp_optarg, "td=", 3) == 0
1068                     && strlen( mcpp_optarg) > 3) {  /* -std=STANDARD*/
1069                 cp = mcpp_optarg + 3;
1070                 if (str_eq( cp, "c89")              /* std=c89      */
1071                         || str_eq( cp, "c90")       /* std=c90      */
1072                         || str_eq( cp, "gnu89")     /* std=gnu89    */
1073                         || str_eq( cp, "iso9899:1990")) {
1074                     std_val = 0L;               /* C90 + extensions */
1075                 } else if (str_eq( cp, "c99")       /* std=c99      */
1076                         || str_eq( cp, "c9x")       /* std=c9x      */
1077                         || str_eq( cp, "gnu99")     /* std=gnu99    */
1078                         || str_eq( cp, "gnu9x")     /* std=gnu9x    */
1079                         || str_eq( cp, "iso9899:1999")
1080                         || str_eq( cp, "iso9899:199x")) {
1081                     std_val = 199901L;
1082                 } else if (str_eq( cp, "c++98")) {  /* std=c++98    */
1083                     cplus_val = std_val = 199711L;
1084                 } else if (memcmp( cp, "iso9899:", 8) == 0
1085                         && strlen( cp) >= 14) { /* std=iso9899:199409, etc. */
1086                     mcpp_optarg = cp + 8;
1087                     look_and_install( "__STRICT_ANSI__", DEF_NOARGS_PREDEF
1088                             , null, "1");
1089                     ansi = TRUE;
1090                     goto Version;
1091                 } else if (memcmp( cp, "iso14882", 8) == 0) {
1092                     cp += 8;
1093                     ansi = TRUE;
1094                     if (cp && *cp == ':' && strlen( cp) >= 7) {
1095                                     /* std=iso14882:199711, etc.    */
1096                         cplus_val = CPLUS;
1097                         mcpp_optarg = cp + 1;
1098                         goto Version;
1099                     } else {
1100                         goto plus;
1101                     }
1102                 } else {
1103                     usage( opt);
1104                 }
1105                 if (! cplus_val && memcmp( cp, "gnu", 3) != 0) {
1106                     /* 'std=gnu*' does not imply -ansi  */
1107                     look_and_install( "__STRICT_ANSI__", DEF_NOARGS_PREDEF
1108                             , null, "1");
1109                     ansi = TRUE;
1110                 }
1111                 stdc_val = 1;
1112                 sflag = TRUE;
1113             } else {
1114                 usage( opt);
1115             }
1116             break;
1117 
1118         case 't':
1119             if (str_eq( mcpp_optarg, "raditional")
1120                     || str_eq( mcpp_optarg, "raditional-cpp")) {
1121                                 /* -traditional, -traditional-cpp   */
1122                 trad = TRUE;
1123                 mcpp_mode = OLD_PREP;
1124             } else if (str_eq( mcpp_optarg, "rigraphs")) {
1125                 option_flags.trig = TRUE;           /* -trigraphs   */
1126             } else {
1127                 usage( opt);
1128             }
1129             break;
1130 #endif  /* COMPILER == GNUC */
1131 
1132 #if COMPILER == MSC
1133         case 'T':
1134             if (strlen( mcpp_optarg) > 1)
1135                 usage( opt);
1136             i = tolower( *mcpp_optarg);             /* Fold case    */
1137             if (i == 'c') {
1138                 ;                           /* Ignore this option   */
1139             } else if (i == 'p') {
1140                 cplus_val = CPLUS;
1141             } else {
1142                 usage( opt);
1143             }
1144             break;
1145 #endif
1146 
1147         case 'U':                           /* Undefine macro       */
1148             if (undef_cnt >= MAX_UNDEF) {
1149                 mcpp_fputs( "Too many -U options.\n", ERR);
1150                 longjmp( error_exit, -1);
1151             }
1152             undef_list[ undef_cnt++] = mcpp_optarg;
1153             break;
1154 
1155         case 'V':
1156 #if COMPILER == GNUC
1157 Version:
1158 #endif
1159             valp = eval_num( mcpp_optarg);
1160             if (valp->sign == VAL_ERROR)
1161                 usage( opt);
1162             std_val = (long) valp->val;
1163             break;
1164 
1165         case 'v':
1166             option_flags.v = TRUE;
1167             show_path = TRUE;
1168             break;
1169 
1170         case 'W':                           /* warning level        */
1171             if (warn_level == -1)           /* Have to initialize   */
1172                 warn_level = 0;
1173 #if COMPILER == GNUC
1174             if (argv[ mcpp_optind - 1] == mcpp_optarg) {    /* No argument  */
1175                 /*
1176                  * Note: -W without argument is not officially supported.
1177                  *  It may cause an error.
1178                  */
1179                 warn_level |= (1 | 2 | 4 | 16);
1180                 mcpp_optind--;
1181             } else if (str_eq( mcpp_optarg, "comment")
1182                         || str_eq( mcpp_optarg, "comments")
1183                         || str_eq( mcpp_optarg, "sign-compare")) {
1184                 warn_level |= 1;
1185             } else if (str_eq( mcpp_optarg, "undef")) {
1186                 warn_level |= 4;
1187             } else if (str_eq( mcpp_optarg, "all")) {
1188                 warn_level |= (1 | 16);     /* Convert -Wall to -W17*/
1189             } else if (str_eq( mcpp_optarg, "trigraphs")) {
1190                 warn_level |= 16;
1191             }
1192 #endif  /* COMPILER == GNUC */
1193 #if COMPILER == MSC
1194             if (str_eq( mcpp_optarg, "all")) {
1195                 warn_level |= (1 | 16);     /* Convert -Wall to -W17*/
1196             } else if (str_eq( mcpp_optarg, "L")) {
1197                 option_flags.no_source_line = TRUE;
1198                                         /* Single-line diagnostic   */
1199             }
1200 #endif
1201             if (isdigit( *mcpp_optarg)) {
1202                 warn_level |= parse_warn_level( mcpp_optarg, opt);
1203                 if (warn_level > 31 || warn_level < 0)
1204                     usage( opt);
1205             }
1206             if (warn_level == 0)
1207                 warn_level = 0xFF;          /* Remember this option */
1208             /* Else ignore the option   */
1209             break;
1210 
1211 #if COMPILER == GNUC || COMPILER == MSC
1212         case 'w':                           /* Same as -W0          */
1213             warn_level = 0xFF;              /* Remenber this option */
1214             break;
1215 #endif
1216 
1217 #if COMPILER == GNUC
1218         case 'x':
1219             if (str_eq( mcpp_optarg, "c")) {
1220                 break;                      /* -x c -- ignore this  */
1221             } else if (str_eq( mcpp_optarg, "c++")) {
1222                 goto plus;
1223             } else if (str_eq( mcpp_optarg, "assembler-with-cpp")) {
1224                 option_flags.lang_asm = TRUE;
1225                 break;
1226             } else {
1227                 usage( opt);
1228             }
1229             break;
1230 #endif
1231 
1232 #if COMPILER == MSC
1233         case 'Z':
1234             if (str_eq( mcpp_optarg, "c:wchar_t")) {        /* -Zc:wchar_t  */
1235                 look_and_install( "_NATIVE_WCHAR_T_DEFINED", DEF_NOARGS_PREDEF
1236                         , null, "1");
1237                 look_and_install( "_WCHAR_T_DEFINED", DEF_NOARGS_PREDEF, null
1238                         , "1");
1239                 wchar_t_modified = TRUE;
1240             } else if (str_eq( mcpp_optarg, "c:wchar_t-")) {/* -Zc:wchar_t- */
1241                 wchar_t_modified = TRUE;        /* Do not define the macros */
1242             } else if (str_eq( mcpp_optarg, "l")) {
1243                 look_and_install( "_VC_NODEFAULTLIB", DEF_NOARGS_PREDEF, null
1244                         , "1");
1245             } else if (str_eq( mcpp_optarg, "a")) {         /* -Za  */
1246                 undefine( "_MSC_EXTENSIONS");
1247                 option_flags.dollar_in_name = FALSE;
1248             } else if (str_eq( mcpp_optarg, "e")) {
1249                 /* Ignore -Ze silently  */
1250                 break;
1251             } else if (*(mcpp_optarg + 1) == EOS) {
1252                 /* -Z followed by one char  */
1253                 mcpp_fprintf( ERR, warning, opt, mcpp_optarg);
1254                 /* Ignore the option with warning   */
1255             } else {
1256                 usage( opt);
1257             }
1258             break;
1259 #endif
1260 
1261         case 'z':
1262             option_flags.z = TRUE;  /* No output of included file   */
1263             break;
1264 
1265         default:                            /* What is this one?    */
1266             usage( opt);
1267             break;
1268         }                               /* Switch on all options    */
1269 
1270     }                                   /* For all arguments        */
1271 
1272     if (mcpp_optind < argc && set_files( argc, argv, in_pp, out_pp) != NULL)
1273         goto  opt_search;       /* More options after the filename  */
1274 
1275     /* Check consistency of specified options, set some variables   */
1276     chk_opts( sflag, trad);
1277 
1278     if (warn_level == -1)               /* No -W option             */
1279         warn_level = 1;                 /* Default warning level    */
1280     else if (warn_level == 0xFF)
1281         warn_level = 0;                 /* -W0 has high precedence  */
1282 
1283 #if SYSTEM == SYS_MAC
1284     set_a_dir( NULL);                       /* Initialize incdir[]  */
1285     to_search_framework = incend;
1286                         /* Search framework[] next to the directory */
1287 #endif
1288 
1289 #if COMPILER == GNUC && SYSTEM == SYS_MAC
1290     if (arch[ 0]) {             /* -arch option has been specified  */
1291         if (((str_eq( CPU, "i386") || str_eq( CPU, "x86_64"))
1292                 && (! str_eq( arch, "i386") && ! str_eq( arch, "x86_64")))
1293             || ((str_eq( CPU, "ppc") || str_eq( CPU, "ppc64"))
1294                 && (! str_eq( arch, "ppc") && ! str_eq( arch, "ppc64")))) {
1295             mcpp_fprintf( ERR, "Wrong argument of -arch option: %s\n", arch);
1296             longjmp( error_exit, -1);
1297         }
1298     }
1299 #endif
1300     if (! arch[ 0]) {
1301         /* None of -arch, -m32 or -m64 options has been specified.  */
1302         /* The CPU-specific-macros will be defined in init_cpu_macro(). */
1303         strcpy( arch, CPU);
1304     }
1305 #if COMPILER != GNUC
1306     init_cpu_macro( gval, sse);
1307 #endif
1308 
1309 #if COMPILER == GNUC
1310     if (sysdir < sysdir_end) {
1311         char **     dp = sysdir;
1312         if (! sys_dirp || sys_dirp == incdir)
1313             sys_dirp = dp;
1314         while (dp < sysdir_end)
1315             set_a_dir( *dp++);
1316     }
1317     if (*in_pp && str_eq( (*in_pp) + strlen( *in_pp) - 2, ".S"))
1318         option_flags.lang_asm = TRUE;   /* Input file name is *.S   */
1319     if (option_flags.lang_asm) {
1320         look_and_install( "__ASSEMBLER__", DEF_NOARGS_PREDEF, null, "1");
1321         option_flags.dollar_in_name = FALSE;        /* Disable '$' in name  */
1322     }
1323     if (! sys_dirp || sys_dirp == incdir)
1324         sys_dirp = incend;
1325 #endif
1326 #if SYSTEM == SYS_MAC
1327     init_framework();                   /* After setting sys_dirp   */
1328 #endif
1329     set_env_dirs();
1330     if (! unset_sys_dirs)
1331         set_sys_dirs( set_cplus_dir);
1332 
1333     if (mkdep_mf) {                         /* -MF overrides -MD    */
1334         mkdep_fp = fopen( mkdep_mf, "w");
1335     } else if (mkdep_md) {
1336         mkdep_fp = fopen( mkdep_md, "w");
1337     }
1338     if (mkdep_mq)                           /* -MQ overrides -MT    */
1339         mkdep_target = mkdep_mq;
1340     else if (mkdep_mt)
1341         mkdep_target = mkdep_mt;
1342 
1343     /* Normalize the path-list  */
1344     if (*in_pp && ! str_eq( *in_pp, "-")) {
1345         char *  tmp = norm_path( null, *in_pp, FALSE, FALSE);
1346         if (tmp)                        /* The file exists          */
1347             *in_pp = tmp;
1348             /* Else mcpp_main() will diagnose *in_pp and exit   */
1349     }
1350     if (! (mcpp_debug & MACRO_CALL)) {
1351         /* -K option alters behavior of -v option   */
1352         if (option_flags.v)
1353             version();
1354         if (show_path) {
1355             fp_debug = stderr;
1356             dump_path();
1357             fp_debug = stdout;
1358         }
1359     }
1360 }
1361 
version(void)1362 static void version( void)
1363 /*
1364  * Print version message.
1365  */
1366 {
1367     const char *    mes[] = {
1368 
1369 #if     MCPP_LIB
1370 /* Write messages here, for example, "MySomeTool with ".    */
1371 #endif
1372 
1373 #ifdef  VERSION_MSG
1374         "MCPP V.2.7.2 (2008/11) "
1375 #else
1376         "MCPP V.", VERSION, " (", DATE, ") "
1377 #endif
1378 #if     COMPILER == INDEPENDENT
1379             , "compiler-independent-build "
1380 #else
1381 #ifdef  CMP_NAME
1382             , "for ", CMP_NAME, " "
1383 #endif
1384 #endif
1385             , "compiled by "
1386 #ifdef  VERSION_MSG
1387             , VERSION_MSG
1388 #else
1389 #ifdef  HOST_CMP_NAME
1390             , HOST_CMP_NAME
1391 #if     HOST_COMPILER == GNUC
1392             , " V.", GCC_MAJOR_VERSION, ".", GCC_MINOR_VERSION
1393 #endif
1394 #endif
1395 #endif
1396             , "\n",
1397             NULL
1398         };
1399 
1400     const char **   mpp = mes;
1401     while (*mpp)
1402         mcpp_fputs( *mpp++, ERR);
1403 }
1404 
usage(int opt)1405 static void usage(
1406     int     opt
1407 )
1408 /*
1409  * Print usage.
1410  */
1411 {
1412     const char *     mes[] = {
1413 
1414 "Usage:  ",
1415 "mcpp",
1416 " [-<opts> [-<opts>]] [<infile> [-<opts>] [<outfile>] [-<opts>]]\n",
1417 "    <infile> defaults to stdin and <outfile> defaults to stdout.\n",
1418 
1419 "\nCommonly used options:\n",
1420 
1421 "-@MODE      Specify preprocessing mode. MODE should be one of these 4:\n",
1422 "    -@std               Standard conforming mode. (default)\n",
1423 "    -@poststd, -@post   special 'post-Standard' mode.\n",
1424 "    -@kr                K&R 1st mode.\n",
1425 "    -@oldprep, -@old    'old_preprocessor' mode (i.e. 'Reiser model' cpp).\n",
1426 
1427 #if COMPILER == MSC
1428 "-arch:SSE, -arch:SSE2   Define the macro _M_IX86_FP as 1, 2 respectively.\n",
1429 #endif
1430 #if SYSTEM == SYS_MAC && COMPILER == GNUC
1431 "-arch <arch>        Change the target to <arch> (i386, x86_64, ppc, ppc64).\n",
1432 #endif
1433 
1434 #if ! STD_LINE_PREFIX
1435 "-b          Output #line lines in C source style.\n",
1436 #endif
1437 
1438 "-C          Output also comments.\n",
1439 "-D <macro>[=<value>]    Define <macro> as <value> (default:1).\n",
1440 "-D <macro(args)>[=<replace>]    Define <macro(args)> as <replace>.\n",
1441 "-e <encoding>   Change the default multi-byte character encoding to one of:\n",
1442 "            euc_jp, gb2312, ksc5601, big5, sjis, iso2022_jp, utf8.\n",
1443 
1444 #if SYSTEM == SYS_MAC
1445 "-F <framework>      Add <framework> to top of framework directory list.\n",
1446 #endif
1447 #if COMPILER == GNUC
1448 "-finput-charset=<encoding>      Same as -e <encoding>.\n",
1449 "            (Don't insert spaces around '=').\n",
1450 #endif
1451 #if COMPILER == MSC
1452 "-Fl <file>  Include the <file> prior to the main input file.\n",
1453 "-G<n>       Define the macro _M_IX86 according to <n>.\n",
1454 #endif
1455 #if COMPILER == LCC
1456 "-g <n>      Define the macro __LCCDEBUGLEVEL as <n>.\n",
1457 #endif
1458 
1459 "-I <directory>      Add <directory> to the #include search list.\n",
1460 
1461 #if COMPILER == GNUC
1462 "-isysroot <dir>     Change root of system header directory to <dir>.\n",
1463 "-include <file>     Include the <file> prior to the main input file.\n",
1464 #else
1465 "-I-         Unset system or site specific include directories.\n",
1466 #endif
1467 #if COMPILER == MSC
1468 "-J          Define the macro _CHAR_UNSIGNED as 1.\n",
1469 #endif
1470 
1471 "-j          Don't output the source line in diagnostics.\n",
1472 "-M, -MM, -MD, -MMD, -MP, -MQ target, -MT target, -MF file\n",
1473 "            Output source file dependency line for makefile.\n",
1474 #if SYS_FAMILY == SYS_UNIX
1475 "-m32        Change target CPU from x86_64, ppc64 to i386, ppc, respectively.\n",
1476 "-m64        Change target CPU from i386, ppc to x86_64, ppc64, respectively.\n",
1477 #endif
1478 "-N          Don't predefine any non-standard macros.\n",
1479 
1480 #if COMPILER == GNUC
1481 "-nostdinc   Unset system or site specific include directories.\n",
1482 #endif
1483 #if COMPILER == LCC
1484 "-O          Define the macro __LCCOPTIMLEVEL as 1.\n",
1485 #endif
1486 
1487 "-o <file>   Output to <file>.\n",
1488 "-P          Don't output #line lines.\n",
1489 "-Q          Output diagnostics to \"mcpp.err\" (default:stderr).\n",
1490 #if COMPILER == MSC
1491 "-RTC*       Define the macro __MSVC_RUNTIME_CHECKS as 1.\n",
1492 #endif
1493 #if COMPILER == GNUC
1494 "-traditional, -traditional-cpp      Same as -@oldprep.\n",
1495 #endif
1496 "-U <macro>  Undefine <macro>.\n",
1497 
1498 #if COMPILER == GNUC
1499 "-undef      Same as -N.\n",
1500 #endif
1501 #if COMPILER == MSC
1502 "-u          Same as -N.\n",
1503 #endif
1504 
1505 "-v          Show version and include directories of mcpp.\n",
1506 "-W <level>  Set warning level to <level> (OR of {0,1,2,4,8,16}, default:1).\n",
1507 
1508 #if COMPILER == MSC
1509 "-WL         Same as -j.\n",
1510 #endif
1511 #if COMPILER == MSC || COMPILER == GNUC
1512 "-w          Same as -W0.\n",
1513 #endif
1514 #if COMPILER == MSC
1515 "-X          Same as -I-.\n",
1516 "-Zc:wchar_t     Define _NATIVE_WCHAR_T_DEFINED and _WCHAR_T_DEFINED as 1.\n",
1517 "-Zl         Define the macro _VC_NODEFAULTLIB as 1.\n",
1518 #endif
1519 
1520 "-z          Don't output the included file, only defining macros.\n",
1521 
1522 "\nOptions available with -@std (default) or -@poststd options:\n",
1523 
1524 "-+          Process C++ source.\n",
1525 
1526 #if DIGRAPHS_INIT
1527 "-2          Disable digraphs.\n",
1528 #else
1529 "-2          Enable digraphs.\n",
1530 #endif
1531 #if COMPILER == GNUC
1532 "-digraphs   Enable digraphs.\n",
1533 #endif
1534 
1535 "-h <n>      Re-define the pre-defined macro __STDC_HOSTED__ as <n>.\n",
1536 
1537 #if COMPILER == GNUC
1538 "-lang-c89   Same as -S1.\n",
1539 "-lang-c++   Same as -+.\n",
1540 "-pedantic, -pedantic-errors     Same as -W7.\n",
1541 "-S <n>      Redefine __STDC__ to <n>.\n",
1542 #else
1543 "-S <n>      Redefine __STDC__ to <n>, undefine old style macros.\n",
1544 #endif
1545 
1546 #if COMPILER == GNUC
1547 "-std=<STANDARD>     Specify the standard to which the code should conform.\n",
1548 "            <STANDARD> may be one of: c90, c99, iso9899:1990, iso14882, etc.\n",
1549 "            iso9899:<n>, iso14882:<n> : Same as -V <n> (long in decimals).\n",
1550 #endif
1551 #if COMPILER == MSC
1552 "-Tp         Same as -+.\n",
1553 #endif
1554 
1555 "-V <n>      Redefine __STDC_VERSION__ or __cplusplus to <n>.\n",
1556 "            C with -V199901L specifies C99 specs.\n",
1557 "            C++ with -V199901L specifies C99 compatible specs.\n",
1558 
1559 #if COMPILER == GNUC
1560 "-x c++      Same as -+.\n",
1561 #endif
1562 
1563 "\nOptions available with only -@std (default) option:\n",
1564 
1565 "-@compat    Expand recursive macro more than Standard.\n",
1566 #if TRIGRAPHS_INIT
1567 "-3          Disable trigraphs.\n",
1568 #else
1569 "-3          Enable trigraphs.\n",
1570 #endif
1571 "-K          Output macro annotations embedding in comments.\n",
1572 #if COMPILER == GNUC
1573 "-trigraphs  Enable trigraphs.\n",
1574 #endif
1575 
1576 "\nOptions available with -@std (default), -@kr or -@oldprep options:\n",
1577 
1578 #if COMPILER == GNUC
1579 "-lang-asm   Same as -x assembler-with-cpp.\n",
1580 "-x assembler-with-cpp   Process \"assembler\" source.\n",
1581 #elif   COMPILER == MSC
1582 "-A          Process \"assembler\" source.\n",
1583 #else
1584 "-a          Process \"assembler\" source.\n",
1585 #endif
1586 
1587 "-k          Keep white spaces of input lines as they are.\n",
1588 
1589 "\nFor further details see mcpp-manual.html.\n",
1590         NULL,
1591     };
1592 
1593     const char *    illegopt = "Incorrect option -%c%s\n";
1594     const char * const *    mpp = mes;
1595 
1596     if (opt != '?')
1597         mcpp_fprintf( ERR, illegopt, opt, mcpp_optarg ? mcpp_optarg : null);
1598     version();
1599 #if MCPP_LIB
1600     mes[ 1] = argv0;
1601 #endif
1602     while (*mpp)
1603         mcpp_fputs( *mpp++, ERR);
1604     longjmp( error_exit, -1);
1605 }
1606 
set_opt_list(char * optlist)1607 static void set_opt_list(
1608     char *  optlist
1609 )
1610 /*
1611  * Set list of legal option characters.
1612  */
1613 {
1614     const char *    list[] = {
1615 
1616 #if ! STD_LINE_PREFIX
1617     "b",
1618 #endif
1619 
1620 #if SYS_FAMILY == SYS_UNIX
1621     "m:",
1622 #endif
1623 
1624 #if COMPILER == GNUC
1625     "$A:a:cd:Ef:g:i:l:r:s:t:u:O:p:q:wx:",
1626 #elif COMPILER == MSC
1627     "Aa:F:G:JR:T:XZ:uw",
1628 #elif   COMPILER == LCC
1629     "g:O",
1630 #endif
1631 
1632 #if COMPILER != GNUC && COMPILER != MSC
1633     "a",
1634 #endif
1635 #if SYSTEM == SYS_MAC
1636     "F:-:",
1637 #endif
1638 
1639     NULL
1640     };
1641 
1642     const char * const *    lp = & list[ 0];
1643 
1644     strcpy( optlist, "23+@:e:h:jkn:o:vzCD:I:KM:NPQS:U:V:W:");
1645                                                 /* Default options  */
1646     while (*lp)
1647         strcat( optlist, *lp++);
1648     if (strlen( optlist) >= OPTLISTLEN)
1649         cfatal( "Bug: Too long option list", NULL, 0L, NULL);       /* _F_  */
1650 }
1651 
parse_warn_level(const char * mcpp_optarg,int opt)1652 static int  parse_warn_level(
1653     const char *    mcpp_optarg,
1654     int     opt
1655 )
1656 /*
1657  * Parse warn level option.
1658  * Warning level option is specified as '19' or '1|2|16' or even '3|16'.
1659  * Even spaces are allowed as ' 1 | 2|16 '.
1660  */
1661 {
1662     const char *    cp = mcpp_optarg;
1663     int             w, i;
1664 
1665     w = i = 0;
1666     while( *cp != EOS) {
1667         while( *cp == ' ')
1668             cp++;                           /* Skip spaces          */
1669         if (! isdigit( *cp))
1670             break;                          /* Error    */
1671         while (isdigit( *cp)) {
1672             i *= 10;
1673             i += (*cp++ - '0');
1674         }
1675         while (*cp == ' ')
1676             cp++;
1677         if (*cp == '|') {       /* Only digits or '|' are allowed   */
1678             w |= i;                         /* Take OR of the args  */
1679             i = 0;
1680             cp++;
1681         }
1682     }
1683     if (*cp != EOS) {               /* Not ending with digit        */
1684         mcpp_fprintf( ERR, "Illegal warning level option \"%s\"\n"
1685                 , mcpp_optarg);
1686         usage( opt);
1687     }
1688     w |= i;                                 /* Take the last arg    */
1689     return  w;
1690 }
1691 
def_a_macro(int opt,char * def)1692 static void def_a_macro(
1693     int     opt,                            /* 'D'  */
1694     char *  def                         /* Argument of -D option    */
1695 )
1696 /*
1697  * Define a macro specified by -D option.
1698  * The macro maybe either object-like or function-like (with parameter).
1699  */
1700 {
1701     DEFBUF *    defp;
1702     char *      definition;             /* Argument of -D option    */
1703     char *      cp;
1704     int         i;
1705 
1706     /* Convert trigraphs for the environment which need trigraphs   */
1707     if (mcpp_mode == STD && option_flags.trig)
1708         cnv_trigraph( def);
1709     if (mcpp_mode == POST_STD && option_flags.dig)
1710         cnv_digraph( def);  /* Convert prior to installing macro    */
1711     definition = xmalloc( strlen( def) + 4);
1712     strcpy( definition, def);
1713     if ((cp = strchr( definition, '=')) != NULL) {
1714         *cp = ' ';                          /* Remove the '='       */
1715         cp = "\n";                          /* Append <newline>     */
1716     } else {
1717         cp = " 1\n";                        /* With definition "1"  */
1718     }
1719     strcat( definition, cp);
1720     cp = definition;
1721     while ((char_type[ *cp & UCHARMAX] & SPA) == 0)
1722         cp++;
1723     i = *cp;
1724     *cp = EOS;
1725     if ((defp = look_id( definition)) != NULL)      /* Pre-defined  */
1726         undefine( definition);
1727     *cp = i;
1728     /* Now, save the definition.    */
1729     unget_string( definition, NULL);
1730     if (do_define( FALSE, 0) == NULL)       /* Define a macro       */
1731         usage( opt);
1732     *cp = EOS;
1733     if (str_eq( definition, "__STDC__")) {
1734         defp = look_id( definition);
1735         defp->nargs = DEF_NOARGS_STANDARD;
1736                                 /* Restore Standard-predefinedness  */
1737     }
1738     free( definition);
1739     skip_nl();                      /* Clear the appended <newline> */
1740 }
1741 
chk_opts(int sflag,int trad)1742 static void     chk_opts(
1743     int     sflag,      /* Flag of Standard or post-Standard mode   */
1744     int     trad                    /* -traditional (GCC only)      */
1745 )
1746 /*
1747  * Check consistency between the specified options.
1748  * Set default value of some variables for each 'mcpp_mode'.
1749  */
1750 {
1751     int     incompat = FALSE;
1752 
1753     switch (mcpp_mode) {
1754     case STD    :
1755     case POST_STD   :
1756         if (trad)
1757             incompat = TRUE;
1758         if (! stdc_val)
1759             stdc_val = STDC;
1760         break;
1761     case KR :
1762     case OLD_PREP   :
1763 #if COMPILER == GNUC
1764         if (sflag || cplus_val || ansi || std_val != -1L)
1765 #else
1766         if (sflag || cplus_val || std_val != -1L)
1767 #endif
1768             incompat = TRUE;
1769         if (option_flags.dig) {
1770             if (option_flags.dig != DIGRAPHS_INIT)
1771                 incompat = TRUE;
1772             else
1773                 option_flags.dig = 0;
1774         }
1775         break;
1776     }
1777 
1778     if (mcpp_mode == POST_STD
1779             && (option_flags.lang_asm || compat_mode || option_flags.k))
1780         incompat = TRUE;
1781     if (mcpp_mode != STD && option_flags.trig) {
1782         if (option_flags.trig != TRIGRAPHS_INIT)
1783             incompat = TRUE;
1784         else
1785             option_flags.trig = FALSE;
1786     }
1787     if (mcpp_mode != STD && (mcpp_debug & MACRO_CALL))
1788         incompat = TRUE;
1789     if ((mcpp_debug & MACRO_CALL)
1790                 && (option_flags.lang_asm || option_flags.c)) {
1791             mcpp_fputs( "Disabled -K option.\n", ERR);
1792             mcpp_debug &= ~MACRO_CALL;
1793             /* -a and -C options do not co-exist with -K    */
1794     }
1795     if (incompat) {
1796         mcpp_fputs( "Incompatible options are specified.\n", ERR);
1797         usage( '?');
1798     }
1799 
1800     standard = (mcpp_mode == STD || mcpp_mode == POST_STD);
1801     /* Modify magic characters in character type table. */
1802     if (! standard)
1803         char_type[ DEF_MAGIC] = 0;
1804     if (mcpp_mode != STD)
1805         char_type[ IN_SRC] = 0;
1806     if (mcpp_mode == POST_STD || mcpp_mode == KR)
1807         char_type[ TOK_SEP] = 0;    /* TOK_SEP equals to COM_SEP    */
1808     if (mcpp_mode != STD)
1809         char_type[ MAC_INF] = 0;
1810 
1811     expand_init( compat_mode, ansi);
1812                 /* Set function pointer to macro expansion routine  */
1813 }
1814 
1815 #if COMPILER != GNUC
1816 
init_cpu_macro(int gval,int sse)1817 static void init_cpu_macro (
1818     int     gval,               /* Argument of -G option for MSC    */
1819     int     sse                 /* Argument of -sse: option for MSC */
1820 )
1821 /*
1822  * Set predefined macros for CPU.
1823  * This routine is called from do_options() only once.
1824  * GCC-specific-build defines these macro by init_gcc_macro().
1825  */
1826 {
1827     const char *    cpu_macro[][ 7] = {
1828 #if SYS_FAMILY == SYS_UNIX
1829             { "__i386__"
1830 #if SYSTEM == SYS_CYGWIN
1831                 , "_X86_"
1832 #endif
1833                 , NULL,},
1834             { "__x86_64__", "__amd64__", NULL,},
1835             { "__ppc__", "__powerpc__", NULL,},
1836             { "__ppc64__", "__powerpc64__", NULL,}
1837 #elif   SYS_FAMILY == SYS_WIN
1838             { "_WIN32", "__WIN32__", "_X86_"
1839 #if SYSTEM == SYS_MINGW
1840                 , "__i386__"
1841 #endif
1842                 , NULL,},
1843             { "_WIN32", "_WIN64", "__WIN64__", "_M_AMD64", "_AMD64_", "_X64_"
1844                 , NULL,},       /* "_WIN32" is defined even on Windows 64   */
1845             { NULL,},                               /* Not supported  */
1846             { NULL,}                                /* Not supported  */
1847 #endif
1848         };
1849     const char **   macro;
1850     int             index;
1851 
1852     if (str_eq( arch, "i386"))
1853         index = 0;
1854     else if (str_eq( arch, "x86_64"))
1855         index = 1;
1856     else if (str_eq( arch, "ppc"))
1857         index = 2;
1858     else if (str_eq( arch, "ppc64"))
1859         index = 3;
1860     else
1861         index = 9;
1862 
1863     if (index == 9) {                               /* Unknown CPU  */
1864         look_and_install( "__" CPU "__", DEF_NOARGS_PREDEF, null, "1");
1865         return;
1866     }
1867     macro = cpu_macro[ index];
1868     while (*macro)
1869         look_and_install( *macro++, DEF_NOARGS_PREDEF, null, "1");
1870 #if SYS_FAMILY == SYS_WIN
1871     if (index == 0) {
1872         char    val[] = "600";
1873         if (gval)
1874             val[ 0] = gval;
1875         look_and_install( "_M_IX86", DEF_NOARGS_PREDEF, null, val);
1876         val[ 0] = '0' + sse;
1877         val[ 1] = '\0';
1878         look_and_install( "_M_IX86_FP", DEF_NOARGS_PREDEF, null, val);
1879     }
1880 #endif
1881 }
1882 #endif  /* COMPILER != GNUC */
1883 
init_predefines(void)1884 static void init_predefines( void)
1885 /*
1886  * Set or unset predefined macros.
1887  */
1888 {
1889     char    tmp[ 16];
1890 
1891     if (std_val != -1L) {               /* Version is specified     */
1892         if (cplus_val)
1893             cplus_val = std_val;        /* Value of __cplusplus     */
1894         else
1895             stdc_ver = std_val;     /* Value of __STDC_VERSION__    */
1896     } else {
1897         if (! cplus_val)
1898             stdc_ver = stdc_val ? STDC_VERSION : 0L;
1899     }
1900 
1901     if (nflag) {
1902         un_predefine( TRUE);
1903     } else if (stdc_val || cplus_val) {
1904 #if COMPILER != GNUC
1905         un_predefine( FALSE);           /* Undefine "unix" or so    */
1906 #endif
1907     }
1908     sprintf( tmp, "%ldL", cplus_val ? cplus_val : stdc_ver);
1909     if (cplus_val) {
1910         look_and_install( "__cplusplus", DEF_NOARGS_STANDARD, null, tmp);
1911     } else {
1912         if (stdc_ver)
1913             look_and_install( "__STDC_VERSION__", DEF_NOARGS_STANDARD, null
1914                     , tmp);
1915 #ifdef  COMPILER_CPLUS
1916         if (! nflag)        /* Undefine pre-defined macro for C++   */
1917             undefine( COMPILER_CPLUS);
1918 #endif
1919     }
1920     set_limit();
1921     stdc2 = cplus_val || stdc_ver >= 199901L;
1922     stdc3 = (cplus_val >= 199901L) || (stdc_ver >= 199901L);
1923         /* (cplus_val >= 199901L) makes C++ C99-compatible specs    */
1924     if (standard)
1925         init_std_defines();
1926     if (stdc3)
1927         set_pragma_op();
1928 }
1929 
init_std_defines(void)1930 static void init_std_defines( void)
1931 /*
1932  * For STD and POST_STD modes.
1933  * The magic pre-defines are initialized with magic argument counts.
1934  * expand_macro() notices this and calls the appropriate routine.
1935  * DEF_NOARGS is one greater than the first "magic" definition.
1936  * 'DEF_NOARGS - n' are reserved for pre-defined macros.
1937  * __STDC_VERSION__ and __cplusplus are defined by chk_opts() and set_cplus().
1938  */
1939 {
1940     char    tmp[ 16];
1941     char    timestr[ 14];
1942     time_t  tvec;
1943     char *  tstring;
1944 
1945     look_and_install( "__LINE__", DEF_NOARGS_DYNAMIC - 1, null, "-1234567890");
1946     /* Room for 11 chars (10 for long and 1 for '-' in case of wrap round.  */
1947     look_and_install( "__FILE__", DEF_NOARGS_DYNAMIC - 2, null, null);
1948                                             /* Should be stuffed    */
1949 
1950     /* Define __DATE__, __TIME__ as present date and time.          */
1951     time( &tvec);
1952     tstring = ctime( &tvec);
1953     sprintf( timestr, "\"%.3s %c%c %.4s\"",
1954         tstring + 4,
1955         *(tstring + 8) == '0' ? ' ' : *(tstring + 8),
1956         *(tstring + 9),
1957         tstring + 20);
1958     look_and_install( "__DATE__", DEF_NOARGS_DYNAMIC, null, timestr);
1959     sprintf( timestr, "\"%.8s\"", tstring + 11);
1960     look_and_install( "__TIME__", DEF_NOARGS_DYNAMIC, null, timestr);
1961 
1962     if (! look_id( "__STDC_HOSTED__")) {
1963         /*
1964          * Some compilers, e.g. GCC older than 3.3, define this macro by
1965          * -D option.
1966          */
1967         sprintf( tmp, "%d", STDC_HOSTED);
1968         look_and_install( "__STDC_HOSTED__", DEF_NOARGS_PREDEF, null, tmp);
1969     }
1970 #if COMPILER != GNUC        /* GCC do not undefine __STDC__ on C++  */
1971     if (cplus_val)
1972         return;
1973 #endif
1974     /* Define __STDC__ as 1 or such for Standard conforming compiler.   */
1975     if (! look_id( "__STDC__")) {
1976         sprintf( tmp, "%d", stdc_val);
1977         look_and_install( "__STDC__", DEF_NOARGS_STANDARD, null, tmp);
1978     }
1979 }
1980 
1981 #define LINE90LIMIT         32767
1982 #define LINE_CPLUS_LIMIT    32767
1983 
set_limit(void)1984 static void set_limit( void)
1985 /*
1986  * Set the minimum translation limits specified by the Standards.
1987  */
1988 {
1989     if (cplus_val) {            /* Specified by C++ 1998 Standard   */
1990         std_limits.str_len = SLEN_CPLUS_MIN;
1991         std_limits.id_len = IDLEN_CPLUS_MIN;
1992         std_limits.n_mac_pars = NMACPARS_CPLUS_MIN;
1993         std_limits.exp_nest = EXP_NEST_CPLUS_MIN;
1994         std_limits.blk_nest = BLK_NEST_CPLUS_MIN;
1995         std_limits.inc_nest = INCLUDE_NEST_CPLUS_MIN;
1996         std_limits.n_macro = NMACRO_CPLUS_MIN;
1997         std_limits.line_num = LINE_CPLUS_LIMIT;
1998     } else if (stdc_ver >= 199901L) {       /* Specified by C 1999 Standard */
1999         std_limits.str_len = SLEN99MIN;
2000         std_limits.id_len = IDLEN99MIN;
2001         std_limits.n_mac_pars = NMACPARS99MIN;
2002         std_limits.exp_nest = EXP_NEST99MIN;
2003         std_limits.blk_nest = BLK_NEST99MIN;
2004         std_limits.inc_nest = INCLUDE_NEST99MIN;
2005         std_limits.n_macro = NMACRO99MIN;
2006         std_limits.line_num = LINE99LIMIT;
2007     } else if (standard) {          /* Specified by C 1990 Standard */
2008         std_limits.str_len = SLEN90MIN;
2009         std_limits.id_len = IDLEN90MIN;
2010         std_limits.n_mac_pars = NMACPARS90MIN;
2011         std_limits.exp_nest = EXP_NEST90MIN;
2012         std_limits.blk_nest = BLK_NEST90MIN;
2013         std_limits.inc_nest = INCLUDE_NEST90MIN;
2014         std_limits.n_macro = NMACRO90MIN;
2015         std_limits.line_num = LINE90LIMIT;
2016     }
2017     /* Else pre-Standard mode   */
2018 }
2019 
set_pragma_op(void)2020 static void set_pragma_op( void)
2021 /*
2022  *      #define _Pragma(a)  _Pragma ( a )
2023  * Define _Pragma() operator as a special macro so as to be searched
2024  * easily.  The unusual 'DEF_PRAGMA' is a marker of this psuedo
2025  * macro.
2026  */
2027 {
2028     char *  name = "_Pragma";
2029     char    tmp[ 16];
2030 
2031     sprintf( tmp, "%c%s ( %c%c )", DEF_MAGIC, name, MAC_PARM, 1);
2032                                                 /* Replacement text */
2033     look_and_install( name, DEF_PRAGMA, "a", tmp);
2034 }
2035 
init_sys_macro(void)2036 void    init_sys_macro( void)
2037 /*
2038  * Define system-specific macros and some Standard required macros
2039  * and undefine macros specified by -U options.
2040  */
2041 {
2042     /* This order is important. */
2043     def_macros();               /* Define macros specified by -D    */
2044 #if COMPILER == GNUC
2045     chk_env();
2046 #endif
2047     init_predefines();                  /* Define predefined macros */
2048 #if COMPILER == GNUC
2049     init_gcc_macro();
2050 #elif   COMPILER == MSC
2051     init_msc_macro();
2052 #endif
2053     undef_macros();             /* Undefine macros specified by -U  */
2054     if (mcpp_debug & MACRO_CALL)
2055         dump_def( FALSE, TRUE);     /* Finally putout current macro names   */
2056 }
2057 
at_start(void)2058 void    at_start( void)
2059 /*
2060  * Do the commands prior to processing main source file after do_options().
2061  */
2062 {
2063     char *  env;
2064     FILEINFO *      file_saved = infile;
2065 
2066     /*
2067      * Set multi-byte character encoding according to environment variables
2068      * LC_ALL, LC_CTYPE and LANG -- with preference in this order.
2069      */
2070     if (! mb_changed) {                     /* -m option precedes   */
2071         if ((env = getenv( "LC_ALL")) != NULL)
2072             set_encoding( env, "LC_ALL", 0);
2073         else if ((env = getenv( "LC_CTYPE")) != NULL)
2074             set_encoding( env, "LC_CTYPE", 0);
2075         else if ((env = getenv( "LANG")) != NULL)
2076             set_encoding( env, "LANG", 0);
2077     }
2078 
2079 #if COMPILER == GNUC || COMPILER == MSC
2080     if (option_flags.dollar_in_name)
2081         char_type[ 0x24] |= LET;    /* Enable '$' in identifiers    */
2082     /*
2083      * Do the -include (-Fl for MSC) options in the specified order.
2084      * Note: This functionality is implemented as nested #includes
2085      *   which results the same effect as sequential #includes.
2086      */
2087     {
2088         char **         preinc;
2089         /*
2090          * Note: Here, 'infile' is the main input file, which is pseudo-
2091          * parent file of the files to pre-include.  So, we must
2092          * temporarily set the infile's directory to the current directory
2093          * in order to preinclude the files relative to it.
2094          */
2095         preinc = preinc_end;
2096         while (preinclude <= --preinc && *preinc != NULL)
2097             open_file( &null, NULL, *preinc, TRUE, TRUE, FALSE);
2098     }
2099 #endif
2100 
2101     put_info( file_saved);
2102 }
2103 
put_info(FILEINFO * sharp_file)2104 static void put_info(
2105     FILEINFO *  sharp_file
2106 )
2107 /*
2108  * Putout compiler-specific information.
2109  */
2110 {
2111     if (no_output || option_flags.p)
2112         return;
2113     sharp_file->line++;
2114     sharp( sharp_file, 0);
2115     sharp_file->line--;
2116 #if COMPILER == GNUC
2117     if (gcc_work_dir)
2118         mcpp_fprintf( OUT, "%s%ld \"%s%c\"\n"
2119                 , std_line_prefix ? "#line " : LINE_PREFIX
2120                 , 1, cur_work_dir, '/');
2121         /* Putout the current directory as a #line line as: */
2122         /* '# 1 "/abs-path/cur_dir//"'.                     */
2123     mcpp_fprintf( OUT, "%s%ld \"<built-in>\"\n"
2124                 , std_line_prefix ? "#line " : LINE_PREFIX , 1);
2125     mcpp_fprintf( OUT, "%s%ld \"<command line>\"\n"
2126                 , std_line_prefix ? "#line " : LINE_PREFIX , 1);
2127     mcpp_fprintf( OUT, "%s%ld \"%s\"%s\n"
2128             , std_line_prefix ? "#line " : LINE_PREFIX, 1, cur_fullname
2129             , ! str_eq( cur_fullname, sharp_file->full_fname) ? " 1" : null);
2130             /* Suffix " 1" for the file specified by -include   */
2131 #endif
2132 }
2133 
set_files(int argc,char ** argv,char ** in_pp,char ** out_pp)2134 static char *   set_files(
2135     int     argc,
2136     char ** argv,
2137     char ** in_pp,
2138     char ** out_pp
2139 )
2140 /*
2141  * Set input and/or output files.
2142  */
2143 {
2144     char *      cp;
2145 
2146     if (*in_pp == NULL) {                           /* Input file   */
2147         cp = argv[ mcpp_optind++];
2148 #if SYS_FAMILY == SYS_WIN
2149         cp = bsl2sl( cp);
2150 #endif
2151         *in_pp = cp;
2152     }
2153     if (mcpp_optind < argc && argv[ mcpp_optind][ 0] != '-'
2154             && *out_pp == NULL) {
2155         cp = argv[ mcpp_optind++];
2156 #if SYS_FAMILY == SYS_WIN
2157         cp = bsl2sl( cp);
2158 #endif
2159         *out_pp = cp;                               /* Output file  */
2160     }
2161     if (mcpp_optind >= argc)
2162         return  NULL;           /* Exhausted command line arguments */
2163     if (argv[ mcpp_optind][ 0] == '-')
2164         return  argv[ mcpp_optind];                 /* More options */
2165     cfatal( "Excessive file argument \"%s\"", argv[ mcpp_optind], 0L , NULL);
2166     return  NULL;
2167 }
2168 
set_env_dirs(void)2169 static void set_env_dirs( void)
2170 /*
2171  * Add to include path those specified by environment variables.
2172  */
2173 {
2174     const char *    env;
2175 
2176     if (cplus_val) {
2177         if ((env = getenv( ENV_CPLUS_INCLUDE_DIR)) != NULL)
2178             parse_env( env);
2179     }
2180     if ((env = getenv( ENV_C_INCLUDE_DIR)) != NULL)
2181         parse_env( env);
2182 }
2183 
parse_env(const char * env)2184 static void parse_env(
2185     const char *    env
2186 )
2187 /*
2188  * Parse environmental variable and append the path to include-dir-list.
2189  */
2190 {
2191     char *  save;
2192     char *  save_start;
2193     char *  p;
2194     int     sep;
2195 
2196     save = save_start = save_string( env);
2197     while (*save) {
2198         p = save;
2199         while (*p && *p != ENV_SEP)
2200             p++;
2201         if (p != save)  {                   /* Variable separator   */
2202             sep = *p;
2203             *p = EOS;
2204             set_a_dir( save);
2205             if (sep == EOS)
2206                 break;
2207             save = ++p;
2208         }
2209         while (*save == ENV_SEP)
2210             ++save;
2211     }
2212     free( save_start);
2213 }
2214 
set_sys_dirs(int set_cplus_dir)2215 static void set_sys_dirs(
2216     int     set_cplus_dir       /* Set C++ include-directory too    */
2217 )
2218 /*
2219  * Set site-specific and system-specific directories to the include directory
2220  * list.
2221  */
2222 {
2223     if (cplus_val && set_cplus_dir) {
2224 #ifdef  CPLUS_INCLUDE_DIR1
2225         set_a_dir( CPLUS_INCLUDE_DIR1);
2226 #endif
2227 #ifdef  CPLUS_INCLUDE_DIR2
2228         set_a_dir( CPLUS_INCLUDE_DIR2);
2229 #endif
2230 #ifdef  CPLUS_INCLUDE_DIR3
2231         set_a_dir( CPLUS_INCLUDE_DIR3);
2232 #endif
2233 #ifdef  CPLUS_INCLUDE_DIR4
2234         set_a_dir( CPLUS_INCLUDE_DIR4);
2235 #endif
2236     }
2237 
2238 #if SYS_FAMILY == SYS_UNIX
2239     set_a_dir( "/usr/local/include");
2240 #endif
2241 
2242 #ifdef  C_INCLUDE_DIR1
2243     set_a_dir( C_INCLUDE_DIR1);
2244 #endif
2245 #ifdef  C_INCLUDE_DIR2
2246     set_a_dir( C_INCLUDE_DIR2);
2247 #endif
2248 
2249 #if SYS_FAMILY == SYS_UNIX
2250 #if SYSTEM == SYS_CYGWIN
2251     if (no_cygwin)                          /* -mno-cygwin          */
2252         set_a_dir( "/usr/include/mingw");
2253     else
2254         set_a_dir( "/usr/include");
2255 #else
2256     set_a_dir( "/usr/include"); /* Should be placed after C_INCLUDE_DIR?    */
2257 #endif
2258 #endif
2259 }
2260 
set_a_dir(const char * dirname)2261 static void set_a_dir(
2262     const char *    dirname                 /* The path-name        */
2263 )
2264 /*
2265  * Append an include directory.
2266  * This routine is called from the following routines (in this order).
2267  * 1. do_options() by -I option.
2268  * 2. do_options() by -isystem option (for GNUC).
2269  * 3. set_env_dirs() by environment variables.
2270  * 4. set_sys_dirs() by CPLUS_INCLUDE_DIR?, C_INCLUDE_DIR? and system-
2271  *    specifics (unless -I- or -nostdinc option is specified).
2272  * Ignore non-existent directory.
2273  * Note that this routine should be called only in initializing steps,
2274  *      because increase of include dirs causes reallocation of incdir[].
2275  * Note: a trailing PATH-DELIM is appended by norm_path().
2276  */
2277 {
2278     char *  norm_name;
2279     const char **   ip;
2280 
2281     if (incdir == NULL) {               /* Should be initialized    */
2282         max_inc = INIT_NUM_INCLUDE;
2283         incdir = (const char **) xmalloc( sizeof (char *) * max_inc);
2284         incend = &incdir[ 0];
2285     } else if (incend - incdir >= max_inc) {        /* Buffer full  */
2286 #if SYSTEM == SYS_MAC
2287         size_t  framework_pos = to_search_framework - incdir;
2288 #endif
2289 #if COMPILER == GNUC
2290         size_t  sys_pos = 0;
2291         if (sys_dirp)
2292             sys_pos = sys_dirp - incdir;
2293 #endif
2294         incdir = (const char **) xrealloc( (void *) incdir
2295                 , sizeof (char *) * max_inc * 2);
2296         incend = &incdir[ max_inc];
2297 #if COMPILER == GNUC
2298         if (sys_pos)
2299             sys_dirp = &incdir[ sys_pos];
2300 #endif
2301 #if SYSTEM == SYS_MAC
2302         to_search_framework = &incdir[ framework_pos];
2303 #endif
2304         max_inc *= 2;
2305     }
2306 
2307     if (dirname == NULL)
2308         return;                     /* Only to initialize incdir[]  */
2309     norm_name = norm_dir( dirname, FALSE);
2310     if (! norm_name)                        /* Non-existent         */
2311         return;
2312     for (ip = incdir; ip < incend; ip++) {
2313         if (str_case_eq( *ip, norm_name)) {
2314             if (option_flags.v && ! (mcpp_debug & MACRO_CALL))
2315                 mcpp_fprintf( ERR, "Duplicate directory \"%s\" is ignored\n"
2316                         , norm_name);
2317             free( norm_name);               /* Already registered   */
2318             return;
2319         }
2320     }
2321     /* Register new directory   */
2322     *incend++ = norm_name;
2323 }
2324 
2325 #if SYSTEM == SYS_MAC && COMPILER == GNUC
2326 /* Definitions for "header map" file of Xcode / Apple-GCC.          */
2327 /* These definitions were taken from cpplib.h of Apple-GCC-4.0.1    */
2328 
2329 #define HMAP_SAME_ENDIANNESS_MAGIC      \
2330         (((((('h' << 8) | 'm') << 8) | 'a') << 8) | 'p')
2331 
2332 typedef unsigned short  uint16;
2333 typedef unsigned int    uint32;
2334 
2335 struct hmap_bucket
2336 {
2337     uint32  key;            /* Offset (into strings) of key             */
2338     struct {
2339         uint32  prefix;     /* Offset (into strings) of value prefix    */
2340         uint32  suffix;     /* Offset (into strings) of value suffix    */
2341     } value;                /* Value (prefix- and suffix-strings)       */
2342 };
2343 
2344 struct hmap_header_map
2345 {
2346     uint32  magic;          /* Magic word, also indicates byte order    */
2347     uint16  version;        /* Version number -- currently 1            */
2348     uint16  _reserved;      /* Reserved for future use -- zero for now  */
2349     uint32  strings_offset; /* Offset to start of string pool           */
2350     uint32  count;          /* Number of entries in the string table    */
2351     uint32  capacity;       /* Number of buckets (always a power of 2)  */
2352     uint32  max_value_length;
2353                         /* Length of longest result path (excl. '\0')   */
2354     struct hmap_bucket  buckets[1];
2355                         /* Inline array of 'capacity' maptable buckets  */
2356     /* Strings follow the buckets, at strings_offset.  */
2357 };
2358 #endif
2359 
norm_dir(const char * dirname,int framework)2360 static char *   norm_dir(
2361     const char *    dirname,        /* Directory path to normalize  */
2362     int             framework       /* Setting a framework directory*/
2363 )
2364 /*
2365  * Normalize include directory path.
2366  * Handle -isysroot option for GCC, including framework directory for SYS_MAC.
2367  */
2368 {
2369     char *  norm_name;
2370 
2371 #if COMPILER == GNUC
2372     if (sysroot && sys_dirp) {
2373         /* Logical system root specified and dirname is system header dir   */
2374         char    delim[ 2] = { EOS, EOS};
2375         char *  dir;
2376 #if SYSTEM == SYS_MAC
2377         if (! framework && memcmp( dirname, "/usr/", 5) != 0)
2378             return  NULL;           /* /Developer/usr/lib/gcc/      */
2379 #endif
2380         if (dirname[ 0] != PATH_DELIM)
2381             delim[ 0] = PATH_DELIM;
2382         dir = xmalloc( strlen( sysroot) + strlen( dirname) + 2);
2383         sprintf( dir, "%s%s%s", sysroot, delim, dirname);
2384         dirname = dir;
2385     }
2386 #endif
2387 #if SYSTEM == SYS_MAC && COMPILER == GNUC
2388     if (strlen( dirname) > 5
2389             && str_case_eq( dirname + strlen( dirname) - 5, ".hmap")) {
2390         /* "header map" file (not an include directory) */
2391         norm_name = norm_path( null, dirname, FALSE, TRUE);
2392         if (! norm_name && option_flags.v)
2393             mcpp_fprintf( ERR, "Invalid header map file \"%s\" is ignored\n"
2394                     , dirname);
2395     } else
2396 #endif
2397     {
2398         norm_name = norm_path( dirname, NULL, FALSE, FALSE);
2399                             /* Normalize the pathname to compare    */
2400         if (! norm_name && option_flags.v && ! (mcpp_debug & MACRO_CALL))
2401             mcpp_fprintf( ERR, "Non-existent directory \"%s\" is ignored\n"
2402                     , dirname);
2403     }
2404 #if COMPILER == GNUC
2405     if (sysroot && sys_dirp)
2406         free( dirname);
2407 #endif
2408 
2409     return  norm_name;
2410 }
2411 
norm_path(const char * dir,const char * fname,int inf,int hmap)2412 static char *   norm_path(
2413     const char *    dir,        /* Include directory (maybe "", never NULL) */
2414     const char *    fname,
2415         /* Filename (possibly has directory part, or maybe NULL)    */
2416     int     inf,    /* If TRUE, output some infs when (mcpp_debug & PATH)   */
2417     int     hmap            /* "header map" file of Apple-GCC       */
2418 )
2419 /*
2420  * Normalize the pathname removing redundant components such as
2421  * "foo/../", "./" and trailing "/.".
2422  * Append trailing "/" if 'fname' is NULL.
2423  * Change relative path to absolute path.
2424  * Dereference a symbolic linked file (or directory) to a real directory/file.
2425  * Return a malloc'ed buffer, if the directory/file exists.
2426  * Return NULL, if the specified directory/file does not exist or 'dir' is
2427  * not a directory or 'fname' is not a regular file.
2428  * This routine is called from set_a_dir(), init_gcc_macro(), do_once() and
2429  * open_file().
2430  */
2431 {
2432     char *  norm_name;                  /* The path-list converted  */
2433     char *  start;
2434     char *  cp1;
2435     char *  cp2;
2436     char *  abs_path;
2437     int     len;                            /* Should not be size_t */
2438     size_t  start_pos = 0;
2439     char    slbuf1[ PATHMAX+1];             /* Working buffer       */
2440 #if SYS_FAMILY == SYS_UNIX
2441     char    slbuf2[ PATHMAX+1]; /* Working buffer for dereferencing */
2442 #endif
2443 #if SYSTEM == SYS_CYGWIN || SYSTEM == SYS_MINGW
2444     static char *   root_dir;
2445                 /* System's root directory in Windows file system   */
2446     static size_t   root_dir_len;
2447 #if SYSTEM == SYS_CYGWIN
2448     static char *   cygdrive = "/cygdrive/";    /* Prefix for drive letter  */
2449 #else
2450     static char *   mingw_dir;          /* "/mingw" dir in Windows  */
2451     static size_t   mingw_dir_len;
2452 #endif
2453 #endif
2454 #if HOST_COMPILER == MSC
2455     struct _stat    st_buf;
2456 #else
2457     struct stat     st_buf;
2458 #endif
2459 
2460     if (! dir || (*dir && is_full_path( fname)))
2461         cfatal( "Bug: Wrong argument to norm_path()"        /* _F_  */
2462                 , NULL, 0L, NULL);
2463     inf = inf && (mcpp_debug & PATH);       /* Output information   */
2464 
2465     strcpy( slbuf1, dir);                   /* Include directory    */
2466     len = strlen( slbuf1);
2467     if (fname && len && slbuf1[ len - 1] != PATH_DELIM) {
2468         slbuf1[ len] = PATH_DELIM;          /* Append PATH_DELIM    */
2469         slbuf1[ ++len] = EOS;
2470     } else if (! fname && len && slbuf1[ len - 1] == PATH_DELIM) {
2471         /* stat() of some systems do not like trailing '/'  */
2472         slbuf1[ --len] = EOS;
2473     }
2474     if (fname)
2475         strcat( slbuf1, fname);
2476     if (stat( slbuf1, & st_buf) != 0        /* Non-existent         */
2477             || (! fname && ! S_ISDIR( st_buf.st_mode))
2478                 /* Not a directory though 'fname' is not specified  */
2479             || (fname && ! S_ISREG( st_buf.st_mode)))
2480                 /* Not a regular file though 'fname' is specified   */
2481         return  NULL;
2482 #if SYSTEM == SYS_MAC && COMPILER == GNUC
2483     if (hmap) {                         /* Dirty "header map" file  */
2484         struct hmap_header_map  hmap;
2485         size_t      cnt;
2486         FILE *      fp;
2487         fp = fopen( fname, "r");
2488         cnt = fread( & hmap, sizeof (struct hmap_header_map), 1, fp);
2489         fclose( fp);
2490         if (cnt == 0 || hmap.magic != HMAP_SAME_ENDIANNESS_MAGIC)
2491             return  NULL;
2492     }
2493 #endif
2494     if (! fname) {
2495         slbuf1[ len] = PATH_DELIM;          /* Append PATH_DELIM    */
2496         slbuf1[ ++len] = EOS;
2497     }
2498 #if SYS_FAMILY == SYS_UNIX
2499     /* Dereference symbolic linked directory or file, if any    */
2500     slbuf1[ len] = EOS;     /* Truncate PATH_DELIM and 'fname' part, if any */
2501     slbuf2[ 0] = EOS;
2502     if (*dir && ! fname) {      /* Registering include directory    */
2503         /* Symbolic link check of directories are required  */
2504         deref_syml( slbuf1, slbuf2, slbuf1);
2505     } else if (fname) {                             /* Regular file */
2506         len = strlen( slbuf1);
2507         strcat( slbuf1, fname);
2508         deref_syml( slbuf1, slbuf2, slbuf1 + len);
2509                                 /* Symbolic link check of directory */
2510         if ((len = readlink( slbuf1, slbuf2, PATHMAX)) > 0) {
2511             /* Dereference symbolic linked file (not directory) */
2512             *(slbuf2 + len) = EOS;
2513             cp1 = slbuf1;
2514             if (slbuf2[ 0] != PATH_DELIM) {     /* Relative path    */
2515                 cp2 = strrchr( slbuf1, PATH_DELIM);
2516                 if (cp2)        /* Append to the source directory   */
2517                     cp1 = cp2 + 1;
2518             }
2519             strcpy( cp1, slbuf2);
2520         }
2521     }
2522     if (inf) {
2523         if (slbuf2[ 0])
2524             mcpp_fprintf( DBG, "Dereferenced \"%s%s\" to \"%s\"\n"
2525                     , dir, fname ? fname : null, slbuf1);
2526     }
2527 #endif
2528     len = strlen( slbuf1);
2529     start = norm_name = xmalloc( len + 1);  /* Need a new buffer    */
2530     strcpy( norm_name, slbuf1);
2531 #if SYS_FAMILY == SYS_WIN
2532     bsl2sl( norm_name);
2533 #endif
2534 #if SPECIAL_PATH_DELIM                  /* ':' ?    */
2535     for (cp1 = norm_name; *cp1 != EOS; cp1++) {
2536         if (*cp1 == PATH_DELIM)
2537             *cp1 = '/';
2538     }
2539 #endif
2540     cp1 = norm_name;
2541 
2542 #if SYSTEM == SYS_CYGWIN
2543     /* Convert to "/cygdirve/x/dir" style of absolute path-list     */
2544     if (len >= 8 && (memcmp( cp1, "/usr/bin", 8) == 0
2545                     || memcmp( cp1, "/usr/lib", 8) == 0)) {
2546         memmove( cp1, cp1 + 4, len - 4 + 1);    /* Remove "/usr"    */
2547         len -= 4;
2548     }
2549     if (*cp1 == '/' && (len < 10 || memcmp( cp1, cygdrive, 10) != 0)) {
2550         /* /dir, not /cygdrive/     */
2551         if (! root_dir_len) {           /* Should be initialized    */
2552             /* Convert "X:\DIR-list" to "/cygdrive/x/dir-list"      */
2553             root_dir = xmalloc( strlen( CYGWIN_ROOT_DIRECTORY) + 1);
2554             strcpy( root_dir, CYGWIN_ROOT_DIRECTORY);
2555             *(root_dir + 1) = *root_dir;        /* "x:/" to " x/"   */
2556             cp1 = xmalloc( strlen( cygdrive) + strlen( root_dir));
2557             strcpy( cp1, cygdrive);
2558             strcat( cp1, root_dir + 1);
2559             free( root_dir);
2560             root_dir = cp1;
2561             root_dir_len = strlen( root_dir);
2562         }
2563         cp1 = xmalloc( root_dir_len + len + 1);
2564         strcpy( cp1, root_dir);
2565         strcat( cp1, norm_name);        /* Convert to absolute path */
2566         free( norm_name);
2567         norm_name = start = cp1;
2568         len += root_dir_len;
2569     }
2570 #endif
2571 
2572 #if SYSTEM == SYS_MINGW
2573     /* Handle the mess of MinGW's path-list */
2574     /* Convert to "x:/dir" style of absolute path-list  */
2575     if (*cp1 == PATH_DELIM && isalpha( *(cp1 + 1))
2576             && *(cp1 + 2) == PATH_DELIM) {          /* /c/, /d/, etc*/
2577         *cp1 = *(cp1 + 1);
2578         *(cp1 + 1) = ':';               /* Convert to c:/, d:/, etc */
2579     } else if (memcmp( cp1, "/mingw", 6) == 0) {
2580         if (! mingw_dir_len) {          /* Should be initialized    */
2581             mingw_dir_len = strlen( MINGW_DIRECTORY);
2582             mingw_dir = xmalloc( mingw_dir_len + 1);
2583             strcpy( mingw_dir, MINGW_DIRECTORY);
2584         }
2585         cp1 = xmalloc( mingw_dir_len + len + 1);
2586         strcpy( cp1, mingw_dir);
2587         strcat( cp1, norm_name + 6);    /* Convert to absolute path */
2588         free( norm_name);
2589         norm_name = start = cp1;
2590         len += mingw_dir_len;
2591     } else if (memcmp( cp1, "/usr", 4) == 0) {
2592         memmove( cp1, cp1 + 4, len - 4 + 1);    /* Remove "/usr"    */
2593         len -= 4;
2594     }
2595     if (*cp1 == '/') {                  /* /dir or /                */
2596         if (! root_dir_len) {           /* Should be initialized    */
2597             root_dir_len = strlen( MSYS_ROOT_DIRECTORY);
2598             root_dir = xmalloc( root_dir_len + 1);
2599             strcpy( root_dir, MSYS_ROOT_DIRECTORY);
2600         }
2601         cp1 = xmalloc( root_dir_len + len + 1);
2602         strcpy( cp1, root_dir);
2603         strcat( cp1, norm_name);        /* Convert to absolute path */
2604         free( norm_name);
2605         norm_name = start = cp1;
2606         len += root_dir_len;
2607     }
2608 #endif
2609 
2610 #if SYS_FAMILY == SYS_WIN
2611     if (*(cp1 + 1) == ':')
2612         start = cp1 += 2;               /* Next to the drive letter */
2613     start_pos = 2;
2614 #endif
2615     if (len == 1 && *norm_name == '/')              /* Only "/"     */
2616         return  norm_name;
2617 
2618     if (strncmp( cp1, "./", 2) == 0)    /* Remove beginning "./"    */
2619         memmove( cp1, cp1 + 2, strlen( cp1 + 2) + 1);       /* +1 for EOS   */
2620     if (*start != '/') {    /* Relative path to current directory   */
2621         /* Make absolute path   */
2622         abs_path = xmalloc( len + strlen( cur_work_dir) + 1);
2623         cp1 = stpcpy( abs_path, cur_work_dir);
2624         strcpy( cp1, start);
2625         free( norm_name);
2626         norm_name = abs_path;
2627         start = cp1 = norm_name + start_pos;
2628     }
2629 
2630     while ((cp1 = strstr( cp1, "/./")) != NULL)
2631         memmove( cp1, cp1 + 2, strlen( cp1 + 2) + 1);
2632                                         /* Remove "/." of "/./"     */
2633     cp1 = start;
2634     /* Remove redundant "foo/../"   */
2635     while ((cp1 = strstr( cp1, "/../")) != NULL) {
2636         *cp1 = EOS;
2637         if ((cp2 = strrchr( start, '/')) != NULL) {
2638             if (*(cp1 - 1) != '.') {
2639                 memmove( cp2 + 1, cp1 + 4, strlen( cp1 + 4) + 1);
2640                                         /* Remove "foo/../"         */
2641                 cp1 = cp2;
2642             } else {                                /* Impossible   */
2643                 break;
2644             }
2645         } else {                                    /* Impossible   */
2646             break;
2647         }
2648     }
2649 
2650 #if SPECIAL_PATH_DELIM
2651     for (cp1 = start; *cp1 != EOS; cp1++) {
2652         if (*cp1 == '/')
2653             *cp1 = PATH_DELIM;
2654     }
2655 #endif
2656     if (inf) {
2657         char    debug_buf[ PATHMAX+1];
2658         strcpy( debug_buf, dir);
2659         strcat( debug_buf, fname ? fname : null);
2660 #if SYS_FAMILY == SYS_WIN
2661         bsl2sl( debug_buf);
2662 #endif
2663         if (! str_eq( debug_buf, norm_name))
2664             mcpp_fprintf( DBG, "Normalized the path \"%s\" to \"%s\"\n"
2665                     , debug_buf, norm_name);
2666     }
2667 
2668     return  norm_name;
2669 }
2670 
2671 #if SYS_FAMILY == SYS_UNIX
2672 
deref_syml(char * slbuf1,char * slbuf2,char * chk_start)2673 static void     deref_syml(
2674     char *      slbuf1,                     /* Original path-list   */
2675     char *      slbuf2,                     /* Working buffer       */
2676     char *      chk_start                   /* Pointer into slbuf1  */
2677 )
2678 /* Dereference symbolic linked directory    */
2679 {
2680     char *      cp2;
2681     int         len;                /* Should be int, not size_t    */
2682 
2683     while ((chk_start = strchr( chk_start, PATH_DELIM)) != NULL) {
2684         *chk_start = EOS;
2685         if ((len = readlink( slbuf1, slbuf2, PATHMAX)) > 0) {
2686             /* Dereference symbolic linked directory    */
2687             cp2 = strrchr( slbuf1, PATH_DELIM); /* Previous delimiter       */
2688             *chk_start = PATH_DELIM;
2689             strcpy( slbuf2 + len, chk_start);
2690             if (slbuf2[ 0] == PATH_DELIM) {     /* Absolute path    */
2691                 strcpy( slbuf1, slbuf2);
2692                 chk_start = slbuf1 + len + 1;
2693             } else {
2694                 if (cp2)
2695                     chk_start = cp2 + 1;
2696                 else
2697                     chk_start = slbuf1;
2698                 strcpy( chk_start, slbuf2);     /* Rewrite the path */
2699                 chk_start += len;
2700             }
2701         } else {
2702             *chk_start++ = PATH_DELIM;
2703         }
2704     }
2705 }
2706 #endif
2707 
2708 #if COMPILER == GNUC
2709 
init_gcc_macro(void)2710 static void init_gcc_macro( void)
2711 /*
2712  * Predefine GCC macros.
2713  * This routine should be called after opening output file in order to putout
2714  * macro informations by -K option into the file.
2715  * Also this routine should be called before undef_macros() in order to
2716  * permit undefining a macro by -U option.
2717  */
2718 {
2719     char        fname[ BUFSIZ];
2720     char        lbuf[ BUFSIZ];
2721     char *      include_dir;    /* The version-specific include directory   */
2722     char *      tmp;
2723     FILE *      fp;
2724     DEFBUF *    defp;
2725     const char *    cp;
2726     char *      tp;
2727     int         i;
2728 
2729     if (nflag)                                  /* -undef option    */
2730         goto  undef_special;
2731 
2732     tmp = xmalloc( strlen( INC_DIR) + strlen( "/mingw/mcpp-gcc-")
2733             + strlen( arch) + 1);
2734 #if SYSTEM == SYS_CYGWIN
2735     if (no_cygwin) {
2736         sprintf( tmp, "%s/mingw/mcpp-gcc-%s", INC_DIR, arch);
2737     } else {
2738         sprintf( tmp, "%s/mcpp-gcc-%s", INC_DIR, arch);
2739     }
2740 #else
2741     sprintf( tmp, "%s/mcpp-gcc-%s", INC_DIR, arch);
2742 #endif
2743     include_dir = norm_path( tmp, NULL, TRUE, FALSE);
2744     free( tmp);
2745 
2746     for (i = 0; i <= 1; i++) {
2747         int         nargs;
2748 
2749         if ((mcpp_mode == POST_STD || ansi) && i == 0)
2750             continue;   /* POST_STD or __STRICT_ANSI__ does not     */
2751                         /*      predefine non-conforming macros     */
2752         /* The predefined macro file    */
2753         cp = i ? "std" : "old";
2754         sprintf( fname, "%sg%s%d%d_predef_%s.h"
2755                 , include_dir, cplus_val ? "xx" : "cc"
2756                 , gcc_maj_ver, gcc_min_ver, cp);
2757             /* Note that norm_path() append a PATH_DELIM.   */
2758         if ((fp = fopen( fname, "r")) == NULL) {
2759             mcpp_fprintf( ERR, "The mode for %s has not been installed.\n"
2760                     , arch);
2761             longjmp( error_exit, -1);
2762         }
2763         nargs = i ? 0 : DEF_NOARGS_PREDEF_OLD;
2764             /* g*_predef_std.h has DEF_NOARGS_PREDEF or non-negative args   */
2765             /* while g*_predef_old.h has only DEF_NOARGS_PREDEF_OLD args    */
2766         while (fgets( lbuf, BUFSIZ, fp) != NULL) {
2767             unget_string( lbuf, "gcc_predefine");
2768             if (skip_ws() == '#'
2769                 && scan_token( skip_ws(), (tp = work_buf, &tp), work_end)
2770                         == NAM
2771                     && str_eq( work_buf, "define")) {
2772                 defp = do_define( TRUE, nargs);     /* Ignore re-definition */
2773             }
2774             skip_nl();
2775         }
2776     }
2777     free( include_dir);
2778 
2779 undef_special:
2780     if (look_id( "__OPTIMIZE__"))       /* -O option is specified   */
2781         undefine( "__NO_INLINE__");
2782 }
2783 
chk_env(void)2784 static void chk_env( void)
2785 /*
2786  * Check the environment variables to specify output of dependency lines.
2787  */
2788 {
2789     char *  env;
2790     char *  cp;
2791 
2792     /* Output of dependency lines   */
2793     if ((env = getenv( "DEPENDENCIES_OUTPUT")) == NULL) {
2794         if ((env = getenv( "SUNPRO_DEPENDENCIES")) == NULL)
2795             return;
2796         else
2797             mkdep |= MD_SYSHEADER;
2798     }
2799     mkdep |= MD_MKDEP;
2800     if ((cp = strchr( env, ' ')) != NULL) {
2801         *cp++ = EOS;
2802         while (*cp == ' ')
2803             cp++;
2804     }
2805     if (! mkdep_fp)                 /* Command line option precedes */
2806         mkdep_fp = fopen( env, "a");
2807     if (! mkdep_target)
2808         mkdep_target = cp;
2809 }
2810 
2811 #elif   COMPILER == MSC
2812 
init_msc_macro(void)2813 static void init_msc_macro( void)
2814 /*
2815  * Define a few MSC-specific predefined macros.
2816  */
2817 {
2818     DEFBUF *    defp;
2819     int         i;
2820 
2821     defp = look_id( "_MSC_VER");
2822     i = atoi( defp->repl);
2823     if (i >= 1400) {                        /* _MSC_VER >= 1400     */
2824         look_and_install( "_MT", DEF_NOARGS_PREDEF, null, "1");
2825         if (cplus_val && ! wchar_t_modified) {
2826             /* -Zc:wchar_t- was not specified   */
2827             look_and_install( "_NATIVE_WCHAR_T_DEFINED", DEF_NOARGS_PREDEF
2828                     , null, "1");
2829             look_and_install( "_WCHAR_T_DEFINED", DEF_NOARGS_PREDEF, null
2830                     , "1");
2831         }
2832     }
2833 }
2834 
2835 #endif
2836 
def_macros(void)2837 static void     def_macros( void)
2838 /*
2839  * Define macros specified by -D option.
2840  * This routine should be called before undef_macros().
2841  */
2842 {
2843     int         i;
2844 
2845     for (i = 0; i < def_cnt; i++)
2846         def_a_macro( 'D', def_list[ i]);
2847 }
2848 
undef_macros(void)2849 static void     undef_macros( void)
2850 /*
2851  * Undefine macros specified by -U option.
2852  * This routine should be called after init_predefine().
2853  */
2854 {
2855     char *      name;
2856     int         i;
2857 
2858     for (i = 0; i < undef_cnt; i++) {
2859         name = undef_list[ i];
2860         if (look_id( name) != NULL)
2861             undefine( name);
2862         else if (warn_level & 8)
2863             mcpp_fprintf( ERR, "\"%s\" wasn't defined\n", name);
2864     }
2865 }
2866 
put_depend(const char * filename)2867 void    put_depend(
2868     const char *    filename
2869 )
2870 /*
2871  * Append a header name to the source file dependency line.
2872  */
2873 {
2874 #define MAX_OUT_LEN     76      /* Maximum length of output line    */
2875 #define MKDEP_INITLEN   (MKDEP_INIT * 0x100)
2876 #define MKDEP_MAX       (MKDEP_INIT * 0x10)
2877 #define MKDEP_MAXLEN    (MKDEP_INITLEN * 0x10)
2878 
2879     static char *   output = NULL;          /* File names           */
2880     static size_t * pos = NULL;             /* Offset to filenames  */
2881     static int      pos_num;                /* Index of pos[]       */
2882     static char *   out_p;                  /* Pointer to output[]  */
2883     static size_t   mkdep_len;              /* Size of output[]     */
2884     static size_t   pos_max;                /* Size of pos[]        */
2885     static FILE *   fp;         /* Path to output dependency line   */
2886     static size_t   llen;       /* Length of current physical output line   */
2887     size_t *        pos_p;                  /* Index into pos[]     */
2888     size_t          fnamlen;                /* Length of filename   */
2889 
2890     if (fp == NULL) {   /* Main source file.  Have to initialize.   */
2891 #if MCPP_LIB
2892         if (output != NULL) {
2893             free( output);
2894             free( pos);
2895         }
2896 #endif
2897         output = xmalloc( mkdep_len = MKDEP_INITLEN);
2898         pos = (size_t *) xmalloc( (pos_max = MKDEP_INIT) * sizeof (size_t));
2899         out_p = md_init( filename, output);
2900         fp = mkdep_fp;
2901         llen = strlen( output);
2902         pos_num = 0;            /* Initialize for MCPP_LIB build    */
2903     } else if (filename == NULL) {              /* End of input     */
2904         out_p = stpcpy( out_p, "\n\n");
2905         if (mkdep & MD_PHONY) {
2906             /* Output the phony target line for each recorded header files. */
2907             char *  cp;
2908             int     c;
2909 
2910             if (strlen( output) * 2 + (pos_num * 2) >= MKDEP_MAXLEN) {
2911                 cerror( "Too long dependency line"          /* _E_  */
2912                         , NULL, 0L, NULL);
2913                 if (fp == fp_out)
2914                     mcpp_fputs( output, OUT);
2915                 else
2916                     fputs( output, fp);
2917                 return;
2918             } else if (strlen( output) * 2 + (pos_num * 2) >= mkdep_len) {
2919                 /* Enlarge the buffer   */
2920                 size_t  len = out_p - output;
2921                 output = xrealloc( output, mkdep_len *= 2);
2922                 out_p = output + len;
2923             }
2924             pos_num--;
2925             for (pos_p = &pos[ 0]; pos_p <= &pos[ pos_num]; pos_p++) {
2926                 if (pos_p == &pos[ pos_num]) {      /* End of output    */
2927                     for (cp = output + *pos_p; *cp != '\n'; cp++)
2928                         ;
2929                     c = '\n';                       /* Append newline   */
2930                 } else {
2931                     cp = output + *(pos_p + 1) - 1;
2932                     while( *cp == ' ' || *cp == '\\' || *cp == '\n')
2933                         cp--;               /* Remove trailing spaces   */
2934                     c = *(++cp);
2935                 }
2936                 *cp = EOS;
2937                 out_p = stpcpy( out_p, output + *pos_p);
2938                 out_p = stpcpy( out_p, ":\n\n");
2939                 *cp = c;
2940             }
2941         }
2942         if (fp == fp_out) { /* To the same path with normal preprocessing   */
2943             mcpp_fputs( output, OUT);
2944         } else {        /* To the file specified by -MF, -MD, -MMD options  */
2945             fputs( output, fp);
2946             fclose( fp);
2947         }
2948         fp = NULL;      /* Clear for the next call in MCPP_LIB build        */
2949         return;
2950     }
2951 
2952     fnamlen = strlen( filename);
2953     /* Check the recorded filename  */
2954     for (pos_p = pos; pos_p < &pos[ pos_num]; pos_p++) {
2955         if (memcmp( output + *pos_p, filename, fnamlen) == 0)
2956             return;                 /* Already recorded filename    */
2957     }
2958     /* Any new header.  Append its name to output.  */
2959     if (llen + fnamlen > MAX_OUT_LEN) {         /* Line is long     */
2960         out_p = stpcpy( out_p, " \\\n ");       /* Fold it          */
2961         llen = 1;
2962     }
2963     llen += fnamlen + 1;
2964     if (pos_num >= MKDEP_MAX
2965             || out_p + fnamlen + 1 >= output + MKDEP_MAXLEN)
2966         cfatal( "Too long dependency line: %s", output, 0L, NULL);
2967     /* Need to enlarge the buffer   */
2968     if (pos_num >= pos_max) {
2969         pos = (size_t *) xrealloc( (char *) pos
2970                 , (pos_max *= 2) * sizeof (size_t *));
2971     }
2972     if (output + mkdep_len <= out_p + fnamlen + 1) {
2973         size_t  len = out_p - output;
2974         output = xrealloc( output, mkdep_len *= 2);
2975         out_p = output + len;
2976     }
2977     *out_p++ = ' ';
2978     pos[ pos_num++] = out_p - output;       /* Remember the offset  */
2979             /* Don't use pointer, since 'output' may be reallocated later.  */
2980     out_p = stpcpy( out_p, filename);
2981 }
2982 
md_init(const char * filename,char * output)2983 static char *   md_init(
2984     const char *    filename,   /* The source file name             */
2985     char *  output              /* Output to dependency file        */
2986 )
2987 /*
2988  * Initialize output file and target.
2989  */
2990 {
2991     char    prefix[ PATHMAX];
2992     char *  cp = NULL;
2993     size_t  len;
2994     char *  out_p;
2995     const char *    target = filename;
2996     const char *    cp0;
2997 
2998     if (! mkdep_target || ! mkdep_fp) {         /* Make target name */
2999 #ifdef  PATH_DELIM
3000         if ((cp0 = strrchr( target, PATH_DELIM)) != NULL)
3001             target = cp0 + 1;
3002 #endif
3003         if ((cp0 = strrchr( target, '.')) == NULL)
3004             len = strlen( target);
3005         else
3006             len = (size_t) (cp0 - target);
3007         memcpy( prefix, target, len);
3008         cp = prefix + len;
3009         *cp++ = '.';
3010     }
3011 
3012     if (! mkdep_fp) {   /* Unless already opened by -MF, -MD, -MMD options  */
3013         if (mkdep & MD_FILE) {
3014             strcpy( cp, "d");
3015             mkdep_fp = fopen( prefix, "w");
3016         } else {
3017             mkdep_fp = fp_out;  /* Output dependency line to normal output  */
3018             no_output++;                /* Without normal output    */
3019         }
3020     }
3021 
3022     if (mkdep_target) {         /* -MT or -MQ option is specified   */
3023         if (mkdep & MD_QUOTE) {         /* 'Quote' $, \t and space  */
3024             out_p = md_quote( output);
3025         } else {
3026             out_p = stpcpy( output, mkdep_target);
3027         }
3028     } else {
3029         strcpy( cp, OBJEXT);
3030         out_p = stpcpy( output, prefix);
3031     }
3032 
3033     *out_p++ = ':';
3034     *out_p = EOS;
3035     return  out_p;
3036 }
3037 
md_quote(char * output)3038 static char *   md_quote(
3039     char *  output
3040 )
3041 /*
3042  * 'Quote' $, tab and space.
3043  * This function was written referring to GCC V.3.2 source.
3044  */
3045 {
3046     char *  p;
3047     char *  q;
3048 
3049     for (p = mkdep_target; *p; p++, output++) {
3050         switch (*p) {
3051         case ' ':
3052         case '\t':
3053             /* GNU-make treats backslash-space sequence peculiarly  */
3054             for (q = p - 1; mkdep_target <= q && *q == '\\'; q--)
3055                 *output++ = '\\';
3056             *output++ = '\\';
3057             break;
3058         case '$':
3059             *output++ = '$';
3060             break;
3061         default:
3062             break;
3063         }
3064         *output = *p;
3065     }
3066     *output = EOS;
3067     return  output;
3068 }
3069 
3070 static const char *     toolong_fname =
3071         "Too long header name \"%s%.0ld%s\"";               /* _F_  */
3072 static const char *     excess_token =
3073         "Excessive token sequence \"%s\"";          /* _E_, _W1_    */
3074 
do_include(int next)3075 int     do_include(
3076     int     next        /* TRUE if the directive is #include_next   */
3077 )
3078 /*
3079  * Process the #include line.
3080  * There are three variations:
3081  *      #include "file"         search somewhere relative to the
3082  *                              current (or source) directory, if not
3083  *                              found, treat as #include <file>.
3084  *      #include <file>         Search in an implementation-dependent
3085  *                              list of places.
3086  *      #include macro-call     Expand the macro call, it must be one of
3087  *                              "file" or <file>, process as such.
3088  * On success : return TRUE;
3089  * On failure of syntax : return FALSE;
3090  * On failure of file opening : return FALSE.
3091  * do_include() always absorbs the line (including the <newline>).
3092  */
3093 {
3094     const char * const  no_name = "No header name";         /* _E_  */
3095     char    header[ PATHMAX + 16];
3096     int     token_type;
3097     char *  fname;
3098     char *  filename;
3099     int     delim;                          /* " or <, >            */
3100 
3101     if ((delim = skip_ws()) == '\n') {      /* No argument          */
3102         cerror( no_name, NULL, 0L, NULL);
3103         return  FALSE;
3104     }
3105     fname = infile->bptr - 1;       /* Current token for diagnosis  */
3106 
3107     if (standard && (char_type[ delim] & LET)) {    /* Maybe macro  */
3108         int     c;
3109         char    *hp;
3110 
3111         hp = header;
3112         *hp = EOS;
3113         c = delim;
3114         while (get_unexpandable( c, FALSE) != NO_TOKEN) {
3115                                 /* Expand any macros in the line    */
3116             if (header + PATHMAX < hp + (int) (workp - work_buf))
3117                 cfatal( toolong_fname, header, 0L, work_buf);
3118             hp = stpcpy( hp, work_buf);
3119             while (char_type[ c = get_ch()] & HSP)
3120                 *hp++ = c;
3121         }
3122         *hp = EOS;                          /* Ensure to terminate  */
3123         if (macro_line == MACRO_ERROR)      /* Unterminated macro   */
3124             return  FALSE;                  /*   already diagnosed. */
3125         unget_string( header, NULL);        /* To re-read           */
3126         delim = skip_ws();
3127         if (delim == '\n') {
3128             cerror( no_name, NULL, 0L, NULL);       /* Expanded to  */
3129             return  FALSE;                          /*   0 token.   */
3130         }
3131     }
3132 
3133     token_type = scan_token( delim, (workp = work_buf, &workp)
3134             , work_buf + PATHMAX);
3135     if (token_type == STR)                  /* String literal form  */
3136         goto  found_name;
3137     else if (token_type == OPE && openum == OP_LT)          /* '<'  */
3138         workp = scan_quote( delim, work_buf, work_buf + PATHMAX, TRUE);
3139                                         /* Re-construct or diagnose */
3140     else                                    /* Any other token in-  */
3141         goto  not_header;                   /*   cluding <=, <<, <% */
3142 
3143     if (workp == NULL)                      /* Missing closing '>'  */
3144         goto  syntax_error;
3145 
3146 found_name:
3147     *--workp = EOS;                         /* Remove the closing and   */
3148     fname = save_string( &work_buf[ 1]);    /*  the starting delimiter. */
3149 
3150     if (skip_ws() != '\n') {
3151         if (standard) {
3152             cerror( excess_token, infile->bptr-1, 0L, NULL);
3153             skip_nl();
3154             goto  error;
3155         } else if (mcpp_mode == OLD_PREP) {
3156             skip_nl();
3157         } else {
3158             if (warn_level & 1)
3159                 cwarn( excess_token, infile->bptr-1, 0L, NULL);
3160             skip_nl();
3161         }
3162     }
3163 
3164 #if SYS_FAMILY == SYS_WIN
3165     bsl2sl( fname);
3166 #endif
3167     filename = fname;
3168 #if NO_DIR                              /* Unofficial feature           */
3169     if (no_dir) {                       /* Strip directory components   */
3170         char    src_dir[ PATHMAX] = { EOS, };
3171         if (has_directory( fname, src_dir))
3172             filename = fname + strlen( src_dir);
3173         delim = '"';    /* Even a system header is handled as a local one   */
3174     }
3175 #endif
3176     if (open_include( filename, (delim == '"'), next)) {
3177         /* 'fname' should not be free()ed, it is used as file->         */
3178         /*      real_fname and has been registered into fnamelist[]     */
3179         return  TRUE;
3180     }
3181 
3182     cerror( "Can't open include file \"%s\"", filename, 0L, NULL);  /* _E_  */
3183 error:
3184     free( fname);
3185     return  FALSE;
3186 
3187 not_header:
3188     cerror( "Not a header name \"%s\"", fname, 0L, NULL);   /* _E_  */
3189 syntax_error:
3190     skip_nl();
3191     return  FALSE;
3192 }
3193 
open_include(char * filename,int searchlocal,int next)3194 static int  open_include(
3195     char *  filename,               /* File name to include         */
3196     int     searchlocal,            /* TRUE if #include "file"      */
3197     int     next                    /* TRUE if #include_next        */
3198 )
3199 /*
3200  * Open an include file.  This routine is only called from do_include() above.
3201  * It searches the list of directories via search_dir() and opens the file
3202  * via open_file(), linking it into the list of active files.
3203  * Returns TRUE if the file was opened, FALSE if it fails.
3204  */
3205 {
3206     char    src_dir[ PATHMAX] = { EOS, };   /* Directory part of includer   */
3207     int     full_path;              /* Filename is full-path-list   */
3208     int     has_dir = FALSE;        /* Includer has directory part  */
3209     int     has_dir_src = FALSE;
3210     int     has_dir_fname = FALSE;
3211 
3212     full_path = is_full_path( filename);
3213 
3214     if (!full_path && searchlocal && (search_rule & SOURCE)) {
3215         has_dir_src  = has_directory( infile->src_dir, src_dir);
3216         has_dir_fname = has_directory( infile->real_fname
3217                 , src_dir + strlen( src_dir));
3218         /* Get directory part of the parent file of the file to include.*/
3219         /* Note that infile->dirp of main input file is set to "" and   */
3220         /* remains the same even if -include options are processed.     */
3221         has_dir = has_dir_src || has_dir_fname
3222                 || (**(infile->dirp) != EOS);
3223     }
3224     if (mcpp_debug & PATH)
3225         mcpp_fprintf( DBG, "filename: %s\n", filename);
3226 
3227 #if COMPILER == GNUC
3228     if (! full_path) {
3229         if (i_split                     /* -I- option is specified  */
3230                 || next)                        /* or #include_next */
3231         goto  search_dirs;
3232     }
3233 #endif
3234 
3235     if ((searchlocal && ((search_rule & CURRENT) || !has_dir)) || full_path) {
3236         /*
3237          * Look in local directory first.
3238          * Try to open filename relative to the "current directory".
3239          */
3240         if (open_file( &null, NULL, filename, searchlocal && !full_path
3241                 , FALSE, FALSE))
3242             return  TRUE;
3243         if (full_path)
3244             return  FALSE;
3245     }
3246 
3247     if (searchlocal && (search_rule & SOURCE) && has_dir) {
3248         /*
3249          * Look in local directory of source file.
3250          * Try to open filename relative to the "source directory".
3251          */
3252         if (open_file( infile->dirp, src_dir, filename, TRUE, FALSE, FALSE))
3253             return  TRUE;
3254     }
3255 
3256 #if COMPILER == MSC
3257     if (searchlocal) {
3258         /* Visual C searches ancestor source's directory, too.  */
3259         FILEINFO *  file = infile;
3260         while ((file = file->parent) != NULL) {
3261             /* Search each parent includer's directory  */
3262             if (open_file( file->dirp, src_dir, filename, TRUE, FALSE, FALSE))
3263                 return  TRUE;
3264         }
3265     }
3266 #endif
3267 #if COMPILER == GNUC
3268 search_dirs:
3269     if (searchlocal) {
3270         /* Search the directories specified by -iquote option, if any.  */
3271         const char **   qdir;
3272         for (qdir = quote_dir; qdir < quote_dir_end; qdir++) {
3273             if (open_file( qdir, NULL, filename, FALSE, FALSE, FALSE))
3274                 return  TRUE;
3275         }
3276     }
3277 #endif
3278     /* Search the include directories   */
3279     if (search_dir( filename, searchlocal, next))
3280         return  TRUE;
3281 
3282     return  FALSE;
3283 }
3284 
has_directory(const char * source,char * directory)3285 static int  has_directory(
3286     const char *    source,         /* Filename to examine          */
3287     char *  directory               /* Put directory stuff here     */
3288 )
3289 /*
3290  * If a directory is found in the 'source' filename string (i.e. "includer"),
3291  * the directory part of the string is copied to 'directory' and
3292  * has_directory() returns TRUE.
3293  * Else, nothing is copied and it returns FALSE.
3294  */
3295 {
3296     const char *    sp;
3297     size_t  len;
3298 
3299     if (! source)
3300         return  FALSE;
3301     if ((sp = strrchr( source, PATH_DELIM)) == NULL) {
3302         return  FALSE;
3303     } else {
3304         len = (size_t)(sp - source) + 1;    /* With path-delimiter  */
3305         memcpy( directory, source, len);
3306         directory[ len] = EOS;
3307         return  TRUE;
3308     }
3309 }
3310 
is_full_path(const char * path)3311 static int  is_full_path(
3312     const char *    path
3313 )
3314 /*
3315  * Check whether the path is a full (absolute) path list or not.
3316  */
3317 {
3318     if (! path)
3319         return  FALSE;
3320 #if SYS_FAMILY == SYS_UNIX
3321     if (path[0] == PATH_DELIM)
3322 #elif   SYS_FAMILY == SYS_WIN
3323     if ((path[1] == ':' && path[2] == PATH_DELIM)   /* "C:/path"    */
3324             || path[0] == PATH_DELIM)       /* Root dir of current drive    */
3325 #elif   1
3326 /* For other systems you should write code here.    */
3327     if (path[0] == PATH_DELIM)
3328 #endif
3329         return  TRUE;
3330     else
3331         return  FALSE;
3332 }
3333 
search_dir(char * filename,int searchlocal,int next)3334 static int  search_dir(
3335     char *  filename,               /* File name to include         */
3336     int     searchlocal,            /* #include "header.h"          */
3337     int     next                    /* TRUE if #include_next        */
3338 )
3339 /*
3340  * Look in any directories specified by -I command line arguments,
3341  * specified by environment variable, then in the builtin search list.
3342  */
3343 {
3344     const char **   incptr;                 /* -> inlcude directory */
3345 
3346     incptr = incdir;
3347 #if COMPILER == GNUC
3348     if (next && **inc_dirp != EOS)
3349         incptr = inc_dirp + 1;
3350         /* In case of include_next search after the includer's directory    */
3351 #endif
3352 
3353     for ( ; incptr < incend; incptr++) {
3354         if (strlen( *incptr) + strlen( filename) >= PATHMAX)
3355             cfatal( toolong_fname, *incptr, 0L, filename);  /* _F_  */
3356 #if SYSTEM == SYS_MAC
3357         if (incptr == to_search_framework && ! searchlocal) {
3358                                 /* Now search the framework dirs    */
3359             if (search_framework( filename)) {          /* Found    */
3360                 if (in_import)  /* "#import"ed file is once only    */
3361                     do_once( infile->full_fname);
3362                 return  TRUE;
3363             }
3364             /* Else continue to search incptr   */
3365         }
3366 #endif
3367         if (open_file( incptr, NULL, filename, FALSE, FALSE, FALSE))
3368             /* Now infile has been renewed  */
3369             return  TRUE;
3370     }
3371 
3372     return  FALSE;
3373 }
3374 
open_file(const char ** dirp,const char * src_dir,const char * filename,int local,int include_opt,int sys_frame)3375 static int  open_file(
3376     const char **   dirp,           /* Pointer to include directory */
3377     const char *    src_dir,        /* Source directory of includer */
3378     const char *    filename,       /* Filename (possibly has directory)    */
3379     int         local,                      /* #include "file"      */
3380     int         include_opt,        /* Specified by -include option */
3381     int         sys_frame           /* System framework header (for SYS_MAC)*/
3382 )
3383 /*
3384  * Open a file, add it to the linked list of open files, close the includer
3385  * if nessesary and truncate the includer's buffer.
3386  * This is called from open_include() and at_start().
3387  */
3388 {
3389     char        dir_fname[ PATHMAX] = { EOS, };
3390 #if HOST_COMPILER == BORLANDC
3391     /* Borland's fopen() does not set errno.    */
3392     static int  max_open = FOPEN_MAX - 5;
3393 #else
3394     static int  max_open;
3395 #endif
3396     int         len;
3397     FILEINFO *  file = infile;
3398     FILE *      fp;
3399     char *      fullname;
3400     const char *    fname;
3401 
3402     errno = 0;      /* Clear errno possibly set by path searching   */
3403 #if SYSTEM == SYS_MAC && COMPILER == GNUC
3404     if (strlen( *dirp) > 5
3405             && str_case_eq( *dirp + strlen( *dirp) - 5, ".hmap")) {
3406         /* Search header map file for a header  */
3407         if (! search_header_map( *dirp, filename, dir_fname))
3408             return  NULL;
3409         fname = dir_fname;                  /* Found a path-list    */
3410         dirp = &null;
3411         goto  search;
3412     } else
3413 #endif
3414     {
3415         if (mcpp_debug & PATH)
3416             mcpp_fprintf( DBG, "Searching %s%s%s\n", *dirp
3417                     , src_dir ? src_dir : null, filename);
3418     }
3419     /* src_dir is usually NULL.  This is specified to   */
3420     /* search the source directory of the includer.     */
3421     if (src_dir && *src_dir != EOS) {
3422         strcpy( dir_fname, src_dir);
3423         strcat( dir_fname, filename);
3424         fname = dir_fname;
3425     } else {
3426         fname = filename;
3427     }
3428 search:
3429     fullname = norm_path( *dirp, fname, TRUE, FALSE);
3430                                     /* Convert to absolute path     */
3431     if (! fullname)                 /* Non-existent or directory    */
3432         return  FALSE;
3433     if (standard && included( fullname))        /* Once included    */
3434         goto  true;
3435 
3436     if ((max_open != 0 && max_open <= include_nest)
3437                             /* Exceed the known limit of open files */
3438             || ((fp = fopen( fullname, "r")) == NULL && errno == EMFILE)) {
3439                             /* Reached the limit for the first time */
3440         if (mcpp_debug & PATH) {
3441 #if HOST_COMPILER == BORLANDC
3442             if (include_nest == FOPEN_MAX - 5)
3443 #else
3444             if (max_open == 0)
3445 #endif
3446                 mcpp_fprintf( DBG,
3447     "#include nest reached at the maximum of system: %d, returned errno: %d\n"
3448                     , include_nest, errno);
3449         }
3450         /*
3451          * Table of open files is full.
3452          * Remember the file position and close the includer.
3453          * The state will be restored by get_line() on end of the included.
3454          */
3455         file->pos = ftell( file->fp);
3456         fclose( file->fp);
3457         /* In case of failure, re-open the includer */
3458         if ((fp = fopen( fullname, "r")) == NULL) {
3459             file->fp = fopen( cur_fullname, "r");
3460             fseek( file->fp, file->pos, SEEK_SET);
3461             goto  false;
3462         }
3463         if (max_open == 0)      /* Remember the limit of the system */
3464             max_open = include_nest;
3465     } else if (fp == NULL)                  /* No read permission   */
3466         goto  false;
3467     /* Truncate buffer of the includer to save memory   */
3468     len = (int) (file->bptr - file->buffer);
3469     if (len) {
3470         file->buffer = xrealloc( file->buffer, len + 1);
3471         file->bptr = file->buffer + len;
3472     }
3473 
3474     if (! include_opt)
3475         sharp( NULL, 0);    /* Print includer's line num and fname  */
3476     add_file( fp, src_dir, filename, fullname, include_opt);
3477     /* Add file-info to the linked list.  'infile' has been just renewed    */
3478     /*
3479      * Remember the directory for #include_next.
3480      * Note: inc_dirp is restored to the parent includer's directory
3481      *   by get_ch() when the current includer is finished.
3482      */
3483     infile->dirp = inc_dirp = dirp;
3484 #if 0   /* This part is only for debugging  */
3485     chk_dirp( dirp);
3486 #endif
3487 #if COMPILER == GNUC
3488     if ((**dirp != EOS && sys_dirp <= dirp && dirp <= incend)
3489 #if SYSTEM == SYS_MAC
3490             || sys_frame
3491 #endif
3492             )
3493         infile->sys_header = TRUE;      /* Found in a system header dir     */
3494     else
3495         infile->sys_header = FALSE;
3496 #endif
3497     cur_fullname = fullname;
3498 
3499     if (option_flags.z) {
3500         no_output++;        /* Don't output the included file       */
3501         if (include_nest == 2)
3502             mcpp_fprintf( OUT, "#include \"%s\"\n", fullname);
3503             /* Output #include line instead, if it is in main source file   */
3504     } else if (! include_opt) {     /* Do not sharp() on -include   */
3505         src_line = 1;                   /* Working on line 1 now    */
3506         sharp( NULL, 1);    /* Print out the included file name     */
3507     }
3508     src_line = 0;                       /* To read the first line   */
3509 
3510     if (mkdep && ((mkdep & MD_SYSHEADER) || ! infile->sys_header))
3511         put_depend( fullname);          /* Output dependency line   */
3512 
3513 true:
3514     return  TRUE;
3515 false:
3516     free( fullname);
3517     return  FALSE;
3518 }
3519 
add_file(FILE * fp,const char * src_dir,const char * filename,const char * fullname,int include_opt)3520 void    add_file(
3521     FILE *      fp,                         /* Open file pointer    */
3522     const char *    src_dir,                /* Directory of source  */
3523     const char *    filename,               /* Name of the file     */
3524     const char *    fullname,               /* Full path list       */
3525     int         include_opt         /* File specified by -include option    */
3526 )
3527 /*
3528  * Initialize tables for this open file.  This is called from open_file()
3529  * (for #include files), and from the entry to MCPP to open the main input
3530  * file.  It calls a common routine get_file() to build the FILEINFO
3531  * structure which is used to read characters.
3532  */
3533 {
3534     FILEINFO *      file;
3535     const char *    too_many_include_nest =
3536             "More than %.0s%ld nesting of #include";    /* _F_ _W4_ */
3537 
3538     filename = set_fname( filename);    /* Search or append to fnamelist[]  */
3539     fullname = set_fname( fullname);    /* Search or append to fnamelist[]  */
3540     file = get_file( filename, src_dir, fullname, (size_t) NBUFF, include_opt);
3541                                         /* file == infile           */
3542     file->fp = fp;                      /* Better remember FILE *   */
3543     cur_fname = filename;
3544 
3545     if (include_nest >= INCLUDE_NEST)   /* Probably recursive #include      */
3546         cfatal( too_many_include_nest, NULL, (long) INCLUDE_NEST, NULL);
3547     if (standard && (warn_level & 4)
3548             && include_nest == std_limits.inc_nest + 1)
3549         cwarn( too_many_include_nest, NULL, (long) std_limits.inc_nest, NULL);
3550     include_nest++;
3551 }
3552 
set_fname(const char * filename)3553 static const char *     set_fname(
3554     const char *    filename
3555 )
3556 /*
3557  * Register the source filename to fnamelist[].
3558  * Search fnamelist[] for filename or append filename to fnamelist[].
3559  * Returns the pointer.
3560  * file->real_fname and file->full_fname points into fnamelist[].
3561  */
3562 {
3563     INC_LIST *  fnamep;
3564     size_t      fnamelen;
3565 
3566     if (fnamelist == NULL) {            /* Should be initialized    */
3567         max_fnamelist = INIT_NUM_FNAMELIST;
3568         fnamelist = (INC_LIST *) xmalloc( sizeof (INC_LIST) * max_fnamelist);
3569         fname_end = &fnamelist[ 0];
3570     } else if (fname_end - fnamelist >= max_fnamelist) {
3571                                 /* Buffer full: double the elements */
3572         fnamelist = (INC_LIST *) xrealloc( (void *) fnamelist
3573                 , sizeof (INC_LIST) * max_fnamelist * 2);
3574         fname_end = &fnamelist[ max_fnamelist];
3575         max_fnamelist *= 2;
3576     }
3577 
3578     /* Register the filename in fnamelist[] */
3579     fnamelen = strlen( filename);
3580     for (fnamep = fnamelist; fnamep < fname_end; fnamep++) {
3581         if (fnamep->len == fnamelen && str_case_eq( fnamep->name, filename))
3582             return  filename;           /* Already registered       */
3583     }
3584     fname_end->name = xmalloc( fnamelen + 1);
3585     filename = strcpy( fname_end->name, filename);
3586                                 /* Global pointer for get_file()    */
3587     fname_end->len = fnamelen;
3588     fname_end++;
3589 
3590     return  filename;
3591 }
3592 
3593 #if SYSTEM == SYS_MAC
3594 #if COMPILER == GNUC
3595 
3596 /* Routines to search "header map" file of Xcode / Apple-GCC.       */
3597 /* search_header_map() and hmap_hash() were written referring to    */
3598 /* c-incpath.c of Apple-GCC-4.0.1.                                  */
3599 
search_header_map(const char * hmap_file,const char * filename,char * pathlist)3600 static char *   search_header_map(
3601     const char *    hmap_file,              /* Header map file      */
3602     const char *    filename,               /* Filename to search   */
3603     char *          pathlist        /* Buffer for a found pathlist  */
3604 )
3605 /*
3606  * Search a table in "header map" file for a header.
3607  */
3608 {
3609     struct stat     stat_buf;
3610     FILE *          fp;
3611     size_t          fsize;
3612     const char *    contents;
3613     struct hmap_header_map *    hmap;
3614     struct hmap_bucket *        buckets;
3615     const char *    strings;
3616     uint32          mask;
3617     uint32          key_offs;
3618     uint32          i;
3619 
3620     stat( hmap_file, &stat_buf);            /* Get size of the file */
3621     fsize = stat_buf.st_size;
3622     contents = xmalloc( fsize + 1);
3623     fp = fopen( hmap_file, "r");
3624     fread( contents, fsize, 1, fp);     /* Read whole of the file at once   */
3625     hmap = (struct hmap_header_map *) contents;
3626 
3627     strings = ((const char *) hmap) + hmap->strings_offset;
3628     buckets = hmap->buckets;
3629     mask = hmap->capacity - 1;
3630     i = hmap_hash( filename) & mask;
3631     while ((key_offs = buckets[ i].key) != 0) {
3632         if (str_case_eq( filename, strings + key_offs)) {
3633             /* The names match.  Make path-list.    */
3634             char *  cp = stpcpy( pathlist, strings + buckets[ i].value.prefix);
3635             strcpy( cp, strings + buckets[ i].value.suffix);
3636             break;
3637         }
3638         i = ++i & mask;
3639     }
3640     free( contents);
3641     return  key_offs ? pathlist : NULL;
3642 }
3643 
hmap_hash(const char * fname)3644 static unsigned hmap_hash(
3645     const char *    fname                   /* header name          */
3646 )
3647 /*
3648  * Get hash value for the fname.
3649  */
3650 {
3651     const char *    sp;
3652     unsigned        hash_code = 0;
3653 
3654     for (sp = fname; *sp; sp++)
3655         hash_code += tolower( *sp & 0xFF) * 13;
3656     return  hash_code;
3657 }
3658 #endif  /* COMPILER == GNUC */
3659 
init_framework(void)3660 static void     init_framework( void)
3661 /*
3662  * Initialize framework[].
3663  */
3664 {
3665     char *  framework_dir;
3666     /* Some frameworks may have been already specified by -F option.    */
3667     sys_framework = num_framework;      /* These are system frameworks  */
3668 #ifdef  FRAMEWORK1
3669     framework_dir = norm_dir( FRAMEWORK1, TRUE);
3670     if (framework_dir)
3671         framework[ num_framework++] = framework_dir;
3672 #endif
3673 #ifdef  FRAMEWORK2
3674     framework_dir = norm_dir( FRAMEWORK2, TRUE);
3675     if (framework_dir)
3676         framework[ num_framework++] = framework_dir;
3677 #endif
3678 #ifdef  FRAMEWORK3
3679     framework_dir = norm_dir( FRAMEWORK3, TRUE);
3680     if (framework_dir)
3681         framework[ num_framework++] = framework_dir;
3682 #endif
3683     if (num_framework >= MAX_FRAMEWORK) {
3684         mcpp_fputs( "Too many Framework directories.", ERR);
3685         longjmp( error_exit, -1);
3686     }
3687 }
3688 
3689 static const char *     dot_frame = ".framework";
3690 
search_framework(char * filename)3691 static int      search_framework(
3692     char *  filename
3693 )
3694 /*
3695  * Search "Framework" directories.
3696  * 'frame/header.h' is converted to
3697  * '/System/Library/Frameworks/frame.framework/Headers/header.h',
3698  * '/System/Library/Frameworks/frame.framework/PrivateHeaders/header.h',
3699  * and so on.
3700  */
3701 {
3702     char        fullname[ PATHMAX + 1];
3703     FILEINFO *  file;
3704     char *      frame, * fname, * cp1, * cp2;
3705     int         sys_frame = FALSE;
3706     int         i;
3707 
3708     cp1 = cp2 = strchr( filename, PATH_DELIM);
3709     /*
3710      * 'filename' should be <frame/header> format or sometimes
3711      *      <frame/dir/header>.
3712      * e.g.: <Foundation/Foundation.h>, <CarbonCore/OSUtils.h>
3713      *      or <IOKit/pwr_mgt/IOPMLib.h>.
3714      */
3715     if (! cp1)
3716         return  FALSE;
3717     *cp1 = EOS;
3718     frame = filename;
3719     fname = cp1 + 1;
3720 
3721     /* Search framework[] directories   */
3722     for (i = 0; i < num_framework; i++) {
3723         cp1 = stpcpy( fullname, framework[ i]);
3724                     /* 'fullname' e.g.: /System/Library/Frameworks/ */
3725         if (search_subdir( fullname, cp1, frame, fname, sys_framework <= i))
3726             return  TRUE;
3727     }
3728 
3729     /*
3730      * Search subframework dirs searching its possible parent framework
3731      * starting from current file's directory to its ancestors.
3732      * Header file in subframework directories should be included only
3733      * by its parent or sibling framework headers.
3734      */
3735     for (i = sys_framework; i < num_framework; i++) {
3736         size_t  frame_len, fname_len;
3737         frame_len = strlen( framework[ i]);
3738         fname_len = strlen( infile->real_fname);
3739         if (fname_len <= frame_len)
3740             continue;
3741         if (memcmp( framework[ i], infile->real_fname, frame_len) == 0) {
3742             sys_frame = TRUE;
3743             break;
3744         }
3745     }
3746     for (file = infile; file; file = file->parent) {
3747         const char *    dot;
3748         size_t  len;
3749 
3750         if (! file->fp)
3751             continue;
3752         dot = strstr( file->real_fname, dot_frame);
3753         if (! dot)
3754             continue;
3755         len = dot - file->real_fname + strlen( dot_frame) + 1;
3756         memcpy( fullname, file->real_fname, len);
3757         cp1 = fullname + len;
3758         cp1 = stpcpy( cp1, "Frameworks/");
3759         /* 'fullname' e.g.:                                             */
3760         /* /System/Library/Frameworks/Foundation.framework/Frameworks/  */
3761         if (search_subdir( fullname, cp1, frame, fname, sys_frame))
3762             return  TRUE;
3763     }
3764 
3765     *cp2 = PATH_DELIM;      /* Restore original include file format */
3766 
3767     return  FALSE;
3768 }
3769 
search_subdir(char * fullname,char * cp,char * frame,char * fname,int sys_frame)3770 static int      search_subdir(
3771     char *  fullname,               /* Buffer for path-list to open */
3772     char *  cp,                     /* Latter half of 'fullname'    */
3773     char *  frame,                  /* 'frame' of <frame/header>    */
3774     char *  fname,                  /* 'header' of <frame/header>   */
3775                 /* or sometimes 'dir/header' of <frame/dir/header>  */
3776     int     sys_frame               /* System framework header ?    */
3777 )
3778 /*
3779  * Make path-list and try to open.
3780  */
3781 {
3782     static const char *     subdir[] = { "Headers", "PrivateHeaders", NULL};
3783     int     j, n;
3784 
3785     cp += sprintf( cp, "%s%s%c", frame, dot_frame, PATH_DELIM);
3786     for (j = 0; subdir[ j] != NULL; j++) {
3787         n = sprintf( cp, "%s%c%s", subdir[ j], PATH_DELIM, fname);
3788         /*
3789          * 'fullname' is for example:
3790          * /System/Library/Frameworks/Foundation.framework/Headers/
3791          *      Foundation.h,
3792          * /System/Library/Frameworks/Foundation.framework/Frameworks/
3793          *      CarbonCore.framework/Headers/OSUtils.h,
3794          * or /System/Library/Frameworks/IOKit.framework/Headers/
3795          *      pwr_mgt/IOPMLib.h.
3796          * Pass this as one filename argument to open_file() rather than
3797          * deviding to directory part and file part.  The first argument to
3798          * open_file() which is a pointer to the directory part is remembered
3799          * by FILEINFO struct.  But, 'fullname' is over-written each time,
3800          * and the former path-list is lost soon.  Therefore, it cannot be
3801          * passed as the first argument.  In addition, though the first
3802          * argument to open_file() is needed for #include_next, this directive
3803          * has no meaning in framework.
3804          */
3805         if ((cp - fullname) + n > PATHMAX)
3806             cfatal( "Too long framework path", NULL, 0L, NULL); /* _F_  */
3807         if (open_file( &null, NULL, fullname, FALSE, FALSE, sys_frame))
3808             return  TRUE;
3809     }
3810     return  FALSE;
3811 }
3812 
3813 #endif  /* SYSTEM == SYS_MAC    */
3814 
3815 #if 0   /* This part is only for debugging  */
3816 static int  chk_dirp(
3817     const char **   dirp
3818 )
3819 /*
3820  * Check the validity of include directory specified for open_file().
3821  * Called only from open_file().
3822  */
3823 {
3824     const char **   ip;
3825 
3826     if (dirp == &null)
3827         return  TRUE;
3828 
3829     for (ip = incdir; ip < incend; ip++)
3830         if (dirp == ip)
3831             break;
3832     if (ip == incend) {
3833 #if COMPILER == MSC
3834         FILEINFO *  pfile = infile->parent;
3835         if (pfile) {
3836             while ((pfile = pfile->parent) != NULL) {
3837                 /* Search each parent includer's directory  */
3838                 if (dirp == pfile->dirp)
3839                     break;
3840             }
3841         }
3842         if (! pfile)
3843 #endif
3844 #if COMPILER == GNUC
3845         const char **   qdir;
3846         for (qdir = quote_dir; qdir < quote_dir_end; qdir++) {
3847             if (dirp == qdir)
3848                 break;
3849         }
3850         if (qdir == quote_dir_end)
3851 #endif
3852         {
3853             cfatal( "Bug: *dirp:%s is invalid", *dirp, 0L, NULL);
3854             return  FALSE;
3855         }
3856     }
3857     return  TRUE;
3858 }
3859 #endif
3860 
3861 FILEINFO*       sh_file;
3862 int             sh_line;
3863 
sharp(FILEINFO * sharp_file,int flag)3864 void    sharp(
3865     FILEINFO *  sharp_file,
3866     int         flag        /* Flag to append to the line for GCC   */
3867 )
3868 /*
3869  * Output a line number line.
3870  * 'file' is 'sharp_file' if specified,
3871  * else (i.e. 'sharp_file' is NULL) 'infile'.
3872  */
3873 {
3874     FILEINFO *  file;
3875     int         line;
3876 
3877     file = sharp_file ? sharp_file : infile;
3878     if (! file)
3879         return;
3880     while (! file->fp)
3881         file = file->parent;
3882     line = sharp_file ? sharp_file->line : src_line;
3883     if (no_output || option_flags.p || file == NULL
3884             || (file == sh_file && line == sh_line))
3885         goto  sharp_exit;
3886     sh_file = file;
3887     sh_line = line;
3888     if (keep_comments)
3889         mcpp_fputc( '\n', OUT);         /* Ensure to be on line top */
3890     if (std_line_prefix)
3891         mcpp_fprintf( OUT, "#line %ld", line);
3892     else
3893         mcpp_fprintf( OUT, "%s%ld", LINE_PREFIX, line);
3894     cur_file( file, sharp_file, flag);
3895     mcpp_fputc( '\n', OUT);
3896 sharp_exit:
3897     wrong_line = FALSE;
3898 }
3899 
cur_file(FILEINFO * file,FILEINFO * sharp_file,int flag)3900 static void cur_file(
3901     FILEINFO *  file,                   /* infile or sharp_file     */
3902     FILEINFO *  sharp_file,             /* The 'file' or NULL       */
3903     int         flag                    /* Flag to append for GCC   */
3904 )
3905 /*
3906  * Output current source file name and line number.
3907  * Called only from sharp() above.
3908  */
3909 {
3910     const char *    name;
3911 
3912     if (mcpp_debug & MACRO_CALL) {  /* In macro notification mode   */
3913         if (sharp_file)                         /* Main input file  */
3914             name = file->filename;
3915         else                /* Output full-path-list, normalized    */
3916             name = cur_fullname;
3917     } else {                /* Usually, the path not "normalized"   */
3918         if (sharp_file) {                       /* Main input file  */
3919             name = file->filename;
3920         } else if (str_eq( file->filename, file->real_fname)) {
3921             sprintf( work_buf, "%s%s", *(file->dirp), cur_fname);
3922             name = work_buf;
3923         } else {            /* Changed by '#line fname' directive   */
3924             name = file->filename;
3925         }
3926     }
3927     if (sharp_filename == NULL || ! str_eq( name, sharp_filename)) {
3928         if (sharp_filename != NULL)
3929             free( sharp_filename);
3930         sharp_filename = save_string( name);
3931     }
3932     mcpp_fprintf( OUT, " \"%s\"", name);
3933 #if COMPILER == GNUC
3934     if (! std_line_prefix) {
3935         if (flag) {
3936             mcpp_fputc( ' ', OUT);
3937             mcpp_fputc( '0' + flag, OUT);
3938         }
3939         if (file->sys_header)
3940             mcpp_fputs( " 3", OUT);
3941     }
3942 #endif
3943 }
3944 
3945 #if SYS_FAMILY == SYS_WIN
3946 
bsl2sl(char * filename)3947 static char *   bsl2sl(
3948     char * filename
3949 )
3950 /*
3951  * Convert '\\' in the path-list to '/'.
3952  */
3953 {
3954     static int  diagnosed = FALSE;
3955     char *  cp;
3956 
3957     cp = filename;
3958 
3959     while (*cp) {
3960         if (bsl_in_mbchar) {
3961             int     c;
3962             c = *cp & UCHARMAX;
3963             if (char_type[ c] & mbchk) {    /* First byte of MBCHAR */
3964                 char    tmp[ PATHMAX];
3965                 char *  tp = tmp;
3966                 *tp++ = *cp++;
3967                 mb_read( c, &cp, &tp);
3968                             /* Read over the multi-byte characters  */
3969                 continue;
3970             }
3971         }
3972         if (*cp == '\\') {
3973             *cp++ = PATH_DELIM;
3974             if (!diagnosed && (warn_level & 2) && (warn_level != -1)) {
3975                             /* Backslash in source program          */
3976                 cwarn( "Converted \\ to %s", "/", 0L, NULL);        /* _W2_ */
3977                     diagnosed = TRUE;       /* Diagnose only once   */
3978             }
3979         } else {
3980             cp++;
3981         }
3982     }
3983 
3984     return  filename;
3985 }
3986 
3987 #endif  /* SYS_FAMILY == SYS_WIN    */
3988 
3989 static const char * const   unknown_arg =
3990         "Unknown argument \"%s\"";      /*_W1_*/
3991 static const char * const   not_ident =
3992         "Not an identifier \"%s\"";     /*_W1_*/
3993 
is_junk(void)3994 static int  is_junk( void)
3995 /*
3996  * Check the trailing junk in a directive line.
3997  * This routine is never called in OLD_PREP mode.
3998  */
3999 {
4000     int     c;
4001 
4002     c = skip_ws();
4003     unget_ch();
4004     if (c != '\n') {                        /* Trailing junk        */
4005         if (warn_level & 1)
4006             cwarn( unknown_arg, infile->bptr, 0L, NULL);
4007         return TRUE;
4008     } else {
4009         return FALSE;
4010     }
4011 }
4012 
4013 #define PUSH    1
4014 #define POP    -1
4015 
4016 #define __SETLOCALE     1       /* #pragma __setlocale( "encoding") */
4017 #define SETLOCALE       2       /* #pragma setlocale( "encoding")   */
4018 
do_pragma(void)4019 void    do_pragma( void)
4020 /*
4021  * Process the #pragma lines.
4022  * 1. Process the sub-directive for MCPP.
4023  * 2. Pass the line to the compiler-proper.
4024  *      #pragma MCPP put_defines, #pragma MCPP preprocess,
4025  *      #pragma MCPP preprocessed and #pragma once are, however, not put
4026  *      out so as not to duplicate output when re-preprocessed.
4027  * When EXPAND_PRAGMA == TRUE and (__STDC_VERSION__ >= 199901L or
4028  * __cplusplus >= 199901L), the line is subject to macro expansion unless
4029  * the next to 'pragma' token is one of 'STDC', 'GCC' or 'MCPP'.
4030  */
4031 {
4032     int         c;
4033     int         warn = FALSE;               /* Necessity of warning */
4034     int         token_type;
4035     char *      bp;                         /* Pointer to argument  */
4036     char *      tp;
4037     FILEINFO *  file;
4038 
4039     wrong_line = TRUE;                      /* In case of error     */
4040     c = skip_ws();
4041     bp = infile->bptr - 1;  /* Remember token to pass to compiler   */
4042     if (c == '\n') {
4043         if (warn_level & 1)
4044             cwarn( "No sub-directive", NULL, 0L, NULL);     /* _W1_ */
4045         unget_ch();
4046         return;
4047     }
4048     token_type = scan_token( c, (tp = work_buf, &tp), work_end);
4049 #if EXPAND_PRAGMA
4050 #if COMPILER == MSC
4051     if (token_type == NAM
4052             && !str_eq( identifier, "STDC") && !str_eq( identifier, "MCPP")) {
4053 #else
4054     if (stdc3 && token_type == NAM
4055             && !str_eq( identifier, "STDC") && !str_eq( identifier, "MCPP")) {
4056 #endif
4057         DEFBUF *        defp;
4058         char *          mp;
4059         char *          mp_end;
4060         LINE_COL        line_col = { 0L, 0};
4061 
4062         bp = mp = xmalloc( (size_t)(NMACWORK + IDMAX));
4063                                     /* Buffer for macro expansion   */
4064         mp_end = mp + NMACWORK;
4065         tp = stpcpy( mp, identifier);
4066         do {                /* Expand all the macros in the line    */
4067             int     has_pragma;
4068             if (token_type == NAM && (defp = is_macro( &tp)) != NULL) {
4069                 tp = expand_macro( defp, bp, mp_end, line_col, & has_pragma);
4070                 if (has_pragma)
4071                 cerror( "_Pragma operator found in #pragma line"    /* _E_  */
4072                             , NULL, 0L, NULL);
4073                 if (! stdc3 && (warn_level & 2))
4074                     cwarn(
4075                 "\"%s\" is macro expanded in other than C99 mode"   /* _W2_ */
4076                             , identifier, 0L, NULL);
4077             }
4078             token_type = scan_token( c = get_ch(), (bp = tp, &tp), mp_end);
4079         } while (c != '\n');
4080         unget_string( mp, NULL);                    /* To re-read   */
4081         free( mp);
4082         c = skip_ws();
4083         bp = infile->bptr - 1;
4084         token_type = scan_token( c, (tp = work_buf, &tp), work_end);
4085     }
4086 #endif
4087     if (token_type != NAM) {
4088         if (warn_level & 1)
4089             cwarn( not_ident, work_buf, 0L, NULL);
4090         goto  skip_nl;
4091     } else if (str_eq( identifier, "once")) {   /* #pragma once     */
4092        if (! is_junk()) {
4093             file = infile;
4094             while (file->fp == NULL)
4095                 file = file->parent;
4096             do_once( file->full_fname);
4097             goto  skip_nl;
4098         }
4099     } else if (str_eq( identifier, "MCPP")) {
4100         if (scan_token( skip_ws(), (tp = work_buf, &tp), work_end) != NAM) {
4101             if (warn_level & 1)
4102                 cwarn( not_ident, work_buf, 0L, NULL);
4103         }
4104         if (str_eq( identifier, "put_defines")) {
4105             if (! is_junk())
4106                 dump_def( TRUE, FALSE); /* #pragma MCPP put_defines */
4107         } else if (str_eq( identifier, "preprocess")) {
4108             if (! is_junk())            /* #pragma MCPP preprocess  */
4109                 mcpp_fputs( "#pragma MCPP preprocessed\n", OUT);
4110                     /* Just putout the directive    */
4111         } else if (str_eq( identifier, "preprocessed")) {
4112             if (! is_junk()) {          /* #pragma MCPP preprocessed*/
4113                 skip_nl();
4114                 do_preprocessed();
4115                 return;
4116             }
4117         } else if (str_eq( identifier, "warning")) {
4118                                         /* #pragma MCPP warning     */
4119             cwarn( infile->buffer, NULL, 0L, NULL);
4120         } else if (str_eq( identifier, "push_macro")) {
4121             push_or_pop( PUSH);         /* #pragma MCPP push_macro  */
4122         } else if (str_eq( identifier, "pop_macro")) {
4123             push_or_pop( POP);          /* #pragma MCPP pop_macro   */
4124         } else if (str_eq( identifier, "debug")) {
4125             do_debug( TRUE);            /* #pragma MCPP debug       */
4126         } else if (str_eq( identifier, "end_debug")) {
4127             do_debug( FALSE);           /* #pragma MCPP end_debug   */
4128         } else {
4129             warn = TRUE;
4130         }
4131         if (warn && (warn_level & 1))
4132             cwarn( unknown_arg, identifier, 0L, NULL);
4133         goto  skip_nl;                  /* Do not putout the line   */
4134 #if COMPILER == GNUC
4135     /* The #pragma lines for GCC is skipped not to confuse cc1.     */
4136     } else if (str_eq( identifier, "GCC")) {    /* #pragma GCC *    */
4137         if (scan_token( skip_ws(), (tp = work_buf, &tp), work_end) == NAM) {
4138             if (str_eq( identifier, "poison")
4139                     || str_eq( identifier, "dependency")) {
4140                 if (warn_level & 2)
4141                     cwarn( "Skipped the #pragma line"       /*_W2_  */
4142                             , NULL, 0L, NULL);
4143                 goto skip_nl;
4144             } else if (str_eq( identifier, "system_header")) {
4145                 infile->sys_header = TRUE;      /* Mark as a system header  */
4146                 goto skip_nl;
4147             }
4148         }
4149 #endif
4150 
4151 #if COMPILER == MSC
4152     } else if (str_eq( identifier, "setlocale")) {
4153         if (skip_ws() == '('
4154                 && scan_token( skip_ws(), (tp = work_buf, &tp), work_end)
4155                     == STR
4156                 && skip_ws() == ')') {
4157             if (! is_junk()) {
4158                 work_buf[ 0] = *(tp - 1) = '\0';
4159                 set_encoding( work_buf + 1, NULL, SETLOCALE);
4160                 work_buf[ 0] = *(tp - 1) = '"';
4161             }   /* else warned by is_junk() */
4162         } else {
4163             warn = TRUE;
4164         }
4165 #else   /* COMPILER != MSC  */
4166     } else if (str_eq( identifier, "__setlocale")) {
4167         if (skip_ws() == '('
4168                 && scan_token( skip_ws(), (tp = work_buf, &tp), work_end)
4169                         == STR
4170                 && skip_ws() == ')') {
4171             if (! is_junk()) {              /* #pragma __setlocale  */
4172                 work_buf[ 0] = *(tp - 1) = '\0';
4173                 set_encoding( work_buf + 1, NULL, __SETLOCALE);
4174                 work_buf[ 0] = *(tp - 1) = '"';
4175             }   /* else warned by is_junk() */
4176         } else {
4177             warn = TRUE;
4178         }
4179 #endif
4180 
4181 #if COMPILER == MSC
4182     } else if (str_eq( identifier, "push_macro")) {
4183         push_or_pop( PUSH);
4184         goto  skip_nl;
4185     } else if (str_eq( identifier, "pop_macro")) {
4186         push_or_pop( POP);
4187         goto  skip_nl;
4188 #endif
4189 
4190 #if COMPILER == LCC
4191     } else if (str_eq( identifier, "optimize")
4192                 && (skip_ws() == '(')
4193                 && (char_type[ (c = skip_ws()) & UCHARMAX] == DIG)
4194                 && (skip_ws() == ')')) {
4195         char    tmp[ 2];
4196 
4197         tmp[ 0] = c;
4198         tmp[ 1] = EOS;
4199         look_and_install( optim_name, DEF_NOARGS_PREDEF, null, tmp);
4200 #endif
4201 
4202 #if COMPILER == COMPILER_UNKNOWN
4203     /*
4204      * Write here any compiler-specific #pragma sub-directive which should
4205      * be processed by preprocessor.
4206      */
4207 #endif
4208     }
4209 
4210     if (warn) {
4211         if (warn_level & 1)
4212             cwarn( unknown_arg, identifier, 0L, NULL);
4213         goto  skip_nl;                  /* Do not putout the line   */
4214     }
4215 
4216     sharp( NULL, 0);    /* Synchronize line number before output    */
4217     if (! no_output) {
4218         mcpp_fputs( "#pragma ", OUT);
4219         mcpp_fputs( bp, OUT);           /* Line is put out          */
4220     }
4221 skip_nl: /* Don't use skip_nl() which skips to the newline in source file */
4222     while (get_ch() != '\n')
4223         ;
4224 }
4225 
4226 static void do_once(
4227     const char *    fullname        /* Full-path-list of the header */
4228 )
4229 /*
4230  * Process #pragma once so as not to re-include the file later.
4231  * This directive has been imported from GCC V.1.* / cpp as an extension.
4232  */
4233 {
4234     if (once_list == NULL) {                /* Should initialize    */
4235         max_once = INIT_NUM_ONCE;
4236         once_list = (INC_LIST *) xmalloc( sizeof (INC_LIST) * max_once);
4237         once_end = &once_list[ 0];
4238     } else if (once_end - once_list >= max_once) {
4239                                             /* Double the elements  */
4240         once_list = (INC_LIST *) xrealloc( (void *) once_list
4241                 , sizeof (INC_LIST) * max_once * 2);
4242         once_end = &once_list[ max_once];
4243         max_once *= 2;
4244     }
4245     once_end->name = fullname;
4246     once_end->len = strlen( fullname);
4247     once_end++;
4248 }
4249 
4250 static int  included(
4251     const char *    fullname
4252 )
4253 /*
4254  * Has the file been once included ?
4255  * This routine is only called from open_file().
4256  */
4257 {
4258     INC_LIST *  inc;
4259     size_t      fnamelen;
4260 
4261     if (once_list == NULL)              /* No once file registered  */
4262         return  FALSE;
4263     fnamelen = strlen( fullname);
4264     for (inc = once_list; inc < once_end; inc++) {
4265         if (inc->len == fnamelen && str_case_eq( inc->name, fullname)) {
4266             /* Already included */
4267             if (mcpp_debug & PATH)
4268                 mcpp_fprintf( DBG, "Once included \"%s\"\n", fullname);
4269             return  TRUE;
4270         }
4271     }
4272     return  FALSE;                          /* Not yet included     */
4273 }
4274 
4275 static void push_or_pop(
4276     int     direction
4277 )
4278 /* Process #pragma MCPP push_macro( "MACRO"),
4279  * #pragma MCPP pop_macro( "MACRO") for other compilers than Visual C,
4280  * and #pragma push_macro( "MACRO"), #pragma pop_macro( "MACRO") for Visual C.
4281  * Note:1. "push" count is set in defp->push.
4282  *      2. pushed definitions are inserted immediatly after the current
4283  *          definition of the same name.
4284  *      3. the definitions of a same name macro can be pushed multiple times.
4285  */
4286 {
4287     char *          tp;
4288     DEFBUF **       prevp;
4289     DEFBUF *        defp;
4290     DEFBUF *        dp;
4291     int             cmp;
4292     size_t          s_name, s_def;
4293 
4294     if (skip_ws() == '('
4295             && scan_token( skip_ws(), (tp = work_buf, &tp), work_end) == STR
4296             && skip_ws() == ')') {          /* Correct syntax       */
4297 
4298         if (is_junk())
4299             return;
4300         s_name = strlen( work_buf) - 2;
4301         *(work_buf + s_name + 1) = '\0';
4302         memcpy( identifier, work_buf + 1, s_name + 1);
4303                                             /* Remove enclosing '"' */
4304         prevp = look_prev( identifier, &cmp);
4305         if (cmp == 0) { /* Current definition or pushed definition exists   */
4306             defp = *prevp;
4307             if (direction == PUSH) {/* #pragma push_macro( "MACRO") */
4308                 if (defp->push) {           /* No current definition*/
4309                     if (warn_level & 1)
4310                         cwarn( "\"%s\" is already pushed"   /* _W1_ */
4311                                 , identifier, 0L, NULL);
4312                     return;
4313                 }
4314                 /* Else the current definition exists.  Push it     */
4315                 s_def = sizeof (DEFBUF) + 3 + s_name
4316                         + strlen( defp->repl) + strlen( defp->fname);
4317                 if (mcpp_mode == STD)
4318                     s_def += strlen( defp->parmnames);
4319                 dp = (DEFBUF *) xmalloc( s_def);
4320                 memcpy( dp, defp, s_def);   /* Copy the definition  */
4321                 dp->link = *prevp;          /* Insert to linked-list*/
4322                 *prevp = dp;                /*      the pushed def  */
4323                 prevp = &dp->link;          /* Next link to search  */
4324             } else {                /* #pragma pop_macro( "MACRO")  */
4325                 if (defp->push == 0) {      /* Current definition   */
4326                     if (defp->link == NULL
4327                             || ! str_eq( identifier, defp->link->name)) {
4328                         if (warn_level & 1)
4329                             cwarn( "\"%s\" has not been pushed"     /* _W1_ */
4330                                     , identifier, 0L, NULL);
4331                         return;
4332                     } else {
4333                         *prevp = defp->link;
4334                                 /* Link the previous and the next   */
4335                         free( defp);
4336                             /* Delete the definition to enable popped def   */
4337                     }
4338                 }   /* Else no current definition exists    */
4339             }
4340             while ((defp = *prevp) != NULL) {
4341                 /* Increment or decrement "push" count of all pushed defs   */
4342                 if ((cmp = memcmp( defp->name, identifier, s_name)) > 0)
4343                     break;
4344                 defp->push += direction;        /* Increment or decrement   */
4345                 prevp = &defp->link;
4346             }
4347         } else {    /* No current definition nor pushed definition  */
4348             if (warn_level & 1)
4349                 cwarn( "\"%s\" has not been defined"        /* _W1_ */
4350                         , identifier, 0L, NULL);
4351         }
4352     } else {        /* Wrong syntax */
4353         if (warn_level & 1)
4354             cwarn( "Bad %s syntax", direction == PUSH       /* _W1_ */
4355                     ? "push_macro" : "pop_macro", 0L, NULL);
4356     }
4357 }
4358 
4359 static void do_asm(
4360     int     asm_start                       /* #asm ?               */
4361 )
4362 /*
4363  * #asm, #endasm
4364  * Originally written for OS-9/09 Microware C.
4365  */
4366 {
4367     if (! compiling)
4368         return;
4369     if (asm_start == (in_asm != 0L)) {
4370         if (in_asm)
4371             cerror( "In #asm block started at line %.0s%ld" /* _E_  */
4372                     , NULL, in_asm, NULL);
4373         else
4374             cerror( "Without #asm", NULL, 0L, NULL);        /* _E_  */
4375         skip_nl();
4376         unget_ch();
4377         return;
4378     }
4379     in_asm = asm_start ? src_line : 0L;
4380 }
4381 
4382 void    do_old( void)
4383 /*
4384  * Process the out-of-standard directives.
4385  * GCC permits #include_next and #warning even in STANDARD mode.
4386  */
4387 {
4388     static const char * const   unknown
4389             = "Unknown #directive \"%s\"%.0ld%s";       /* _E_ _W8_ */
4390     static const char * const   ext
4391             = "%s is not allowed by Standard%.0ld%s";   /* _W2_ _W8_*/
4392 
4393 #if COMPILER == GNUC
4394     if (str_eq( identifier, "include_next")) {
4395         if ((compiling && (warn_level & 2))
4396                 || (! compiling && (warn_level & 8)))
4397             cwarn( ext, "#include_next", 0L
4398                     , compiling ? NULL : " (in skipped block)");
4399         if (! compiling)
4400             return;
4401         in_include = TRUE;
4402         do_include( TRUE);
4403         in_include = FALSE;
4404         return;
4405     } else if (str_eq( identifier, "warning")) {
4406         if ((compiling && (warn_level & 2))
4407                 || (! compiling && (warn_level & 8)))
4408             cwarn( ext, "#warning", 0L
4409                     , compiling ? NULL : " (in skipped block)");
4410         if (! compiling)
4411             return;
4412         cwarn( infile->buffer, NULL, 0L, NULL);
4413                                     /* Always output the warning    */
4414         skip_nl();
4415         unget_ch();
4416         return;
4417     } else if (str_eq( identifier, "ident") || str_eq( identifier, "sccs")) {
4418         if ((compiling && (warn_level & 1))
4419                 || (! compiling && (warn_level & 8))) {
4420             if (str_eq( identifier, "ident"))
4421                 cwarn(
4422     compiling ? "Ignored #ident" : "#ident (in skipped block)"  /* _W1_ _W8_*/
4423                         , NULL, 0L, NULL);
4424             else
4425                 cwarn(
4426     compiling ? "Ignored #sccs" : "#sccs (in skipped block)"    /* _W1_ _W8_*/
4427                         , NULL, 0L, NULL);
4428         }
4429         if (! compiling)
4430             return;
4431         skip_nl();
4432         unget_ch();
4433         return;
4434     }
4435 #endif  /* COMPILER == GNUC */
4436 
4437 #if COMPILER == MSC
4438     if (str_eq( identifier, "using") || str_eq( identifier, "import")) {
4439                                             /* #using or #import    */
4440         if (! compiling)
4441             return;
4442         mcpp_fputs( infile->buffer, OUT);   /* Putout the line as is*/
4443         skip_nl();
4444         unget_ch();
4445         return;
4446     }
4447 #endif
4448 
4449 #if SYSTEM == SYS_MAC
4450     if (str_eq( identifier, "import")) {
4451         if ((compiling && (warn_level & 2))
4452                 || (! compiling && (warn_level & 8)))
4453             cwarn( ext, "#import", 0L
4454                     , compiling ? NULL : " (in skipped block)");
4455         if (! compiling)
4456             return;
4457         in_import = in_include = TRUE;
4458         do_include( FALSE);
4459         in_import = in_include = FALSE;
4460         return;
4461     }
4462 #endif
4463 
4464     if (! standard && do_prestd_directive())
4465         return;
4466 
4467     if (compiling) {
4468         if (option_flags.lang_asm) {        /* "Assembler" source   */
4469             if (warn_level & 1)
4470                 cwarn( unknown, identifier, 0L, NULL);
4471             mcpp_fputs( infile->buffer, OUT);   /* Putout the line  */
4472         } else {
4473             cerror( unknown, identifier, 0L, NULL);
4474         }
4475     } else if (warn_level & 8) {
4476         cwarn( unknown, identifier, 0L, " (in skipped block)");
4477     }
4478     skip_nl();
4479     unget_ch();
4480     return;
4481 }
4482 
4483 static int  do_prestd_directive( void)
4484 /*
4485  * Process directives for pre-Standard mode.
4486  */
4487 {
4488 #if COMPILER != GNUC
4489     if (str_eq( identifier, "assert")) {    /* #assert              */
4490         if (! compiling)                    /* Only validity check  */
4491             return  TRUE;
4492         if (eval_if() == 0L) {              /* Assert expression    */
4493             cerror( "Preprocessing assertion failed"        /* _E_  */
4494                     , NULL, 0L, NULL);
4495             skip_nl();
4496             unget_ch();
4497         }
4498         return  TRUE;
4499     } else
4500 #endif
4501     if (str_eq( identifier, "put_defines")) {
4502         if (! compiling)                    /* Only validity check  */
4503             return  TRUE;
4504         if (mcpp_mode != OLD_PREP && ! is_junk())
4505             dump_def( TRUE, FALSE);         /* #put_defines         */
4506         skip_nl();
4507         unget_ch();
4508         return  TRUE;
4509     } else if (str_eq( identifier, "preprocess")) {
4510         if (! compiling)                    /* Only validity check  */
4511             return  TRUE;
4512         if (mcpp_mode != OLD_PREP && ! is_junk())
4513         /* Just putout the directive for the succeding preprocessor */
4514             mcpp_fputs( "#preprocessed\n", OUT);
4515         skip_nl();
4516         unget_ch();
4517         return  TRUE;
4518     } else if (str_eq( identifier, "preprocessed")) {
4519         if (! compiling)                    /* Only validity check  */
4520             return  TRUE;
4521         if (mcpp_mode != OLD_PREP && ! is_junk()) {
4522             skip_nl();
4523             do_preprocessed();              /* #preprocessed        */
4524             return  TRUE;
4525         }
4526         skip_nl();
4527         unget_ch();
4528         return  TRUE;
4529     }
4530 
4531     if (str_eq( identifier, "debug")) {     /* #debug <args>        */
4532         if (! compiling)                    /* Only validity check  */
4533             return  TRUE;
4534         do_debug( TRUE);
4535         return  TRUE;
4536     } else if (str_eq( identifier, "end_debug")) {
4537         if (! compiling)
4538             return  TRUE;
4539         do_debug( FALSE);                   /* #end_debug <args>    */
4540         return  TRUE;
4541     }
4542 
4543     if (str_eq( identifier, "asm")) {       /* #asm                 */
4544         do_asm( TRUE);
4545         return  TRUE;
4546     }
4547     if (str_eq( identifier, "endasm")) {    /* #endasm              */
4548         do_asm( FALSE);
4549         skip_nl();                          /* Skip comments, etc.  */
4550         unget_ch();
4551         return  TRUE;
4552     }
4553 
4554     return  FALSE;                          /* Unknown directive    */
4555 }
4556 
4557 static void do_preprocessed( void)
4558 /*
4559  * The source file has been already preprocessed.
4560  * Copy the lines to output.
4561  * Install macros according the #define directives.
4562  */
4563 {
4564     const char *    corrupted =
4565             "This preprocessed file is corrupted";          /* _F_  */
4566     FILEINFO *      file;
4567     char *          lbuf;
4568     char *          cp;
4569     const char **   incptr;
4570     char *          comment = NULL;
4571     char *          colon = NULL;
4572     const char *    dir;
4573 #if STD_LINE_PREFIX == FALSE
4574     char            conv[ NBUFF];
4575     char *          arg;
4576 
4577     /*
4578      * Compiler cannot accept C source style #line.
4579      * Convert it to the compiler-specific format.
4580      */
4581     strcpy( conv, LINE_PREFIX);
4582     arg = conv + strlen( conv);
4583 #endif
4584     file = infile;
4585     lbuf = file->bptr = file->buffer;           /* Reset file->bptr */
4586 
4587     /* Copy the input to output until a comment line appears.       */
4588     while (fgets( lbuf, NBUFF, file->fp) != NULL
4589             && memcmp( lbuf, "/*", 2) != 0) {
4590 #if STD_LINE_PREFIX == FALSE
4591         if (memcmp( lbuf, "#line ", 6) == 0) {
4592             strcpy( arg, lbuf + 6);
4593             mcpp_fputs( conv, OUT);
4594         } else
4595 #endif
4596         {
4597             mcpp_fputs( lbuf, OUT);
4598         }
4599     }
4600     if (! str_eq( lbuf, "/* Currently defined macros. */\n"))
4601         cfatal( "This is not a preprocessed source"         /* _F_  */
4602                 , NULL, 0L, NULL);
4603 
4604     /* Define macros according to the #define lines.    */
4605     while (fgets( lbuf, NWORK, file->fp) != NULL) {
4606         if (memcmp( lbuf, "/*", 2) == 0) {
4607                                     /* Standard predefined macro    */
4608             continue;
4609         }
4610         if (memcmp( lbuf, "#define ", 8) != 0) {
4611             if (memcmp( lbuf, "#line", 5) == 0)
4612                 continue;
4613             else
4614                 cfatal( corrupted, NULL, 0L, NULL);
4615         }
4616         /* Filename and line-number information in comment as:  */
4617         /* dir/fname:1234\t*/
4618         cp = lbuf + strlen( lbuf);
4619         if ((memcmp( cp - 4, "\t*/\n", 4) != 0)
4620                 || (*(cp - 4) = EOS
4621                         , (comment = strrchr( lbuf, '*')) == NULL)
4622                 || (memcmp( --comment, "/* ", 3) != 0)
4623                 || ((colon = strrchr( comment, ':')) == NULL))
4624             cfatal( corrupted, NULL, 0L, NULL);
4625         src_line = atol( colon + 1);        /* Pseudo line number   */
4626         *colon = EOS;
4627         dir = comment + 3;
4628         inc_dirp = &null;
4629         /* Search the include directory list    */
4630         for (incptr = incdir ; incptr < incend; incptr++) {
4631             if (memcmp( *incptr, dir, strlen( *incptr)) == 0) {
4632                 inc_dirp = incptr;
4633                 break;
4634             }
4635         }
4636         /* Register the filename to fnamelist[] */
4637         /* inc_dirp may be NULL, and cur_fname may be "(predefined)"    */
4638         cur_fname = set_fname( dir + strlen( *inc_dirp));
4639         strcpy( comment - 2, "\n");         /* Remove the comment   */
4640         unget_string( lbuf + 8, NULL);
4641         do_define( FALSE, 0);
4642         get_ch();                               /* '\n' */
4643         get_ch();                               /* Clear the "file" */
4644         unget_ch();                             /* infile == file   */
4645     }
4646     file->bptr = file->buffer + strlen( file->buffer);
4647 }
4648 
4649 static int  do_debug(
4650     int     set                         /* TRUE to set debugging    */
4651 )
4652 /*
4653  * #pragma MCPP debug, #pragma MCPP end_debug, #debug, #end_debug
4654  * Return TRUE when diagnostic is issued else return FALSE.
4655  */
4656 {
4657     struct Debug_arg {
4658         const char *    arg_name;               /* Name of option   */
4659         int     arg_num;                        /* Value of 'debug' */
4660     };
4661     static struct Debug_arg     debug_args[] = {
4662         { "path",   PATH    },
4663         { "token",  TOKEN   },
4664         { "expand", EXPAND  },
4665         { "macro_call", MACRO_CALL  },      /* Implemented only in STD mode */
4666         { "if",     IF      },
4667         { "expression", EXPRESSION  },
4668         { "getc",   GETC    },
4669         { "memory", MEMORY  },
4670         { NULL,     0       },
4671     };
4672     struct Debug_arg    *argp;
4673     int     num;
4674     int     c;
4675 
4676     c = skip_ws();
4677     if (c == '\n') {
4678         unget_ch();
4679         if (set) {
4680             if (warn_level & 1)
4681                 cwarn( "No argument", NULL, 0L, NULL);      /* _W1_ */
4682             return TRUE;
4683         } else {
4684             mcpp_debug = 0;                 /* Clear all the flags  */
4685             return FALSE;
4686         }
4687     }
4688     while (scan_token( c, (workp = work_buf, &workp), work_end) == NAM) {
4689         argp = debug_args;
4690         while (argp->arg_name) {
4691             if (str_eq( argp->arg_name, work_buf))
4692                 break;
4693             argp++;
4694         }
4695         if (argp->arg_name == NULL) {
4696             if (warn_level & 1)
4697                 cwarn( unknown_arg, work_buf, 0L, NULL);
4698             goto  diagnosed;
4699         } else {
4700             num = argp->arg_num;
4701             if (set) {
4702                 mcpp_debug |= num;
4703                 if (num == PATH)
4704                     dump_path();
4705                 else if (num == MEMORY)
4706                     print_heap();
4707                 else if (num == MACRO_CALL)
4708                     option_flags.k = TRUE;  /* This pragma needs this mode  */
4709             } else {
4710                 mcpp_debug &= ~num;
4711             }
4712         }
4713         c = skip_ws();
4714     }
4715     if ((mcpp_mode != STD && (mcpp_debug & MACRO_CALL)) || c != '\n') {
4716         if (warn_level & 1) {
4717             if (c != '\n') {
4718                 cwarn( not_ident, work_buf, 0L, NULL);
4719             } else {
4720                 cwarn( unknown_arg, work_buf, 0L, NULL);
4721                 mcpp_debug &= ~num;                     /* Disable  */
4722             }
4723         }
4724         skip_nl();
4725         unget_ch();
4726         goto  diagnosed;
4727     }
4728     unget_ch();
4729     return FALSE;
4730 diagnosed:
4731     return TRUE;
4732 }
4733 
4734 void    put_asm( void)
4735 /*
4736  * Put out source line as it is.
4737  */
4738 {
4739 #if 0
4740     mcpp_fputs( "#2\n", OUT);
4741     mcpp_fputs( infile->buffer, OUT);
4742     skip_nl();
4743 #endif
4744 }
4745 
4746 static void dump_path( void)
4747 /*
4748  * Show the include directories.
4749  */
4750 {
4751     const char **   incptr;
4752     const char *    inc_dir;
4753     const char *    dir = "./";
4754     int             i;
4755 
4756     mcpp_fputs( "Include paths are as follows --\n", DBG);
4757     for (incptr = incdir; incptr < incend; incptr++) {
4758         inc_dir = *incptr;
4759         if (*inc_dir == '\0')
4760             inc_dir = dir;
4761         mcpp_fprintf( DBG, "    %s\n", inc_dir);
4762     }
4763     mcpp_fputs( "End of include path list.\n", DBG);
4764 #if SYSTEM == SYS_MAC
4765     mcpp_fputs( "Framework paths are as follows --\n", DBG);
4766     for (i = 0; i < num_framework; i++ )
4767         mcpp_fprintf( DBG, "    %s\n", framework[ i]);
4768     mcpp_fputs( "End of framework path list.\n", DBG);
4769 #endif
4770 }
4771 
4772 /*
4773  * Note: The getopt() of glibc should not be used since the specification
4774  *  differs from the standard one.
4775  *  Use this mcpp_getopt() for mcpp.
4776  */
4777 
4778 /* Based on the public-domain-software released by AT&T in 1985.    */
4779 
4780 #define OPTERR( s, c)   if (mcpp_opterr) {  \
4781     mcpp_fputs( argv[0], ERR);  \
4782     mcpp_fputs( s, ERR);        \
4783     mcpp_fputc( c, ERR);        \
4784     mcpp_fputc( '\n', ERR);     \
4785     }
4786 
4787 static int  mcpp_getopt(
4788     int         argc,
4789     char * const *  argv,
4790     const char *    opts
4791 )
4792 /*
4793  * Get the next option (and it's argument) from the command line.
4794  */
4795 {
4796     const char * const   error1 = ": option requires an argument --";
4797     const char * const   error2 = ": illegal option --";
4798     static int      sp = 1;
4799     int             c;
4800     const char *    cp;
4801 
4802     if (sp == 1) {
4803         if (argc <= mcpp_optind ||
4804                 argv[ mcpp_optind][ 0] != '-'
4805                     || argv[ mcpp_optind][ 1] == '\0') {
4806             return  EOF;
4807         } else if (strcmp( argv[ mcpp_optind], "--") == 0) {
4808             mcpp_optind++;
4809             return  EOF;
4810         }
4811     }
4812 /*  mcpp_optopt = c = (unsigned char) argv[ mcpp_optind][ sp];  */
4813     mcpp_optopt = c = argv[ mcpp_optind][ sp] & UCHARMAX;
4814     if (c == ':' || (cp = strchr( opts, c)) == NULL) {
4815         OPTERR( error2, c)
4816         if (argv[ mcpp_optind][ ++sp] == '\0') {
4817             mcpp_optind++;
4818             sp = 1;
4819         }
4820         return  '?';
4821     }
4822     if (*++cp == ':') {
4823         if (argv[ mcpp_optind][ sp+1] != '\0') {
4824             mcpp_optarg = &argv[ mcpp_optind++][ sp+1];
4825         } else if (argc <= ++mcpp_optind) {
4826             OPTERR( error1, c)
4827             sp = 1;
4828             return  '?';
4829         } else {
4830             mcpp_optarg = argv[ mcpp_optind++];
4831         }
4832         sp = 1;
4833     } else {
4834         if (argv[ mcpp_optind][ ++sp] == '\0') {
4835             sp = 1;
4836             mcpp_optind++;
4837         }
4838         mcpp_optarg = NULL;
4839     }
4840     return  c;
4841 }
4842 
4843 #if ! HOST_HAVE_STPCPY
4844 char *  stpcpy(
4845     char *          dest,
4846     const char *    src
4847 )
4848 /*
4849  * Copy the string and return the advanced pointer.
4850  */
4851 {
4852     const char * s;
4853     char *  d;
4854 
4855     for (s = src, d = dest; (*d++ = *s++) != '\0'; )
4856         ;
4857     return  d - 1;
4858 }
4859 #endif
4860 
4861 /*
4862  * list_heap() is a function to print out information of heap-memory.
4863  * See "kmmalloc-2.5.3.zip" by kmatsui.
4864  */
4865 #if     KMMALLOC
4866     int     list_heap( int);
4867 #elif   BSD_MALLOC
4868     int     list_heap( char *);
4869 #elif   DB_MALLOC || DMALLOC
4870     int     list_heap( FILE *);
4871 #endif
4872 
4873 void    print_heap( void)
4874 {
4875 #if     KMMALLOC
4876     list_heap( 1);
4877 #elif   BSD_MALLOC
4878     list_heap( ":cpp");
4879 #elif   DB_MALLOC || DMALLOC || PHK_MALLOC || DLMALLOC
4880     list_heap( fp_debug);
4881 #endif
4882 }
4883 
4884 void    at_end( void)
4885 /*
4886  * Handle the commands to be executed at the end of processing.
4887  */
4888 {
4889 #if COMPILER == GNUC
4890     if (dMflag || dDflag)
4891         dump_def( FALSE, FALSE);
4892 #endif
4893 }
4894 
4895 #if MCPP_LIB
4896 void    clear_filelist( void)
4897 /*
4898  * Free malloced memory for filename-list and directory-list.
4899  */
4900 {
4901     const char **   incp;
4902     INC_LIST *  namep;
4903 
4904     for (incp = incdir; incp < incend; incp++)
4905         free( (void *) *incp);
4906     free( (void *) incdir);
4907     for (namep = fnamelist; namep < fname_end; namep++)
4908         free( (void *) namep->name);
4909     free( (void *) fnamelist);
4910     if (standard)
4911         free( (void *) once_list);
4912 }
4913 #endif
4914 
4915