#include static const char * option_argument( mcpp_options *opts, int argc, char **argv, int *i, const char *attached, const char *option ) { if( attached != NULL && *attached != 0 ) return( attached ); if( *i + 1 >= argc ) { fprintf( stderr, "%s: argument missing after '%s'\n", opts->progname, option ); return( NULL ); } ++*i; return( argv[*i] ); } static int append_action( mcpp_options *opts, enum mcpp_option_action_kind kind, const char *option, const char *argument ) { if( opts->action_count >= opts->action_capacity ) { errno = EOVERFLOW; return( -1 ); } opts->actions[opts->action_count].kind = kind; opts->actions[opts->action_count].option = option; opts->actions[opts->action_count].argument = argument; ++opts->action_count; return( 0 ); } static int set_filename( mcpp_options *opts, const char *name ) { if( opts->in_fname == NULL ) { opts->in_fname = strcmp(name, "-") == 0 ? "" : name; return( 0 ); } if( opts->out_fname == NULL ) { opts->out_fname = strcmp(name, "-") == 0 ? "" : name; return( 0 ); } fprintf( stderr, "%s: too many filenames\n", opts->progname ); return( -1 ); } static int parse_dump_option( mcpp_options *opts, const char *arg ) { const char *p = arg + 2; if( *p == 0 ) return( -1 ); while( *p ) { switch( *p++ ) { case 'M': opts->dump_macros = MCPP_DUMP_ONLY; opts->no_output = 1; while( *p == 'P' ) { opts->dump_only_plus_predefined = 1; ++p; } break; case 'D': opts->dump_macros = MCPP_DUMP_DEFINITIONS; break; default: return( -1 ); } } return( 0 ); } void mcpp_options_init( mcpp_options *opts, int argc ) { if( opts == NULL ) return; memset( opts, 0, sizeof(*opts) ); opts->progname = "mcpu-cpp"; opts->object_suffix = ".o"; opts->action_capacity = argc > 0 ? (size_t)argc * 2 : 2; opts->actions = (mcpp_option_action *)calloc( opts->action_capacity, sizeof(*opts->actions) ); } void mcpp_options_free( mcpp_options *opts ) { if( opts == NULL ) return; free( opts->actions ); opts->actions = NULL; opts->action_count = 0; opts->action_capacity = 0; } int mcpp_handle_options( mcpp_options *opts, int argc, char **argv ) { size_t j; int i; if( opts == NULL || argv == NULL ) { errno = EINVAL; return( -1 ); } for( i = 0; i < argc; ++i ) { const char *arg = argv[i]; const char *value; if( arg[0] != '-' || arg[1] == 0 ) { if( set_filename(opts, arg) != 0 ) return( -1 ); continue; } if( strcmp(arg, "--help") == 0 ) opts->help = 1; else if( strcmp(arg, "--version") == 0 ) opts->version = 1; else if( strcmp(arg, "--no-config") == 0 ) opts->no_config = 1; else if( strcmp(arg, "--config-file") == 0 ) { value = option_argument(opts, argc, argv, &i, NULL, arg); if( value == NULL ) return( -1 ); opts->config_fname = value; } else if( strcmp(arg, "--object-suffix") == 0 ) { value = option_argument(opts, argc, argv, &i, NULL, arg); if( value == NULL ) return( -1 ); opts->object_suffix = value; } else if( strcmp(arg, "-dconfig") == 0 ) opts->dump_config = 1; else if( strcmp(arg, "-dsearch-dirs") == 0 ) opts->dump_search_dirs = 1; else if( arg[0] == '-' && arg[1] == 'd' && arg[2] != 0 ) { if( parse_dump_option(opts, arg) != 0 ) goto unknown; } else if( strcmp(arg, "-v") == 0 || strcmp(arg, "--verbose") == 0 ) opts->verbose = 1; else if( strcmp(arg, "-nostdinc") == 0 ) opts->no_standard_includes = 1; else if( strcmp(arg, "-nostdinc++") == 0 ) opts->no_standard_kplusplus_includes = 1; else if( strcmp(arg, "-E") == 0 ) { } else if( strcmp(arg, "-w") == 0 ) opts->inhibit_warnings = 1; else if( strcmp(arg, "-Wcomment") == 0 || strcmp(arg, "-Wcomments") == 0 ) { opts->warn_comments = 1; opts->warn_comments_explicit = 1; } else if( strcmp(arg, "-Wno-comment") == 0 || strcmp(arg, "-Wno-comments") == 0 ) { opts->warn_comments = 0; opts->warn_comments_explicit = 1; } else if( strcmp(arg, "-Wall") == 0 ) { if( !opts->warn_comments_explicit ) opts->warn_comments = 1; } else if( strcmp(arg, "-Werror") == 0 ) opts->warnings_are_errors = 1; else if( strcmp(arg, "-Wno-error") == 0 ) opts->warnings_are_errors = 0; else if( strcmp(arg, "-lint") == 0 ) opts->for_lint = 1; else if( strcmp(arg, "-M") == 0 ) { opts->print_deps = 2; opts->inhibit_output = 1; } else if( strcmp(arg, "-MM") == 0 ) { opts->print_deps = 1; opts->inhibit_output = 1; } else if( strcmp(arg, "-MD") == 0 ) { opts->print_deps = 2; opts->inhibit_output = 0; } else if( strcmp(arg, "-MMD") == 0 ) { opts->print_deps = 1; opts->inhibit_output = 0; } else if( arg[0] == '-' && arg[1] == 'M' && arg[2] == 'F' ) { value = option_argument(opts, argc, argv, &i, arg + 3, "-MF"); if( value == NULL ) return( -1 ); opts->deps_file = value; } else if( arg[0] == '-' && arg[1] == 'M' && (arg[2] == 'T' || arg[2] == 'Q') ) { enum mcpp_option_action_kind kind = arg[2] == 'T' ? MCPP_ACTION_DEP_TARGET : MCPP_ACTION_DEP_TARGET_QUOTED; const char *option = arg[2] == 'T' ? "-MT" : "-MQ"; value = option_argument(opts, argc, argv, &i, arg + 3, option); if( value == NULL || append_action(opts, kind, option, value) != 0 ) return( -1 ); } else if( strcmp(arg, "-MG") == 0 ) opts->print_deps_missing_files = 1; else if( strcmp(arg, "-o") == 0 ) { if( opts->out_fname != NULL ) { fprintf(stderr, "%s: output filename specified twice\n", opts->progname); return( -1 ); } value = option_argument(opts, argc, argv, &i, NULL, arg); if( value == NULL ) return( -1 ); opts->out_fname = strcmp(value, "-") == 0 ? "" : value; } else if( arg[1] == 'D' ) { value = option_argument(opts, argc, argv, &i, arg + 2, "-D"); if( value == NULL || append_action(opts, MCPP_ACTION_DEFINE, "-D", value) != 0 ) return( -1 ); } else if( arg[1] == 'U' ) { value = option_argument(opts, argc, argv, &i, arg + 2, "-U"); if( value == NULL || append_action(opts, MCPP_ACTION_UNDEF, "-U", value) != 0 ) return( -1 ); } else if( arg[1] == 'I' && arg[2] == '-' && arg[3] == 0 ) goto unknown; else if( arg[1] == 'I' ) { value = option_argument(opts, argc, argv, &i, arg + 2, "-I"); if( value == NULL || append_action(opts, MCPP_ACTION_INCLUDE_USER, "-I", value) != 0 ) return( -1 ); } else if( strcmp(arg, "-include") == 0 || strcmp(arg, "-imacros") == 0 || strcmp(arg, "-isystem") == 0 || strcmp(arg, "-idirafter") == 0 ) { enum mcpp_option_action_kind kind = MCPP_ACTION_INCLUDE; if( strcmp(arg, "-imacros") == 0 ) kind = MCPP_ACTION_IMACROS; else if( strcmp(arg, "-isystem") == 0 ) kind = MCPP_ACTION_INCLUDE_SYSTEM; else if( strcmp(arg, "-idirafter") == 0 ) kind = MCPP_ACTION_INCLUDE_AFTER; value = option_argument(opts, argc, argv, &i, NULL, arg); if( value == NULL || append_action(opts, kind, arg, value) != 0 ) return( -1 ); } else { unknown: fprintf( stderr, "%s: unknown option '%s'\n", opts->progname, arg ); return( -1 ); } } if( opts->in_fname == NULL ) opts->in_fname = ""; if( opts->out_fname == NULL ) opts->out_fname = ""; if( opts->deps_file != NULL && opts->print_deps == 0 ) { fprintf( stderr, "%s: -MF requires one of -M, -MM, -MD or -MMD\n", opts->progname ); return( -1 ); } if( opts->print_deps == 0 ) { for( j = 0; j < opts->action_count; ++j ) if( opts->actions[j].kind == MCPP_ACTION_DEP_TARGET || opts->actions[j].kind == MCPP_ACTION_DEP_TARGET_QUOTED ) { fprintf( stderr, "%s: -MT/-MQ require one of -M, -MM, -MD or -MMD\n", opts->progname ); return( -1 ); } } if( opts->print_deps_missing_files && (opts->print_deps == 0 || !opts->inhibit_output) ) { fprintf( stderr, "%s: -MG may only be used with -M or -MM\n", opts->progname ); return( -1 ); } return( 0 ); } static const char * action_name( enum mcpp_option_action_kind kind ) { switch( kind ) { case MCPP_ACTION_DEFINE: return( "define" ); case MCPP_ACTION_UNDEF: return( "undef" ); case MCPP_ACTION_INCLUDE: return( "include" ); case MCPP_ACTION_IMACROS: return( "imacros" ); case MCPP_ACTION_INCLUDE_USER: return( "include-user" ); case MCPP_ACTION_INCLUDE_SYSTEM: return( "include-system" ); case MCPP_ACTION_INCLUDE_AFTER: return( "include-after" ); case MCPP_ACTION_DEP_TARGET: return( "dep-target" ); case MCPP_ACTION_DEP_TARGET_QUOTED: return( "dep-target-quoted" ); } return( "unknown" ); } int mcpp_options_dump( const mcpp_options *opts, FILE *stream ) { size_t i; if( opts == NULL || stream == NULL ) return( -1 ); fprintf(stream, "input=%s\n", *opts->in_fname ? opts->in_fname : ""); fprintf(stream, "output=%s\n", *opts->out_fname ? opts->out_fname : ""); fprintf(stream, "verbose=%d\n", opts->verbose); fprintf(stream, "nostdinc=%d\n", opts->no_standard_includes); fprintf(stream, "dump_config=%d\n", opts->dump_config); fprintf(stream, "dump_search_dirs=%d\n", opts->dump_search_dirs); fprintf(stream, "dump_macros=%d\n", (int)opts->dump_macros); fprintf(stream, "actions=%lu\n", (unsigned long)opts->action_count); for( i = 0; i < opts->action_count; ++i ) fprintf(stream, "action[%lu]=%s:%s\n", (unsigned long)i, action_name(opts->actions[i].kind), opts->actions[i].argument); return( 0 ); } int mcpp_options_has_unimplemented( const mcpp_options *opts ) { size_t i; if( opts == NULL ) return( 0 ); if( opts->print_deps && opts->inhibit_output && opts->dump_macros != MCPP_DUMP_NONE ) return( 1 ); if( opts->print_deps && !opts->inhibit_output && opts->dump_macros == MCPP_DUMP_ONLY ) return( 1 ); if( opts->no_standard_kplusplus_includes || opts->for_lint ) return( 1 ); for( i = 0; i < opts->action_count; ++i ) if( opts->actions[i].kind != MCPP_ACTION_DEFINE && opts->actions[i].kind != MCPP_ACTION_UNDEF && opts->actions[i].kind != MCPP_ACTION_INCLUDE && opts->actions[i].kind != MCPP_ACTION_IMACROS && opts->actions[i].kind != MCPP_ACTION_INCLUDE_USER && opts->actions[i].kind != MCPP_ACTION_INCLUDE_SYSTEM && opts->actions[i].kind != MCPP_ACTION_INCLUDE_AFTER && opts->actions[i].kind != MCPP_ACTION_DEP_TARGET && opts->actions[i].kind != MCPP_ACTION_DEP_TARGET_QUOTED ) return( 1 ); return( 0 ); }