#include static void welcome( mcpp_options *opts ) { if( opts == NULL ) return; printf( "mcpu-cpp %s\n", PACKAGE_VERSION ); printf( "MCPU languages preprocessor\n" ); } static void usage( mcpp_options *opts ) { printf( "Usage: %s [options] [input [output]]\n\n", opts->progname ); printf( "Options:\n" ); printf( " -o FILE write output to FILE\n" ); printf( " -D NAME[=VALUE] define a command-line macro\n" ); printf( " -U NAME undefine a command-line macro\n" ); printf( " -imacros FILE preprocess FILE for macro state; discard its output\n" ); printf( " -include FILE preprocess FILE before the primary input\n" ); printf( " -I DIR, -IDIR add user include directory\n" ); printf( " -isystem DIR add explicit system include directory\n" ); printf( " -idirafter DIR add include directory searched last\n" ); printf( " -nostdinc suppress effective standard-system include tree\n" ); printf( " -dM dump non-predefined macros after preprocessing\n" ); printf( " -dMP dump predefined macros first, then other macros\n" ); printf( " -dD preserve #define directives in normal output\n" ); printf( " -dconfig dump effective mcpu-cpp configuration\n" ); printf( " -dsearch-dirs dump effective include search directories\n" ); printf( " -M output make dependencies including system headers\n" ); printf( " -MM output make dependencies excluding system headers\n" ); printf( " -MG treat missing headers as generated dependencies\n" ); printf( " -MD write dependencies and keep preprocessing output\n" ); printf( " -MMD like -MD but exclude system headers\n" ); printf( " -MF FILE write dependencies to FILE ('-' means stdout)\n" ); printf( " -MT TARGET set unquoted make dependency target\n" ); printf( " -MQ TARGET set make-quoted dependency target\n" ); printf( " --object-suffix SFX set object suffix used for dependency targets\n" ); printf( " -w suppress all warnings\n" ); printf( " -Wcomment[s] warn about nested /* and multi-line // comments\n" ); printf( " -Wno-comment[s] disable comment warnings even under -Wall\n" ); printf( " -Wall enable all optional warning classes\n" ); printf( " -Werror promote every emitted warning to an error\n" ); printf( " -Wno-error keep emitted warnings as warnings\n" ); printf( " --config-file FILE use only FILE as configuration\n" ); printf( " --no-config do not read configuration files; keep runtime defaults\n" ); printf( " -v, --verbose print configuration/include activity\n" ); printf( " --help display this help and exit\n" ); printf( " --version display version and exit\n\n" ); printf( "If input is omitted or '-', read standard input.\n" ); printf( "If output is omitted or '-', write standard output.\n" ); } static void pipe_closed( int sig ) { (void)sig; _Exit( 0 ); } static int apply_include_options( mcpp *cpp, const mcpp_options *opts ) { size_t i; for( i = 0; i < opts->action_count; ++i ) { const mcpp_option_action *action = &opts->actions[i]; enum mcpu_include_class class_type; switch( action->kind ) { case MCPP_ACTION_INCLUDE_USER: if( action->argument[0] == 0 ) continue; class_type = MCPU_INCLUDE_USER_EXPLICIT; break; case MCPP_ACTION_INCLUDE_SYSTEM: class_type = MCPU_INCLUDE_SYSTEM_EXPLICIT; break; case MCPP_ACTION_INCLUDE_AFTER: class_type = MCPU_INCLUDE_AFTER_EXPLICIT; break; default: continue; } if( mcpu_include_paths_add(&cpp->include_paths, action->argument, class_type) != 0 ) return( -1 ); } return( 0 ); } static int dump_verbose_config( const mcpp *cpp, FILE *stream ) { enum mcpu_language language; const char *name; const char *value; if( cpp == NULL || stream == NULL ) { errno = EINVAL; return( -1 ); } for( language = MCPU_LANG_DIFF; language < MCPU_LANG__COUNT; language = (enum mcpu_language)(language + 1) ) { name = mcpu_language_config_variable( language ); value = mcpu_config_get( &cpp->config, name ); if( value != NULL && fprintf(stream, "config: %s=%s\n", name, value) < 0 ) return( -1 ); } name = "MCPU_CPP_INCLUDE_PATH"; value = mcpu_config_get( &cpp->config, name ); if( value != NULL && fprintf(stream, "config: %s=%s\n", name, value) < 0 ) return( -1 ); name = "MCPU_CPP_SYSTEM_INCLUDE_PATH"; value = mcpu_config_get( &cpp->config, name ); if( value != NULL && fprintf(stream, "config: %s=%s\n", name, value) < 0 ) return( -1 ); name = "MCPU_CPP_AFTER_INCLUDE_PATH"; value = mcpu_config_get( &cpp->config, name ); if( value != NULL && fprintf(stream, "config: %s=%s\n", name, value) < 0 ) return( -1 ); return( ferror(stream) ? -1 : 0 ); } static FILE * open_output( const mcpp_options *opts, int *close_stream ) { FILE *stream; *close_stream = 0; if( opts->out_fname == NULL || opts->out_fname[0] == 0 ) return( stdout ); stream = fopen( opts->out_fname, "wb" ); if( stream != NULL ) *close_stream = 1; return( stream ); } static char * dependency_default_filename( const mcpp_options *opts ) { const char *source; const char *base; const char *dot; size_t stem_length; char *filename; if( opts == NULL ) { errno = EINVAL; return( NULL ); } if( opts->out_fname != NULL && opts->out_fname[0] != 0 ) { source = opts->out_fname; base = source; } else if( opts->in_fname != NULL && opts->in_fname[0] != 0 ) { base = strrchr( opts->in_fname, '/' ); source = base == NULL ? opts->in_fname : base + 1; base = source; } else { source = "-"; base = source; } dot = strrchr( base, '.' ); stem_length = dot != NULL && dot != base ? (size_t)(dot - source) : strlen(source); filename = (char *)malloc( stem_length + 3 ); if( filename == NULL ) return( NULL ); memcpy( filename, source, stem_length ); memcpy( filename + stem_length, ".d", 3 ); return( filename ); } static FILE * open_dependency_output( const mcpp_options *opts, int side_effect, char **allocated_name, int *close_stream ) { const char *name = NULL; FILE *stream; if( opts == NULL || allocated_name == NULL || close_stream == NULL ) { errno = EINVAL; return( NULL ); } *allocated_name = NULL; *close_stream = 0; if( opts->deps_file != NULL ) name = opts->deps_file; else if( side_effect ) { *allocated_name = dependency_default_filename( opts ); if( *allocated_name == NULL ) return( NULL ); name = *allocated_name; } else if( opts->out_fname != NULL && opts->out_fname[0] != 0 ) name = opts->out_fname; if( name == NULL || name[0] == 0 || strcmp(name, "-") == 0 ) return( stdout ); stream = fopen( name, "wb" ); if( stream != NULL ) *close_stream = 1; else fprintf( stderr, "%s: cannot open dependency output '%s': %s\n", opts->progname, name, strerror(errno) ); return( stream ); } static int run_preprocessor( mcpp *cpp, mcpp_options *opts ) { FILE *stream; int close_stream; int rc; cpp->options_data = opts; cpp->verbose = opts->verbose; cpp->include_paths.no_standard_includes = opts->no_standard_includes; if( mcpp_load_config(cpp, opts->config_fname, opts->no_config) != 0 ) return( -1 ); if( cpp->verbose && dump_verbose_config(cpp, stderr) != 0 ) return( -1 ); if( mcpu_include_paths_from_config(&cpp->include_paths, &cpp->config) != 0 || apply_include_options(cpp, opts) != 0 ) return( -1 ); if( opts->dump_config ) { if( opts->out_fname[0] != 0 ) { fprintf( stderr, "%s: -o/output file has no meaning with -dconfig\n", opts->progname ); return( -1 ); } return( mcpu_config_dump(&cpp->config, stdout) ); } if( opts->dump_search_dirs ) { if( opts->out_fname[0] != 0 ) { fprintf( stderr, "%s: -o/output file has no meaning with -dsearch-dirs\n", opts->progname ); return( -1 ); } return( mcpu_include_paths_dump(&cpp->include_paths, stdout) ); } if( mcpp_options_has_unimplemented(opts) ) { fprintf( stderr, "%s: requested option is parsed but its handler is not implemented yet\n", opts->progname ); return( -1 ); } if( opts->in_fname[0] != 0 ) rc = mcpp_process( cpp, opts->in_fname ); else rc = mcpp_process_stream( cpp, stdin, "" ); if( rc != 0 ) return( -1 ); if( opts->print_deps && opts->inhibit_output ) { char *allocated_name; stream = open_dependency_output( opts, 0, &allocated_name, &close_stream ); if( stream == NULL ) { free( allocated_name ); return( -1 ); } rc = mcpp_write_dependencies( cpp, stream, opts->print_deps == 2 ); if( close_stream && fclose(stream) != 0 ) rc = -1; free( allocated_name ); return( rc ); } if( opts->dump_macros == MCPP_DUMP_ONLY ) { stream = open_output( opts, &close_stream ); if( stream == NULL ) return( -1 ); rc = mcpp_dump_macros( cpp, stream ); if( close_stream && fclose(stream) != 0 ) rc = -1; return( rc ); } rc = mcpp_write_output(cpp, opts->out_fname[0] != 0 ? opts->out_fname : NULL); if( rc != 0 || !opts->print_deps ) return( rc ); { char *allocated_name; stream = open_dependency_output( opts, 1, &allocated_name, &close_stream ); if( stream == NULL ) { free( allocated_name ); return( -1 ); } rc = mcpp_write_dependencies( cpp, stream, opts->print_deps == 2 ); if( close_stream && fclose(stream) != 0 ) rc = -1; free( allocated_name ); } return( rc ); } int main( int argc, char **argv ) { mcpp cpp; mcpp_options options; const char *p; int mpu_initialized = 0; int rc = 1; mcpp_options_init( &options, argc ); if( options.actions == NULL ) return( 1 ); p = argv[0] + strlen( argv[0] ); while( p != argv[0] && p[-1] != '/' ) --p; options.progname = p; #ifdef SIGPIPE signal( SIGPIPE, pipe_closed ); #endif if( mcpp_handle_options(&options, argc - 1, argv + 1) != 0 ) goto done_options; if( options.version ) { welcome( &options ); rc = 0; goto done_options; } if( options.help ) { welcome( &options ); usage( &options ); rc = 0; goto done_options; } __mpu_init(); mpu_initialized = 1; mcpp_init( &cpp ); if( mcpp_runtime_paths_discover(&cpp.runtime_paths, argv[0]) != 0 ) { fprintf( stderr, "%s: cannot determine MCPU installation root: %s\n", options.progname, strerror(errno) ); } else if( run_preprocessor(&cpp, &options) == 0 ) rc = 0; mcpp_free( &cpp ); if( mpu_initialized ) __mpu_free_context(); done_options: mcpp_options_free( &options ); return( rc ); }