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 >= "e_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