diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-26 14:22:58 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-26 14:22:58 +0300 |
commit | 5cb3ba92b9c891a481998a45052649a724931687 (patch) | |
tree | c040740312420e4fdaf0ae74527cab51497e9a94 /src | |
parent | 517aad5ca97b8ed3a62dcbeca921bb930e897fbf (diff) | |
download | eclat-5cb3ba92b9c891a481998a45052649a724931687.tar.gz eclat-5cb3ba92b9c891a481998a45052649a724931687.tar.bz2 |
Change command line syntax.
The new syntax is:
eclat [GLOBAL-OPTIONS] COMMAND [COMMAND-OPTIONS] [ARGS]
* grecs: Upgrade.
* lib/forlan.c: New forlan function: sort().
* src/.gitignore: Update.
* src/Makefile.am: Update.
* src/cmdline.opt: Use the nopermute option.
* src/dscrtags-cl.opt: New file.
* src/descrtags.c: Rename to src/dscrtags.c
* src/eclat.c (command): Revamp structure.
(eclat_command): Remove.
(command_tab): Remove.
(cmdtab,cmdcnt): New globals.
(main): Change command line syntax.
* src/eclat.h (eclat_command): Remove.
(eclat_command): Remove.
* src/startinst-cl.opt: New file.
* src/startinst.c: Include startinst-cl.h. Process the command
line options.
Diffstat (limited to 'src')
-rw-r--r-- | src/.gitignore | 1 | ||||
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/cmdline.opt | 28 | ||||
-rw-r--r-- | src/dscrtags-cl.opt | 30 | ||||
-rw-r--r-- | src/dscrtags.c (renamed from src/descrtags.c) | 7 | ||||
-rw-r--r-- | src/eclat.c | 130 | ||||
-rw-r--r-- | src/eclat.h | 9 | ||||
-rw-r--r-- | src/startinst-cl.opt | 33 | ||||
-rw-r--r-- | src/startinst.c | 17 |
9 files changed, 202 insertions, 65 deletions
diff --git a/src/.gitignore b/src/.gitignore index 2f6973f..d5f23bd 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,2 +1,3 @@ cmdline.h +*-cl.h eclat diff --git a/src/Makefile.am b/src/Makefile.am index bda0584..bdc1f9e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,10 +20,12 @@ eclat_SOURCES=\ accfile.c\ cmdline.h\ config.c\ - descrtags.c\ + dscrtags.c\ + dscrtags-cl.h\ eclat.c\ eclat.h\ - startinst.c + startinst.c\ + startinst-cl.h AM_LDFLAGS = $(CURL_LIBS) LDADD=../lib/libeclat.a @LIBOBJS@ ../grecs/src/libgrecs.a @@ -34,7 +36,11 @@ AM_CPPFLAGS= \ -DDEFAULT_INCLUDE_DIR=\"$(pkgdatadir)/include\"\ -DDEFAULT_PREPROCESSOR="$(DEFAULT_PREPROCESSOR)" -BUILT_SOURCES=cmdline.h +BUILT_SOURCES=\ + cmdline.h\ + dscrtags-cl.h\ + startinst-cl.h + EXTRA_DIST=cmdline.opt eclat.conf SUFFIXES=.opt .c .h diff --git a/src/cmdline.opt b/src/cmdline.opt index b295456..d07309f 100644 --- a/src/cmdline.opt +++ b/src/cmdline.opt @@ -36,10 +36,12 @@ replace_string_var(void *p) } OPTIONS_BEGIN("eclat", - [<EC2 Command Line Administrator Tool>],[<>], + [<EC2 Command Line Administrator Tool>], + [<COMMAND [COMMAND-OPTIONS...]>], [<gnu>], + [<nopermute>], [<copyright_year=2012>], - [<copyright_holder=Sergey Poznyakoff>]) + [<copyright_holder=Sergey Poznyakoff>],[<nopermute>]) GROUP(Selecting program mode) @@ -69,26 +71,6 @@ BEGIN conffile = optarg; END -GROUP(Commands) - -OPTION(start-instances,,, - [<Start named instances>]) -BEGIN - eclat_command = eclat_command_start_instances; -END - -OPTION(stop-instances,,, - [<Stop named instances>]) -BEGIN - eclat_command = eclat_command_stop_instances; -END - -OPTION(describe-tags,,, - [<describe tags>]) -BEGIN - eclat_command = eclat_command_describe_tags; -END - GROUP(Modifiers) OPTION(region,,NAME, @@ -219,7 +201,7 @@ END OPTIONS_END -void +static void parse_options(int argc, char *argv[], int *index) { GETOPT(argc, argv, *index, exit(EX_USAGE)) diff --git a/src/dscrtags-cl.opt b/src/dscrtags-cl.opt new file mode 100644 index 0000000..230031a --- /dev/null +++ b/src/dscrtags-cl.opt @@ -0,0 +1,30 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +OPTIONS_BEGIN("eclat describe-tags", + [<List tags and their values>], + [<[FILTER...]>], + [<gnu>], + [<nousage>], + [<noversion>]) + +OPTIONS_END + +static void +parse_options(int argc, char *argv[], int *index) +{ + GETOPT(argc, argv, *index, exit(EX_USAGE)) +} diff --git a/src/descrtags.c b/src/dscrtags.c index 2fc44ef..fca46d3 100644 --- a/src/descrtags.c +++ b/src/dscrtags.c @@ -15,6 +15,7 @@ along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ #include "eclat.h" +#include "dscrtags-cl.h" int eclat_describe_tags(CURL *curl, int argc, char **argv) @@ -28,7 +29,11 @@ eclat_describe_tags(CURL *curl, int argc, char **argv) CURLcode res; struct wordsplit ws; int wsflags; - + + parse_options(argc, argv, &i); + argv += i; + argc -= i; + q = eclat_query_create(use_ssl ? EC2_QF_HTTPS : 0, endpoint, "/"); eclat_query_add_param(q, "Action", "DescribeTags"); diff --git a/src/eclat.c b/src/eclat.c index d20af4a..7d1c642 100644 --- a/src/eclat.c +++ b/src/eclat.c @@ -28,7 +28,6 @@ char *secret_key; char *region_name; char *format_file; int sort_option; -enum eclat_command eclat_command; FILE *xml_dump_file; @@ -210,28 +209,101 @@ node_ident_cmp(struct grecs_node const *a, struct grecs_node const *b) #include "cmdline.h" struct command { - const char *name; + const char *ident; + size_t match_len; + const char *tag; eclat_command_handler_t handler; char *fmt; struct grecs_locus locus; }; -struct command command_tab[] = { - { NULL, NULL }, - { "StartInstances", eclat_start_instance }, - { "StopInstances", eclat_stop_instance }, - { "DescribeTags", eclat_describe_tags } +struct command cmdtab[] = { + { "start-instances", 1, "StartInstances", eclat_start_instance }, + { "stop-instances", 1, "StopInstances", eclat_stop_instance }, + { "describe-tags", 1, "DescribeTags", eclat_describe_tags } }; +size_t cmdcnt = sizeof(cmdtab) / sizeof(cmdtab[0]); +static int +cmdcmp(const void *a, const void *b) +{ + struct command const *cmda = a, *cmdb = b; + return strcmp(cmda->ident, cmdb->ident); +} + +void +init_cmdtab() +{ + size_t i; + + /* Sort commands alphabetically */ + qsort(cmdtab, cmdcnt, sizeof(cmdtab[0]), cmdcmp); + /* Determine minimum abbreviations */ + for (i = 0; i < cmdcnt; i++) { + const char *sample = cmdtab[i].ident; + size_t sample_len = strlen(sample); + size_t minlen = cmdtab[i].match_len; + size_t j; + + for (j = i + 1; j < cmdcnt; j++) { + size_t len = strlen(cmdtab[j].ident); + if (len >= minlen && memcmp(cmdtab[j].ident, sample, + minlen) == 0) + do { + minlen++; + if (minlen <= strlen(cmdtab[j].ident)) + cmdtab[j].match_len = minlen; + if (minlen == sample_len) + break; + } while (len >= minlen && + memcmp(cmdtab[j].ident, + sample, minlen) == 0); + else if (cmdtab[j].ident[0] == sample[0]) + cmdtab[j].match_len = minlen; + else + break; + } + if (minlen <= sample_len) + cmdtab[i].match_len = minlen; + } +} + +void +listcmd() +{ + struct command *cp; + + printf("Available commands:\n"); + for (cp = cmdtab; cp < cmdtab + cmdcnt; cp++) + printf(" %s\n", cp->ident); + + printf("\nRun \"%s COMMAND --help\" to get help on a particular command.\n", + program_name); + + putchar('\n'); +} + struct command * -find_command(const char *name) +find_command_name(const char *name) { struct command *cp; + size_t namelen = strlen(name); + + for (cp = cmdtab; cp < cmdtab + cmdcnt; cp++) { + if (cp->match_len <= namelen && + memcmp(name, cp->ident, namelen) == 0) + return cp; + } + return NULL; +} - for (cp = command_tab + 1; - cp < command_tab + sizeof(command_tab)/sizeof(command_tab[0]); - cp++) { - if (strcmp(cp->name, name) == 0) +struct command * +find_command_tag(const char *tag) +{ + struct command *cp; + + for (cp = cmdtab; cp < cmdtab + cmdcnt; cp++) { + if (strcmp(cp->tag, tag) == 0) return cp; } return NULL; @@ -240,7 +312,7 @@ find_command(const char *name) void define_format(const char *name, const char *format, grecs_locus_t *locus) { - struct command *cp = find_command(name); + struct command *cp = find_command_tag(name); if (!cp) { grecs_error(locus, 0, "unknown command"); @@ -283,15 +355,11 @@ compile_format_file(const char *fmtfile) } forlan_eval_env_t -compile_default_format() +compile_default_format(struct command *cmd) { forlan_eval_env_t env; - if (!command_tab[eclat_command].fmt) - return; - env = forlan_parse_buffer(command_tab[eclat_command].fmt, - strlen(command_tab[eclat_command].fmt), - &command_tab[eclat_command].locus.beg); + env = forlan_parse_buffer(cmd->fmt, strlen(cmd->fmt), &cmd->locus.beg); if (!env) exit(EX_UNAVAILABLE); @@ -310,8 +378,11 @@ main(int argc, char **argv) eclat_partial_tree_t part; struct grecs_node *xmltree; forlan_eval_env_t env = NULL; + struct command *command = NULL; set_program_name(argv[0]); + init_cmdtab(); + proginfo.print_help_hook = listcmd; debug_init(); forlan_init(); config_init(); @@ -320,6 +391,12 @@ main(int argc, char **argv) argc -= index; argv += index; + if (argc) { + command = find_command_name(argv[0]); + if (!command) + die(EX_USAGE, "unrecognized command"); + } + grecs_gram_trace(debug_level(ECLAT_DEBCAT_CFGRAM)); grecs_lex_trace(debug_level(ECLAT_DEBCAT_CFLEX)); @@ -347,13 +424,15 @@ main(int argc, char **argv) if (format_file) env = compile_format_file(format_file); - else - env = compile_default_format(); - - + else if (command) + env = compile_default_format(command); + if (lint_mode) exit(0); + if (!command) + die(EX_USAGE, "no command given"); + if (region_name) { endpoint = region_to_endpoint(region_name); if (!endpoint) @@ -368,9 +447,6 @@ main(int argc, char **argv) } debug(ECLAT_DEBCAT_MAIN, 1, ("using access key %s", access_key)); - if (eclat_command == eclat_command_unspecified) - die(EX_USAGE, "no command given"); - curl = curl_easy_init(); if (!curl) die(EX_UNAVAILABLE, "curl_easy_init failed"); @@ -398,7 +474,7 @@ main(int argc, char **argv) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, parser); - rc = command_tab[eclat_command].handler(curl, argc, argv); + rc = command->handler(curl, argc, argv); curl_easy_cleanup(curl); XML_Parse(parser, "", 0, 1); if (xml_dump_file) diff --git a/src/eclat.h b/src/eclat.h index 1726c92..d8043f7 100644 --- a/src/eclat.h +++ b/src/eclat.h @@ -53,15 +53,6 @@ void config_init(void); void config_finish(struct grecs_node *tree); int run_config_finish_hooks(void); -enum eclat_command { - eclat_command_unspecified, - eclat_command_start_instances, - eclat_command_stop_instances, - eclat_command_describe_tags -}; - -extern enum eclat_command eclat_command; - typedef int (*eclat_command_handler_t) (CURL *curl, int argc, char **argv); int eclat_start_instance(CURL *curl, int argc, char **argv); diff --git a/src/startinst-cl.opt b/src/startinst-cl.opt new file mode 100644 index 0000000..9f986aa --- /dev/null +++ b/src/startinst-cl.opt @@ -0,0 +1,33 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +OPTIONS_BEGIN(NULL, + NULL, + [<ID [ID...]>], + [<gnu>], + [<nousage>], + [<noversion>]) + +OPTIONS_END + +static void +parse_options(const char *progname, const char *docstring, + int argc, char *argv[], int *index) +{ + proginfo.progname = progname; + proginfo.docstring = docstring; + GETOPT(argc, argv, *index, exit(EX_USAGE)) +} diff --git a/src/startinst.c b/src/startinst.c index bf1c364..581b76f 100644 --- a/src/startinst.c +++ b/src/startinst.c @@ -15,6 +15,7 @@ along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ #include "eclat.h" +#include "startinst-cl.h" static int start_stop_instance(CURL *curl, const char *action, int argc, char **argv) @@ -65,14 +66,26 @@ start_stop_instance(CURL *curl, const char *action, int argc, char **argv) int eclat_start_instance(CURL *curl, int argc, char **argv) { + int i; + + parse_options("eclat start-instances", + "Start named instances", + argc, argv, &i); + debug(ECLAT_DEBCAT_MAIN, 1, ("starting instances")); - start_stop_instance(curl, "StartInstances", argc, argv); + start_stop_instance(curl, "StartInstances", argc - i, argv + i); } int eclat_stop_instance(CURL *curl, int argc, char **argv) { + int i; + + parse_options("eclat stop-instances", + "Stop named instances", + argc, argv, &i); + debug(ECLAT_DEBCAT_MAIN, 1, ("stopping instances")); - start_stop_instance(curl, "StopInstances", argc, argv); + start_stop_instance(curl, "StopInstances", argc - i, argv + i); } |