diff --git a/src/internal/argv/argv.h b/src/internal/argv/argv.h index 9e42118..2fe7dd0 100644 --- a/src/internal/argv/argv.h +++ b/src/internal/argv/argv.h @@ -25,6 +25,38 @@ #define ARGV_TAB_WIDTH 8 #endif +/*******************************************/ +/* */ +/* support of hybrid options */ +/* ------------------------- */ +/* hybrid options are very similar to */ +/* long options, yet are prefixed by */ +/* a single dash rather than two */ +/* (i.e. -std, -isystem). */ +/* hybrid options are supported by this */ +/* driver for compatibility with legacy */ +/* tools; note, however, that the use */ +/* of hybrid options should be strongly */ +/* discouraged due to the limitations */ +/* they impose on short options (for */ +/* example, a driver implementing -std */ +/* may not provide -s as a short option */ +/* that takes an arbitrary value). */ +/* */ +/* SPACE: -hybrid VALUE (i.e. -MF file) */ +/* EQUAL: -hybrid=VALUE (i.e. -std=c99) */ +/* ONLY: -opt accepted, --opt rejected */ +/* */ +/*******************************************/ + + +#define ARGV_OPTION_HYBRID_NONE 0x00 +#define ARGV_OPTION_HYBRID_ONLY 0x01 +#define ARGV_OPTION_HYBRID_SPACE 0x02 +#define ARGV_OPTION_HYBRID_EQUAL 0x04 +#define ARGV_OPTION_HYBRID_SWITCH (ARGV_OPTION_HYBRID_SPACE \ + | ARGV_OPTION_HYBRID_EQUAL) + enum argv_optarg { ARGV_OPTARG_NONE, ARGV_OPTARG_REQUIRED, @@ -44,6 +76,10 @@ enum argv_error { ARGV_ERROR_OPTARG_NONE, ARGV_ERROR_OPTARG_REQUIRED, ARGV_ERROR_OPTARG_PARADIGM, + ARGV_ERROR_HYBRID_NONE, + ARGV_ERROR_HYBRID_ONLY, + ARGV_ERROR_HYBRID_SPACE, + ARGV_ERROR_HYBRID_EQUAL, }; struct argv_option { @@ -51,6 +87,7 @@ struct argv_option { const char short_name; int tag; enum argv_optarg optarg; + int flags; const char * paradigm; const char * argname; const char * description; @@ -169,6 +206,26 @@ static inline bool is_last_option(const char * arg) return (arg[0]=='-') && (arg[1]=='-') && !arg[2]; } +static inline bool is_hybrid_option( + const char * arg, + const struct argv_option options[]) +{ + const struct argv_option * option; + struct argv_entry entry; + + if (!is_short_option(arg)) + return false; + + if (!(option = argv_long_option(++arg,options,&entry))) + return false; + + if (!(option->flags & ARGV_OPTION_HYBRID_SWITCH)) + if (argv_short_option(arg,options,&entry)) + return false; + + return true; +} + static inline bool is_arg_in_paradigm(const char * arg, const char * paradigm) { size_t len; @@ -217,6 +274,7 @@ static void argv_scan( bool fval; bool fnext; bool fshort; + bool fhybrid; bool fnoscan; argv++; @@ -229,7 +287,8 @@ static void argv_scan( mentry = meta ? meta->entries : 0; while (ch && (ferror == ARGV_ERROR_OK)) { - option = 0; + option = 0; + fhybrid = false; if (fnoscan) fval = true; @@ -237,7 +296,10 @@ static void argv_scan( else if (is_last_option(ch)) fnoscan = true; - else if ((fshort || is_short_option(ch))) { + else if (!fshort && is_hybrid_option(ch,options)) + fhybrid = true; + + if (!fnoscan && !fhybrid && (fshort || is_short_option(ch))) { if (!fshort) ch++; @@ -285,8 +347,10 @@ static void argv_scan( } else ferror = ARGV_ERROR_SHORT_OPTION; - } else if ((is_long_option(ch))) { - if ((option = argv_long_option(ch+=2,options,&entry))) { + } else if (!fnoscan && (fhybrid || is_long_option(ch))) { + ch += (fhybrid ? 1 : 2); + + if ((option = argv_long_option(ch,options,&entry))) { val = ch + strlen(option->long_name); /* val[0] is either '=' or '\0' */ @@ -295,13 +359,21 @@ static void argv_scan( ch = *parg; } - if (option->optarg == ARGV_OPTARG_NONE) { + if (fhybrid && !(option->flags & ARGV_OPTION_HYBRID_SWITCH)) + ferror = ARGV_ERROR_HYBRID_NONE; + else if (option->optarg == ARGV_OPTARG_NONE) { if (val[0]) { ferror = ARGV_ERROR_OPTARG_NONE; ctx->errch = val + 1; } else fval = false; - } else if (val[0] && !val[1]) + } else if (!fhybrid && (option->flags & ARGV_OPTION_HYBRID_ONLY)) + ferror = ARGV_ERROR_HYBRID_ONLY; + else if (fhybrid && !val[0] && !(option->flags & ARGV_OPTION_HYBRID_SPACE)) + ferror = ARGV_ERROR_HYBRID_SPACE; + else if (fhybrid && val[0] && !(option->flags & ARGV_OPTION_HYBRID_EQUAL)) + ferror = ARGV_ERROR_HYBRID_EQUAL; + else if (val[0] && !val[1]) ferror = ARGV_ERROR_OPTARG_REQUIRED; else if (val[0] && val[1]) { fval = true; @@ -447,6 +519,30 @@ static void argv_show_error(struct argv_ctx * ctx) ctx->erropt->paradigm); break; + case ARGV_ERROR_HYBRID_NONE: + fprintf(stderr,"-%s is not a synonym for --%s\n", + ctx->erropt->long_name, + ctx->erropt->long_name); + break; + + case ARGV_ERROR_HYBRID_ONLY: + fprintf(stderr,"--%s is not a synonym for -%s\n", + ctx->erropt->long_name, + ctx->erropt->long_name); + break; + + case ARGV_ERROR_HYBRID_SPACE: + fprintf(stderr,"-%s: illegal value assignment; valid syntax is -%s=VAL\n", + ctx->erropt->long_name, + ctx->erropt->long_name); + break; + + case ARGV_ERROR_HYBRID_EQUAL: + fprintf(stderr,"-%s: illegal value assignment; valid syntax is -%s VAL\n", + ctx->erropt->long_name, + ctx->erropt->long_name); + break; + case ARGV_ERROR_INTERNAL: fputs("internal error",stderr); break; diff --git a/src/skin/mdso_skin_default.c b/src/skin/mdso_skin_default.c index 3206e4f..d2b8e4b 100644 --- a/src/skin/mdso_skin_default.c +++ b/src/skin/mdso_skin_default.c @@ -2,32 +2,32 @@ #include "argv/argv.h" const struct argv_option mdso_default_options[] = { - {"version", 'v',TAG_VERSION,ARGV_OPTARG_NONE,0,0, + {"version", 'v',TAG_VERSION,ARGV_OPTARG_NONE,0,0,0, "show version information"}, - {"help", 'h',TAG_HELP,ARGV_OPTARG_OPTIONAL,"short|long",0, + {"help", 'h',TAG_HELP,ARGV_OPTARG_OPTIONAL,0,"short|long",0, "show usage information [listing %s options only]"}, - {"machine", 'm',TAG_QUAD_PTR,ARGV_OPTARG_REQUIRED,"32|64",0, + {"machine", 'm',TAG_QUAD_PTR,ARGV_OPTARG_REQUIRED,0,"32|64",0, "set machine bits to %s"}, - {"libpath", 'l',TAG_LIBPATH,ARGV_OPTARG_REQUIRED,"loader|peb|system32",0, + {"libpath", 'l',TAG_LIBPATH,ARGV_OPTARG_REQUIRED,0,"loader|peb|system32",0, "runtime loader should search for the library either " "according to its internal/inherited path (loader), " "or according to the library path in the process PEB block (peb); " "alternatively, the loader may only search for the library " "in the system library directory (system32)."}, - {"libname", 'n',TAG_LIBNAME,ARGV_OPTARG_REQUIRED,0,"", + {"libname", 'n',TAG_LIBNAME,ARGV_OPTARG_REQUIRED,0,0,"", "set dependency library name to %s"}, - {"dstdir", 'd',TAG_DSTDIR,ARGV_OPTARG_REQUIRED,0,"", + {"dstdir", 'd',TAG_DSTDIR,ARGV_OPTARG_REQUIRED,0,0,"", "save generated assembly files under %s"}, - {"pretty", 'p',TAG_PRETTY,ARGV_OPTARG_REQUIRED,"yaml",0, + {"pretty", 'p',TAG_PRETTY,ARGV_OPTARG_REQUIRED,0,"yaml",0, "format output for parsing by %s"}, - {"expsyms", 'e',TAG_EXPSYMS,ARGV_OPTARG_NONE,0,0, + {"expsyms", 'e',TAG_EXPSYMS,ARGV_OPTARG_NONE,0,0,0, "print exported symbols" }, {0}