aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2012-09-26 14:22:58 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2012-09-26 14:22:58 +0300
commit5cb3ba92b9c891a481998a45052649a724931687 (patch)
treec040740312420e4fdaf0ae74527cab51497e9a94 /src
parent517aad5ca97b8ed3a62dcbeca921bb930e897fbf (diff)
downloadeclat-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/.gitignore1
-rw-r--r--src/Makefile.am12
-rw-r--r--src/cmdline.opt28
-rw-r--r--src/dscrtags-cl.opt30
-rw-r--r--src/dscrtags.c (renamed from src/descrtags.c)7
-rw-r--r--src/eclat.c130
-rw-r--r--src/eclat.h9
-rw-r--r--src/startinst-cl.opt33
-rw-r--r--src/startinst.c17
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);
}

Return to:

Send suggestions and report system problems to the System administrator.