From cb61cf384385e42027468d84ff3fc48022911b21 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 30 Jun 2017 02:14:01 -0700 Subject: [PATCH] Rework argument parsing. Heavily simplify the interface of CLI. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-main/cli.c | 516 +++++++++++++++++++++-------------------- jerry-main/cli.h | 128 +++------- jerry-main/main-unix.c | 109 +++++---- 3 files changed, 344 insertions(+), 409 deletions(-) diff --git a/jerry-main/cli.c b/jerry-main/cli.c index be7f64ef89..1bf41f3c20 100644 --- a/jerry-main/cli.c +++ b/jerry-main/cli.c @@ -14,7 +14,7 @@ */ #include -#include +#include #include "cli.h" @@ -37,173 +37,233 @@ */ #define CLI_LINE_TAB 24 +/** + * Declare a char VLA and concatenate a program name and a sub-command name + * (separated by a single space) into the new array. Useful for printing command + * line option usage summary for sub-commands. + * + * @param CMDNAME name of the new array variable. + * @param PROGNAME string containing the name of the program. + * @param CMD string continaing the name of the sub-command. + */ +#define CLI_CMD_NAME(CMDNAME, PROGNAME, CMD) \ + char CMDNAME[strlen ((PROGNAME)) + strlen ((CMD)) + 2]; \ + strncpy (CMDNAME, (PROGNAME), strlen ((PROGNAME))); \ + CMDNAME[strlen ((PROGNAME))] = ' '; \ + strncpy (CMDNAME + strlen ((PROGNAME)) + 1, (CMD), strlen ((CMD)) + 1) + /* - * Print helper functions + * Command line option handling */ /** - * Pad with spaces. + * Initialize a command line option processor. + * + * @return the state that should be passed to other cli_ functions. */ -static void -cli_print_pad (int cnt) /**< number of spaces to print */ +cli_state_t +cli_init (const cli_opt_t *options, /**< array of option definitions, terminated by CLI_OPT_DEFAULT */ + int argc, /**< number of command line arguments */ + char **argv) /**< array of command line arguments */ { - for (int i = 0; i < cnt; i++) + return (cli_state_t) { - printf (" "); - } -} /* cli_print_pad */ + .error = NULL, + .arg = NULL, + .argc = argc, + .argv = argv, + .opts = options + }; +} /* cli_init */ /** - * Print the prefix of a string. + * Checks whether the current argument is an option. + * + * Note: + * The state->error is not NULL on error and it contains the error message. + * + * @return the ID of the option that was found or a CLI_OPT_ constant otherwise. */ -static void -cli_print_prefix (const char *str, /**< string to print */ - int len) /**< length of the prefix to print */ +int +cli_consume_option (cli_state_t *state) /**< state of the command line option processor */ { - for (int i = 0; i < len; i++) + if (state->error != NULL) { - printf ("%c", *str++); + return CLI_OPT_END; } -} /* cli_print_prefix */ -/** - * Print a help message wrapped into the second column. - */ -static void -cli_print_help (const char *help) /**< the help message to print */ -{ - while (help != NULL && *help != 0) + if (state->argc <= 0) { - int length = -1; - int i = 0; - for (; i < CLI_LINE_LENGTH - CLI_LINE_TAB && help[i] != 0; i++) + state->arg = NULL; + return CLI_OPT_END; + } + + const char *arg = state->argv[0]; + + state->arg = arg; + + if (arg[0] != '-') + { + return CLI_OPT_DEFAULT; + } + + if (arg[1] == '-') + { + arg += 2; + + for (const cli_opt_t *opt = state->opts; opt->id != CLI_OPT_DEFAULT; opt++) { - if (help[i] == ' ') + if (opt->longopt != NULL && strcmp (arg, opt->longopt) == 0) { - length = i; + state->argc--; + state->argv++; + return opt->id; } } - if (length < 0 || i < CLI_LINE_LENGTH - CLI_LINE_TAB) - { - length = i; - } - cli_print_prefix (help, length); + state->error = "Unknown long option"; + return CLI_OPT_END; + } - help += length; - while (*help == ' ' && *help != 0) - { - help++; - } + arg++; - if (*help != 0) + for (const cli_opt_t *opt = state->opts; opt->id != CLI_OPT_DEFAULT; opt++) + { + if (opt->opt != NULL && strcmp (arg, opt->opt) == 0) { - printf ("\n"); - cli_print_pad (CLI_LINE_TAB); + state->argc--; + state->argv++; + return opt->id; } } -} /* cli_print_help */ -/* - * Command line option handling - */ + state->error = "Unknown option"; + return CLI_OPT_END; +} /* cli_consume_option */ /** - * Initialize a command line option processor. + * Returns the next argument as string. * - * @return the state that should be passed iteratively to cli_opt_process. + * Note: + * The state->error is not NULL on error and it contains the error message. + * + * @return argument string */ -cli_opt_state_t -cli_opt_init (const cli_opt_t *opts, /**< array of option definitions, terminated by CLI_OPT_END */ - int argc, /**< number of command line arguments */ - char **argv) /**< array of command line arguments */ +const char * +cli_consume_string (cli_state_t *state) /**< state of the command line option processor */ { - return (cli_opt_state_t) + if (state->error != NULL) { - .opts = opts, - .argc = argc, - .argv = argv, - .opt = NULL, - .arg = NULL - }; -} /* cli_opt_init */ + return NULL; + } + + if (state->argc <= 0) + { + state->error = "Expected string argument"; + state->arg = NULL; + return NULL; + } + + state->arg = state->argv[0]; + + state->argc--; + state->argv++; + return state->arg; +} /* cli_consume_string */ /** - * Perform one step of the command line option processor. + * Returns the next argument as integer. * - * @return the ID of the option that was found. (The definition of the found - * option (if any) is available via state->opt, while the option - * string and its arguments are available via state->arg[0..].) - * CLI_OPT_END signals that all command line arguments are consumed. + * Note: + * The state->error is not NULL on error and it contains the error message. + * + * @return argument integer */ int -cli_opt_process (cli_opt_state_t *state) /**< state of the command line option processor */ +cli_consume_int (cli_state_t *state) /**< state of the command line option processor */ { + if (state->error != NULL) + { + return 0; + } + + state->error = "Expected integer argument"; + if (state->argc <= 0) { - state->opt = NULL; state->arg = NULL; - return CLI_OPT_END; + return 0; } - state->arg = state->argv; + state->arg = state->argv[0]; - for (const cli_opt_t *o = state->opts; o->id != CLI_OPT_END; o++) - { - state->opt = o; + char *endptr; + long int value = strtol (state->arg, &endptr, 10); - if (o->id == CLI_OPT_POSITIONAL && (state->arg[0][0] != '-' || !strcmp (state->arg[0], "-"))) - { - state->argc--; - state->argv++; - return CLI_OPT_POSITIONAL; - } - else if ((o->opt != NULL && !strcmp (o->opt, state->arg[0])) - || (o->longopt != NULL && !strcmp (o->longopt, state->arg[0]))) - { - if (state->argc > o->argc) - { - state->argc -= 1 + o->argc; - state->argv += 1 + o->argc; - return o->id; - } - else - { - state->argv += state->argc; - state->argc = 0; - return CLI_OPT_INCOMPLETE; - } - } + if (*endptr != '\0') + { + return 0; } - state->opt = NULL; + state->error = NULL; state->argc--; state->argv++; - return CLI_OPT_UNKNOWN; -} /* cli_opt_process */ + return (int) value; +} /* cli_consume_int */ + +/* + * Print helper functions + */ + +/** + * Pad with spaces. + */ +static void +cli_print_pad (int cnt) /**< number of spaces to print */ +{ + for (int i = 0; i < cnt; i++) + { + printf (" "); + } +} /* cli_print_pad */ + +/** + * Print the prefix of a string. + */ +static void +cli_print_prefix (const char *str, /**< string to print */ + int len) /**< length of the prefix to print */ +{ + for (int i = 0; i < len; i++) + { + printf ("%c", *str++); + } +} /* cli_print_prefix */ /** * Print usage summary of options. */ -void +static void cli_opt_usage (const char *progname, /**< program name, typically argv[0] */ - const cli_opt_t *opts) /**< array of command line option definitions, terminated by CLI_OPT_END */ + const cli_opt_t *opts) /**< array of command line option definitions, terminated by CLI_OPT_DEFAULT */ { int length = (int) strlen (progname); + const cli_opt_t *o = opts; + printf ("%s", progname); - for (const cli_opt_t *o = opts; o->id != CLI_OPT_END; o++) + while (o->id != CLI_OPT_DEFAULT) { - const char *opt = o->opt != NULL ? o->opt : o->longopt; - opt = opt != NULL ? opt : o->meta; + const char *opt = o->opt; + int opt_length = 2 + 1; - int opt_length = (int) strlen (opt); - if (o->argc > 0) + if (opt == NULL) { - opt_length += o->meta != NULL ? 1 + (int) strlen (o->meta) : o->argc * 2; + opt = o->longopt; + opt_length++; } - opt_length += o->quant == CLI_QUANT_Q || o->quant == CLI_QUANT_A ? 2 : 0; - opt_length += o->quant == CLI_QUANT_P || o->quant == CLI_QUANT_A ? 3 : 0; + + opt_length += (int) strlen (opt); if (length + 1 + opt_length >= CLI_LINE_LENGTH) { @@ -213,96 +273,124 @@ cli_opt_usage (const char *progname, /**< program name, typically argv[0] */ } length += opt_length; - printf (" "); + printf (" ["); + + if (o->opt != NULL) + { + printf ("-%s", opt); + } + else + { + printf ("--%s", opt); + } - if (o->quant == CLI_QUANT_Q || o->quant == CLI_QUANT_A) + if (o->meta != NULL) { - printf ("["); + printf (" %s", o->meta); } - printf ("%s", opt); + printf ("]"); + + o++; + } + + if (o->meta != NULL) + { + const char *opt = o->meta; + int opt_length = (int) (2 + strlen (opt)); - if (o->argc > 0) + if (length + 1 + opt_length >= CLI_LINE_LENGTH) { - if (o->meta != NULL) - { - printf (" %s", o->meta); - } - else + length = CLI_LINE_INDENT - 1; + printf ("\n"); + cli_print_pad (length); + } + + printf (" [%s]", opt); + } + + printf ("\n\n"); +} /* cli_opt_usage */ + +/** + * Print a help message wrapped into the second column. + */ +static void +cli_print_help (const char *help) /**< the help message to print */ +{ + while (help != NULL && *help != 0) + { + int length = -1; + int i = 0; + for (; i < CLI_LINE_LENGTH - CLI_LINE_TAB && help[i] != 0; i++) + { + if (help[i] == ' ') { - for (int i = 0; i < o->argc; i++) - { - printf (" _"); - } + length = i; } } + if (length < 0 || i < CLI_LINE_LENGTH - CLI_LINE_TAB) + { + length = i; + } + + cli_print_prefix (help, length); - if (o->quant == CLI_QUANT_Q || o->quant == CLI_QUANT_A) + help += length; + while (*help == ' ' && *help != 0) { - printf ("]"); + help++; } - if (o->quant == CLI_QUANT_P || o->quant == CLI_QUANT_A) + if (*help != 0) { - printf ("..."); + printf ("\n"); + cli_print_pad (CLI_LINE_TAB); } } - - printf ("\n"); -} /* cli_opt_usage */ +} /* cli_print_help */ /** * Print detailed help for options. */ void -cli_opt_help (const cli_opt_t *opts) /**< array of command line option definitions, terminated by CLI_OPT_END */ +cli_help (const char *progname, /**< program name, typically argv[0] */ + const cli_opt_t *options) /**< array of command line option definitions, terminated by CLI_OPT_DEFAULT */ { - for (const cli_opt_t *o = opts; o->id != CLI_OPT_END; o++) + cli_opt_usage (progname, options); + + const cli_opt_t *opt = options; + + while (opt->id != CLI_OPT_DEFAULT) { int length = CLI_LINE_INDENT; - cli_print_pad (length); + cli_print_pad (CLI_LINE_INDENT); - if (o->opt != NULL) + if (opt->opt != NULL) { - printf ("%s", o->opt); - length += (int) strlen (o->opt); + printf ("-%s", opt->opt); + length += (int) (strlen (opt->opt) + 1); } - if (o->opt != NULL && o->longopt != NULL) + if (opt->opt != NULL && opt->longopt != NULL) { printf (", "); length += 2; } - if (o->longopt != NULL) + if (opt->longopt != NULL) { - printf ("%s", o->longopt); - length += (int) strlen (o->longopt); + printf ("--%s", opt->longopt); + length += (int) (strlen (opt->longopt) + 2); } - if (o->opt == NULL && o->longopt == NULL) + if (opt->meta != NULL) { - printf ("%s", o->meta); - length += (int) strlen (o->meta); - } - else if (o->argc > 0) - { - if (o->meta != NULL) - { - printf (" %s", o->meta); - length += 1 + (int) strlen (o->meta); - } - else - { - for (int i = 0; i < o->argc; i++) - { - printf (" _"); - } - length += o->argc * 2; - } + printf (" %s", opt->meta); + length += 1 + (int) strlen (opt->meta); } - if (o->help != NULL) + if (opt->help != NULL) { if (length >= CLI_LINE_TAB) { @@ -312,118 +400,34 @@ cli_opt_help (const cli_opt_t *opts) /**< array of command line option definitio cli_print_pad (CLI_LINE_TAB - length); length = CLI_LINE_TAB; - cli_print_help (o->help); + cli_print_help (opt->help); } printf ("\n"); + opt++; } -} /* cli_opt_help */ - -/* - * Sub-command handling - */ - -/** - * Initialize a sub-command processor. - * - * @return the state that should be passed to cli_cmd_process. - */ -cli_cmd_state_t -cli_cmd_init (const cli_cmd_t *cmds, /**< array of sub-command definitions, terminated by CLI_CMD_END */ - int argc, /**< number of command line arguments */ - char **argv) /**< array of command line arguments */ -{ - return (cli_cmd_state_t) - { - .cmds = cmds, - .argc = argc, - .argv = argv, - .cmd = NULL, - .arg = NULL - }; -} /* cli_cmd_init */ - -/** - * Process first element of the command line and determine whether it is a - * defined sub-command or not. - * - * @return the ID of the sub-command that was found. - */ -int -cli_cmd_process (cli_cmd_state_t *state) /**< state of the sub-command processor */ -{ - if (state->argc <= 0 || state->argv[0][0] == '-') - { - state->cmd = NULL; - state->arg = NULL; - return CLI_CMD_NONE; - } - - state->arg = state->argv; - for (const cli_cmd_t *c = state->cmds; c->id != CLI_CMD_END; c++) + if (opt->help != NULL) { - state->cmd = c; + int length = 0; - if (!strcmp (c->cmd, state->argv[0])) + if (opt->meta != NULL) { - state->argc--; - state->argv++; - state->cmd = c; - return c->id; - } - } + length = (int) (CLI_LINE_INDENT + strlen (opt->meta)); - state->cmd = NULL; - state->argc--; - state->argv++; - return CLI_CMD_UNKNOWN; -} /* cli_cmd_process */ - -/** - * Print usage summary of all sub-commands. - */ -void -cli_cmd_usage (const char *progname, /**< program name, typically argv[0] */ - const cli_cmd_t *cmds) /**< array of sub-command definitions, terminated by CLI_CMD_END */ -{ - for (const cli_cmd_t *c = cmds; c->id != CLI_CMD_END; c++) - { - if (c->cmd != NULL) - { - CLI_CMD_NAME (cmdname, progname, c->cmd); - cli_opt_usage (cmdname, c->opts); + cli_print_pad (CLI_LINE_INDENT); + printf ("%s", opt->meta); } - } -} /* cli_cmd_usage */ - -/** - * Print help of all sub-commands. - */ -void -cli_cmd_help (const cli_cmd_t *cmds) /**< array of sub-command definitions, terminated by CLI_CMD_END */ -{ - for (const cli_cmd_t *c = cmds; c->id != CLI_CMD_END; c++) - { - int length = CLI_LINE_INDENT; - cli_print_pad (length); - - printf ("%s", c->cmd); - length += (int) strlen (c->cmd); - if (c->help != NULL) + if (length >= CLI_LINE_TAB) { - if (length >= CLI_LINE_TAB) - { - printf ("\n"); - length = 0; - } - cli_print_pad (CLI_LINE_TAB - length); - length = CLI_LINE_TAB; - - cli_print_help (c->help); + printf ("\n"); + length = 0; } + cli_print_pad (CLI_LINE_TAB - length); + + cli_print_help (opt->help); printf ("\n"); } -} /* cli_cmd_help */ +} /* cli_help */ diff --git a/jerry-main/cli.h b/jerry-main/cli.h index a5223de4f1..3117e3256c 100644 --- a/jerry-main/cli.h +++ b/jerry-main/cli.h @@ -18,134 +18,58 @@ #include -/* - * Types for CLI - */ - /** - * Command line option definition + * Command line option definition. */ typedef struct { - int id; /**< unique ID of the option (CLI_OPT_END, CLI_OPT_POSITIONAL, or anything >= 0) */ - const char *opt; /**< short option variant (in the form of "-x") */ - const char *longopt; /**< long option variant (in the form of "--xxx") */ - int argc; /**< number of arguments of the option */ + int id; /**< unique ID of the option (CLI_OPT_DEFAULT, or anything >= 0) */ + const char *opt; /**< short option variant (in the form of "x" without dashes) */ + const char *longopt; /**< long option variant (in the form of "xxx" without dashes) */ const char *meta; /**< name(s) of the argument(s) of the option, for display only */ - int quant; /**< quantifier of the option (CLI_QUANT_{Q,A,P,1} for ?,*,+,1), for display only */ const char *help; /**< descriptive help message of the option */ } cli_opt_t; /** - * Quantifiers of command line options - */ -typedef enum -{ - CLI_QUANT_Q, /**< ? (Question mark: optional, zero or one) */ - CLI_QUANT_A, /**< * (Asterisk, star: zero or one or more) */ - CLI_QUANT_P, /**< + (Plus sign: one or more) */ - CLI_QUANT_1 /**< 1 (One: one) */ -} cli_opt_quant_t; - -/** - * Common command line option IDs - */ -typedef enum -{ - CLI_OPT_POSITIONAL = -1, /**< positional "option" */ - CLI_OPT_END = -2, /**< end of options marker */ - CLI_OPT_INCOMPLETE = -3, /**< incomplete option (too few arguments) */ - CLI_OPT_UNKNOWN = -4 /**< unknown option */ -} cli_opt_id_t; - -/** - * State of the command line option processor. - * No fields should be accessed other than arg and opt. + * Special marker for default option which also marks the end of the option list. */ -typedef struct -{ - const cli_opt_t *opts; - int argc; - char **argv; - const cli_opt_t *opt; /**< found option or NULL */ - char **arg; /**< array of strings for the last processed option */ -} cli_opt_state_t; +#define CLI_OPT_DEFAULT -1 /** - * Sub-command definition + * Returned by cli_consume_option () when no more options are available + * or an error occured. */ -typedef struct -{ - int id; /**< unique ID of the sub-command (CLI_CMD_END, or anything >= 0) */ - const char *cmd; /**< sub-command name (in the form of "xxx") */ - const cli_opt_t *opts; /**< array of associated command line option definitions, for display only */ - const char *help; /**< descriptive help message of the sub-command */ -} cli_cmd_t; - -/** - * Common sub-command IDs - */ -typedef enum -{ - CLI_CMD_END = -1, /**< end of sub-commands marker */ - CLI_CMD_NONE = -1, /**< no sub-command */ - CLI_CMD_UNKNOWN = -2 /**< unknown sub-command */ -} cli_cmd_id_t; +#define CLI_OPT_END -2 /** * State of the sub-command processor. - * No fields should be accessed other than arg and cmd. + * No fields should be accessed other than error and arg. */ typedef struct { - const cli_cmd_t *cmds; - int argc; - char **argv; - const cli_cmd_t *cmd; /**< found command or NULL */ - char **arg; /**< array of strings for the processed command */ -} cli_cmd_state_t; - -/* - * Functions for CLI - */ + /* Public fields. */ + const char *error; /**< public field for error message */ + const char *arg; /**< last processed argument as string */ -cli_opt_state_t cli_opt_init (const cli_opt_t *opts, int argc, char **argv); -int cli_opt_process (cli_opt_state_t *state); -void cli_opt_usage (const char *progname, const cli_opt_t *opts); -void cli_opt_help (const cli_opt_t *opts); - -cli_cmd_state_t cli_cmd_init (const cli_cmd_t *cmds, int argc, char **argv); -int cli_cmd_process (cli_cmd_state_t *state); -void cli_cmd_help (const cli_cmd_t *cmds); -void cli_cmd_usage (const char *progname, const cli_cmd_t *cmds); - -/* - * Useful macros for CLI - */ + /* Private fields. */ + int argc; /**< remaining number of arguments */ + char **argv; /**< remaining arguments */ + const cli_opt_t *opts; /**< options */ +} cli_state_t; /** - * Macro for writing command line option definition struct literals + * Macro for writing command line option definition struct literals. */ #define CLI_OPT_DEF(...) /*(cli_opt_t)*/ { __VA_ARGS__ } -/** - * Macro for writing sub-command definition struct literals +/* + * Functions for CLI. */ -#define CLI_CMD_DEF(...) /*(cli_cmd_t)*/ { __VA_ARGS__ } -/** - * Declare a char VLA and concatenate a program name and a sub-command name - * (separated by a single space) into the new array. Useful for printing command - * line option usage summary for sub-commands. - * - * @param CMDNAME name of the new array variable. - * @param PROGNAME string containing the name of the program. - * @param CMD string continaing the name of the sub-command. - */ -#define CLI_CMD_NAME(CMDNAME, PROGNAME, CMD) \ - char CMDNAME[strlen ((PROGNAME)) + strlen ((CMD)) + 2]; \ - strncpy (CMDNAME, (PROGNAME), strlen ((PROGNAME))); \ - CMDNAME[strlen ((PROGNAME))] = ' '; \ - strncpy (CMDNAME + strlen ((PROGNAME)) + 1, (CMD), strlen ((CMD)) + 1) +cli_state_t cli_init (const cli_opt_t *options, int argc, char **argv); +int cli_consume_option (cli_state_t *state); +const char * cli_consume_string (cli_state_t *state); +int cli_consume_int (cli_state_t *state); +void cli_help (const char *progname, const cli_opt_t *options); #endif /* CLI_H */ diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index 5f8f7e5ac5..d8fb2bf029 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -292,41 +292,40 @@ typedef enum /** * Command line options */ -static cli_opt_t main_opts[] = +static const cli_opt_t main_opts[] = { - CLI_OPT_DEF (.id = OPT_HELP, .opt = "-h", .longopt = "--help", + CLI_OPT_DEF (.id = OPT_HELP, .opt = "h", .longopt = "help", .help = "print this help and exit"), - CLI_OPT_DEF (.id = OPT_VERSION, .opt = "-v", .longopt = "--version", + CLI_OPT_DEF (.id = OPT_VERSION, .opt = "v", .longopt = "version", .help = "print tool and library version and exit"), - CLI_OPT_DEF (.id = OPT_MEM_STATS, .longopt = "--mem-stats", + CLI_OPT_DEF (.id = OPT_MEM_STATS, .longopt = "mem-stats", .help = "dump memory statistics"), - CLI_OPT_DEF (.id = OPT_PARSE_ONLY, .longopt = "--parse-only", + CLI_OPT_DEF (.id = OPT_PARSE_ONLY, .longopt = "parse-only", .help = "don't execute JS input"), - CLI_OPT_DEF (.id = OPT_SHOW_OP, .longopt = "--show-opcodes", + CLI_OPT_DEF (.id = OPT_SHOW_OP, .longopt = "show-opcodes", .help = "dump parser byte-code"), - CLI_OPT_DEF (.id = OPT_SHOW_RE_OP, .longopt = "--show-regexp-opcodes", + CLI_OPT_DEF (.id = OPT_SHOW_RE_OP, .longopt = "show-regexp-opcodes", .help = "dump regexp byte-code"), - CLI_OPT_DEF (.id = OPT_DEBUG_SERVER, .longopt = "--start-debug-server", + CLI_OPT_DEF (.id = OPT_DEBUG_SERVER, .longopt = "start-debug-server", .help = "start debug server and wait for a connecting client"), - CLI_OPT_DEF (.id = OPT_SAVE_SNAP_GLOBAL, .longopt = "--save-snapshot-for-global", .argc = 1, .meta = "FILE", + CLI_OPT_DEF (.id = OPT_SAVE_SNAP_GLOBAL, .longopt = "save-snapshot-for-global", .meta = "FILE", .help = "save binary snapshot of parsed JS input (for execution in global context)"), - CLI_OPT_DEF (.id = OPT_SAVE_SNAP_EVAL, .longopt = "--save-snapshot-for-eval", .argc = 1, .meta = "FILE", + CLI_OPT_DEF (.id = OPT_SAVE_SNAP_EVAL, .longopt = "save-snapshot-for-eval", .meta = "FILE", .help = "save binary snapshot of parsed JS input (for execution in local context by eval)"), - CLI_OPT_DEF (.id = OPT_SAVE_LIT_LIST, .longopt = "--save-literals-list-format", .argc = 1, .meta = "FILE", + CLI_OPT_DEF (.id = OPT_SAVE_LIT_LIST, .longopt = "save-literals-list-format", .meta = "FILE", .help = "export literals found in parsed JS input (in list format)"), - CLI_OPT_DEF (.id = OPT_SAVE_LIT_C, .longopt = "--save-literals-c-format", .argc = 1, .meta = "FILE", + CLI_OPT_DEF (.id = OPT_SAVE_LIT_C, .longopt = "save-literals-c-format", .meta = "FILE", .help = "export literals found in parsed JS input (in C source format)"), - CLI_OPT_DEF (.id = OPT_EXEC_SNAP, .longopt = "--exec-snapshot", .argc = 1, .meta = "FILE", .quant = CLI_QUANT_A, + CLI_OPT_DEF (.id = OPT_EXEC_SNAP, .longopt = "exec-snapshot", .meta = "FILE", .help = "execute input snapshot file(s)"), - CLI_OPT_DEF (.id = OPT_LOG_LEVEL, .longopt = "--log-level", .argc = 1, .meta = "NUM", + CLI_OPT_DEF (.id = OPT_LOG_LEVEL, .longopt = "log-level", .meta = "NUM", .help = "set log level (0-3)"), - CLI_OPT_DEF (.id = OPT_ABORT_ON_FAIL, .longopt = "--abort-on-fail", + CLI_OPT_DEF (.id = OPT_ABORT_ON_FAIL, .longopt = "abort-on-fail", .help = "segfault on internal failure (instead of non-zero exit code)"), - CLI_OPT_DEF (.id = OPT_NO_PROMPT, .longopt = "--no-prompt", + CLI_OPT_DEF (.id = OPT_NO_PROMPT, .longopt = "no-prompt", .help = "don't print prompt in REPL mode"), - CLI_OPT_DEF (.id = CLI_OPT_POSITIONAL, .meta = "FILE", .quant = CLI_QUANT_A, - .help = "input JS file(s)"), - CLI_OPT_DEF (.id = CLI_OPT_END) + CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE", + .help = "input JS file(s)") }; /** @@ -360,8 +359,7 @@ check_usage (bool condition, /**< the condition that must hold */ { if (!condition) { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "%s%s\n", msg, opt != NULL ? opt : ""); - cli_opt_usage (name, main_opts); + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "%s: %s%s\n", name, msg, opt != NULL ? opt : ""); exit (JERRY_STANDALONE_EXIT_CODE_FAIL); } } /* check_usage */ @@ -404,16 +402,14 @@ main (int argc, bool is_repl_mode = false; bool no_prompt = false; - cli_opt_state_t cli_state = cli_opt_init (main_opts, argc - 1, argv + 1); - for (int id = cli_opt_process (&cli_state); id != CLI_OPT_END; id = cli_opt_process (&cli_state)) + cli_state_t cli_state = cli_init (main_opts, argc - 1, argv + 1); + for (int id = cli_consume_option (&cli_state); id != CLI_OPT_END; id = cli_consume_option (&cli_state)) { switch (id) { case OPT_HELP: { - cli_opt_usage (argv[0], main_opts); - printf ("\n"); - cli_opt_help (main_opts); + cli_help (argv[0], main_opts); return JERRY_STANDALONE_EXIT_CODE_OK; } case OPT_VERSION: @@ -423,7 +419,7 @@ main (int argc, } case OPT_MEM_STATS: { - if (check_feature (JERRY_FEATURE_MEM_STATS, cli_state.arg[0])) + if (check_feature (JERRY_FEATURE_MEM_STATS, cli_state.arg)) { jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG); flags |= JERRY_INIT_MEM_STATS; @@ -437,7 +433,7 @@ main (int argc, } case OPT_SHOW_OP: { - if (check_feature (JERRY_FEATURE_PARSER_DUMP, cli_state.arg[0])) + if (check_feature (JERRY_FEATURE_PARSER_DUMP, cli_state.arg)) { jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG); flags |= JERRY_INIT_SHOW_OPCODES; @@ -446,7 +442,7 @@ main (int argc, } case OPT_SHOW_RE_OP: { - if (check_feature (JERRY_FEATURE_REGEXP_DUMP, cli_state.arg[0])) + if (check_feature (JERRY_FEATURE_REGEXP_DUMP, cli_state.arg)) { jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG); flags |= JERRY_INIT_SHOW_REGEXP_OPCODES; @@ -455,7 +451,7 @@ main (int argc, } case OPT_DEBUG_SERVER: { - if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg[0])) + if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg)) { flags |= JERRY_INIT_DEBUGGER; } @@ -465,40 +461,43 @@ main (int argc, case OPT_SAVE_SNAP_EVAL: { check_usage (save_snapshot_file_name_p == NULL, argv[0], "Error: snapshot file name already specified", NULL); - if (check_feature (JERRY_FEATURE_SNAPSHOT_SAVE, cli_state.arg[0])) + if (check_feature (JERRY_FEATURE_SNAPSHOT_SAVE, cli_state.arg)) { is_save_snapshot_mode = true; - is_save_snapshot_mode_for_global_or_eval = cli_state.opt->id == OPT_SAVE_SNAP_GLOBAL; - save_snapshot_file_name_p = cli_state.arg[1]; + is_save_snapshot_mode_for_global_or_eval = (id == OPT_SAVE_SNAP_GLOBAL); } + save_snapshot_file_name_p = cli_consume_string (&cli_state); break; } case OPT_SAVE_LIT_LIST: case OPT_SAVE_LIT_C: { check_usage (save_literals_file_name_p == NULL, argv[0], "Error: literal file name already specified", NULL); - if (check_feature (JERRY_FEATURE_SNAPSHOT_SAVE, cli_state.arg[0])) + if (check_feature (JERRY_FEATURE_SNAPSHOT_SAVE, cli_state.arg)) { is_save_literals_mode = true; - is_save_literals_mode_in_c_format_or_list = cli_state.opt->id == OPT_SAVE_LIT_C; - save_literals_file_name_p = cli_state.arg[1]; + is_save_literals_mode_in_c_format_or_list = (id == OPT_SAVE_LIT_C); } + save_literals_file_name_p = cli_consume_string (&cli_state); break; } case OPT_EXEC_SNAP: { - if (check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg[0])) + if (check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg)) { - exec_snapshot_file_names[exec_snapshots_count++] = cli_state.arg[1]; + exec_snapshot_file_names[exec_snapshots_count++] = cli_consume_string (&cli_state); + } + else + { + cli_consume_string (&cli_state); } break; } case OPT_LOG_LEVEL: { - char *endptr; - long int log_level = strtol (cli_state.arg[1], &endptr, 10); - check_usage (log_level >= 0 && log_level <= 3 && !*endptr, - argv[0], "Error: wrong format for ", cli_state.arg[0]); + long int log_level = cli_consume_int (&cli_state); + check_usage (log_level >= 0 && log_level <= 3, + argv[0], "Error: invalid value for --log-level: ", cli_state.arg); jerry_port_default_set_log_level ((jerry_log_level_t) log_level); break; @@ -513,25 +512,33 @@ main (int argc, no_prompt = true; break; } - case CLI_OPT_POSITIONAL: + case CLI_OPT_DEFAULT: { - file_names[files_counter++] = cli_state.arg[0]; + file_names[files_counter++] = cli_consume_string (&cli_state); break; } - case CLI_OPT_INCOMPLETE: - { - check_usage (false, argv[0], "Error: incomplete option: ", cli_state.arg[0]); - break; - } - case CLI_OPT_UNKNOWN: default: { - check_usage (false, argv[0], "Error: unrecognized option: ", cli_state.arg[0]); + cli_state.error = "Internal error"; break; } } } + if (cli_state.error != NULL) + { + if (cli_state.arg != NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state.error, cli_state.arg); + } + else + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state.error); + } + + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + if (is_save_snapshot_mode) { check_usage (files_counter == 1,