diff options
Diffstat (limited to 'src/main.c')
| -rw-r--r-- | src/main.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..0882904 --- /dev/null +++ b/src/main.c @@ -0,0 +1,412 @@ +#include <defs.h> + +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, "<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 ); +} |
