summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c412
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 );
+}