diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-25 17:31:24 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-25 17:45:23 +0300 |
commit | 455e12faaf5efd997ff74ad04c0fcc62608477a5 (patch) | |
tree | 46d24aba487fb2ea76078ef4da60357ff0a340e4 | |
parent | 2f5d961c798802f1e467de1cd310f661e0a45fa7 (diff) | |
download | eclat-455e12faaf5efd997ff74ad04c0fcc62608477a5.tar.gz eclat-455e12faaf5efd997ff74ad04c0fcc62608477a5.tar.bz2 |
Use forlan to format the output.
* lib/forlan.h (forlan_lex_begin): Remove
(forlan_lex_from_buffer)
(forlan_lex_from_file): New protos.
(forlan_parse): Remove.
(forlan_parse_bufferm,forlan_parse_file): New protos.
* lib/forlangrm.y (forlan_parse): Remove.
(forlan_parse_bufferm,forlan_parse_file): New functions.
* lib/forlanlex.l (YY_INPUT): Optionally, read input from file.
(forlan_lex_begin): Remove
(forlan_lex_from_buffer)
(forlan_lex_from_file): New functions.
* src/cmdline.opt: New options: --format, --sort
* src/config.c: New statement: format.
* src/eclat.c: Use output format scripts, if provided.
* src/eclat.conf: Define output format for DescribeTags.
* src/eclat.h: Include forlan.h
(define_format): New proto.
* tests/tforlan.c: New option: -s
-rw-r--r-- | lib/forlan.h | 11 | ||||
-rw-r--r-- | lib/forlangrm.y | 24 | ||||
-rw-r--r-- | lib/forlanlex.l | 34 | ||||
-rw-r--r-- | src/cmdline.opt | 12 | ||||
-rw-r--r-- | src/config.c | 32 | ||||
-rw-r--r-- | src/eclat.c | 123 | ||||
-rw-r--r-- | src/eclat.conf | 17 | ||||
-rw-r--r-- | src/eclat.h | 3 | ||||
-rw-r--r-- | tests/tforlan.c | 49 |
9 files changed, 264 insertions, 41 deletions
diff --git a/lib/forlan.h b/lib/forlan.h index b789d7e..300ef57 100644 --- a/lib/forlan.h +++ b/lib/forlan.h @@ -23,11 +23,14 @@ typedef struct forlan_eval_env *forlan_eval_env_t; extern int forlan_dbg; void forlan_init(); -void forlan_lex_begin(const char *input, size_t length, - struct grecs_locus_point *pt); +void forlan_lex_from_buffer(const char *input, size_t length, + struct grecs_locus_point *pt); +void forlan_lex_from_file(FILE *fp, struct grecs_locus_point *pt); + void forlan_lex_end(void); -forlan_eval_env_t forlan_parse(const char *input, size_t length, - struct grecs_locus_point *pt); +forlan_eval_env_t forlan_parse_buffer(const char *input, size_t length, + struct grecs_locus_point *pt); +forlan_eval_env_t forlan_parse_file(FILE *fp, struct grecs_locus_point *pt); union forlan_node; /* Declared below */ diff --git a/lib/forlangrm.y b/lib/forlangrm.y index e8e3436..6261c5e 100644 --- a/lib/forlangrm.y +++ b/lib/forlangrm.y @@ -385,12 +385,32 @@ forlan_parser() } forlan_eval_env_t -forlan_parse(const char *input, size_t length, struct grecs_locus_point *pt) +forlan_parse_buffer(const char *input, size_t length, + struct grecs_locus_point *pt) { int rc; forlan_eval_env_t env = NULL; - forlan_lex_begin(input, length, pt); + forlan_lex_from_buffer(input, length, pt); + rc = forlan_parser(); + forlan_lex_end(); + grecs_symtab_free(forlan_symtab); + forlan_symtab = NULL; + + if (rc == 0) + env = forlan_create_environment(forlan_parse_tree, + forlan_variable_count); + + return env; +} + +forlan_eval_env_t +forlan_parse_file(FILE *fp, struct grecs_locus_point *pt) +{ + int rc; + forlan_eval_env_t env = NULL; + + forlan_lex_from_file(fp, pt); rc = forlan_parser(); forlan_lex_end(); grecs_symtab_free(forlan_symtab); diff --git a/lib/forlanlex.l b/lib/forlanlex.l index e3f9f26..c3797dd 100644 --- a/lib/forlanlex.l +++ b/lib/forlanlex.l @@ -16,6 +16,7 @@ along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ #include "libeclat.h" +#include <sysexits.h> #include <grecs.h> #include <grecs-locus.h> #include "forlangrm.h" @@ -28,14 +29,17 @@ static size_t forlan_input_pos; #undef YY_INPUT #define YY_INPUT(buf,result,max_size) \ do { \ - size_t __s = forlan_input_len - forlan_input_pos; \ - if (__s > max_size) \ - __s = max_size; \ - if (__s > 0) { \ - memcpy(buf, forlan_input_base, __s); \ - forlan_input_pos += __s; \ - } \ - result = __s; \ + if (forlan_input_base) { \ + size_t __s = forlan_input_len - forlan_input_pos; \ + if (__s > max_size) \ + __s = max_size; \ + if (__s > 0) { \ + memcpy(buf, forlan_input_base, __s); \ + forlan_input_pos += __s; \ + } \ + result = __s; \ + } else \ + result = fread(buf, 1, max_size, yyin); \ } while(0) #define YY_USER_ACTION do { \ @@ -120,8 +124,8 @@ yywrap() } void -forlan_lex_begin(const char *input, size_t length, - struct grecs_locus_point *pt) +forlan_lex_from_buffer(const char *input, size_t length, + struct grecs_locus_point *pt) { forlan_input_base = input; forlan_input_len = length; @@ -131,6 +135,16 @@ forlan_lex_begin(const char *input, size_t length, } void +forlan_lex_from_file(FILE *fp, struct grecs_locus_point *pt) +{ + yyin = fp; + forlan_input_base = NULL; + grecs_current_locus_point = *pt; + yy_flex_debug = debug_level(forlan_dbg) >= FORLAN_DBG_LEX; + grecs_line_acc_create(); +} + +void forlan_lex_end() { grecs_line_acc_free(); diff --git a/src/cmdline.opt b/src/cmdline.opt index 1f8d56d..a17f2b8 100644 --- a/src/cmdline.opt +++ b/src/cmdline.opt @@ -127,6 +127,18 @@ BEGIN use_ssl = 1; END +OPTION(format,F,FILE, + [<use FILE to format the output>]) +BEGIN + format_file = optarg; +END + +OPTION(sort,s,, + [<sort the returned XML teee prior to outputting it>]) +BEGIN + sort_option = 1; +END + GROUP(Preprocessor control) OPTION(include-directory,I,DIR, diff --git a/src/config.c b/src/config.c index b718486..82033d3 100644 --- a/src/config.c +++ b/src/config.c @@ -96,6 +96,34 @@ cb_region(enum grecs_callback_command cmd, return 0; } +static int +cb_format(enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, + void *cb_data) +{ + struct ec2_param *p, key; + int install = 1; + + if (cmd != grecs_callback_set_value) { + grecs_error(locus, 0, "Unexpected block statement"); + return 1; + } + if (!value || value->type != GRECS_TYPE_ARRAY || value->v.arg.c != 2) { + grecs_error(locus, 0, "expected two strings"); + return 1; + } + if (value->v.arg.v[0]->type != GRECS_TYPE_STRING || + value->v.arg.v[1]->type != GRECS_TYPE_STRING) { + grecs_error(locus, 0, "expected two strings"); + return 1; + } + define_format(value->v.arg.v[0]->v.string, + value->v.arg.v[1]->v.string, + &value->v.arg.v[1]->locus); +} + static struct grecs_keyword eclat_kw[] = { { "default-endpoint", "hostname", "Set default EC2 endpoint", @@ -109,7 +137,9 @@ static struct grecs_keyword eclat_kw[] = { { "default-region", "name", "Define default AWS region", grecs_type_string, GRECS_DFLT, ®ion_name }, - + { "format", "<command: string> <format: string>", + "Set default format for the <command>", + grecs_type_string, GRECS_MULT, NULL, 0, cb_format }, { NULL } }; diff --git a/src/eclat.c b/src/eclat.c index 86b4627..a26ef7d 100644 --- a/src/eclat.c +++ b/src/eclat.c @@ -26,6 +26,8 @@ int use_ssl; char *access_key; char *secret_key; char *region_name; +char *format_file; +int sort_option; enum eclat_command eclat_command; @@ -179,15 +181,105 @@ write_callback(void *ptr, size_t size, size_t nmemb, void *data) return realsize; } +static int +node_ident_cmp(struct grecs_node const *a, struct grecs_node const *b) +{ + return strcmp(a->ident, b->ident); +} + #include "cmdline.h" -eclat_command_handler_t handler_tab[] = { - NULL, - eclat_start_instance, - eclat_stop_instance, - eclat_describe_tags +struct command { + const char *name; + 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 * +find_command(const char *name) +{ + struct command *cp; + + for (cp = command_tab + 1; + cp < command_tab + sizeof(command_tab)/sizeof(command_tab[0]); + cp++) { + if (strcmp(cp->name, name) == 0) + return cp; + } + return NULL; +} + +void +define_format(const char *name, const char *format, grecs_locus_t *locus) +{ + struct command *cp = find_command(name); + + if (!cp) { + grecs_error(locus, 0, "unknown command"); + return; + } + + if (cp->fmt) { + grecs_error(locus, 0, "format %s redefined", name); + grecs_error(&cp->locus, 0, "this is the location of " + "the previous definition"); + free(cp->fmt); + } + + cp->fmt = grecs_strdup(format); + cp->locus = *locus; +} +forlan_eval_env_t +compile_format_file(const char *fmtfile) +{ + forlan_eval_env_t env; + FILE *fp; + struct grecs_locus_point pt; + + fp = fopen(fmtfile, "r"); + if (!fp) + die(EX_UNAVAILABLE, "cannot open format file \"%s\": %s", + fmtfile, strerror(errno)); + + pt.file = fmtfile; + pt.line = 1; + pt.col = 0; + + env = forlan_parse_file(fp, &pt); + fclose(fp); + if (!env) + exit(EX_UNAVAILABLE); + + return env; +} + +forlan_eval_env_t +compile_default_format() +{ + 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); + if (!env) + exit(EX_UNAVAILABLE); + + return env; +} + + + int main(int argc, char **argv) { @@ -197,9 +289,11 @@ main(int argc, char **argv) XML_Parser parser; eclat_partial_tree_t part; struct grecs_node *xmltree; + forlan_eval_env_t env = NULL; set_program_name(argv[0]); debug_init(); + forlan_init(); config_init(); parse_options(argc, argv, &index); @@ -230,6 +324,12 @@ main(int argc, char **argv) } else die(EX_OSFILE, "cannot access \"%s\": %s", conffile, strerror(errno)); + + if (format_file) + env = compile_format_file(format_file); + else + env = compile_default_format(); + if (lint_mode) exit(0); @@ -261,7 +361,6 @@ main(int argc, char **argv) curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, eclat_trace_fun); } - /* Create XML parser */ parser = XML_ParserCreate("UTF-8"); @@ -279,15 +378,21 @@ main(int argc, char **argv) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, parser); - rc = handler_tab[eclat_command](curl, argc, argv); + rc = command_tab[eclat_command].handler(curl, argc, argv); curl_easy_cleanup(curl); XML_Parse(parser, "", 0, 1); xmltree = eclat_partial_tree_finish(part); - grecs_print_node(xmltree, GRECS_NODE_FLAG_DEFAULT, stdout); - fputc('\n', stdout); + if (sort_option) + grecs_tree_sort(xmltree, node_ident_cmp); + if (env) { + forlan_run(env, xmltree); + } else { + grecs_print_node(xmltree, GRECS_NODE_FLAG_DEFAULT, stdout); + fputc('\n', stdout); + } exit(rc); } diff --git a/src/eclat.conf b/src/eclat.conf index 1562d52..ef212e7 100644 --- a/src/eclat.conf +++ b/src/eclat.conf @@ -25,3 +25,20 @@ region ap-southeast-1 ec2.ap-southeast-1.amazonaws.com; region ap-northeast-1 ec2.ap-northeast-1.amazonaws.com; # South America (Sao Paulo) Region region sa-east-1 ec2.sa-east-1.amazonaws.com; + +format "DescribeTags" <<\EOT +if (.DescribeTagsResponse) { + for (var in .DescribeTagsResponse.tagSet.item) { + print(var.resourceId,"\t", + var.resourceType,"\t", + var.key,"\t", + var.value,"\n"); + } +} else if (.Response.Errors) + error("Error: ",.Response.Errors.Error.Message,"\n"); +else { + error("Unrecognized response:\n"); + dump(.); +} +EOT; + diff --git a/src/eclat.h b/src/eclat.h index e588b57..9b909c4 100644 --- a/src/eclat.h +++ b/src/eclat.h @@ -27,6 +27,7 @@ #include "grecs.h" #include "wordsplit.h" #include "libeclat.h" +#include "forlan.h" #define ECLAT_DEBCAT_MAIN 0 #define ECLAT_DEBCAT_CFGRAM 1 @@ -68,3 +69,5 @@ int eclat_stop_instance(CURL *curl, int argc, char **argv); int eclat_describe_tags(CURL *curl, int argc, char **argv); char *region_to_endpoint(const char *region); + +void define_format(const char *name, const char *format, grecs_locus_t *locus); diff --git a/tests/tforlan.c b/tests/tforlan.c index 8969c6d..403438e 100644 --- a/tests/tforlan.c +++ b/tests/tforlan.c @@ -31,7 +31,13 @@ void usage() { - printf("usage: %s [-dD] FILE [INPUT]\n"); + printf("usage: %s [OPTIONS] FILE [INPUT]\n", program_name); + printf("OPTIONS are:\n"); + printf(" -D dump parse tree\n"); + printf(" -d LEVEL set debug level\n"); + printf(" -f use file interface\n"); + printf(" -s sort XML tree\n"); + printf(" -h produce this help list\n"); } struct grecs_node * @@ -75,6 +81,10 @@ node_ident_cmp(struct grecs_node const *a, struct grecs_node const *b) return strcmp(a->ident, b->ident); } +#define OPT_DUMP 0x01 +#define OPT_SORT 0x02 +#define OPT_FILE 0x04 + int main(int argc, char **argv) { @@ -84,17 +94,16 @@ main(int argc, char **argv) struct stat st; struct grecs_locus_point pt; int rc; - int dump_option = 0; - int sort_option = 0; + int options = 0; forlan_eval_env_t env; set_program_name(argv[0]); forlan_init(); - while ((rc = getopt(argc, argv, "Dd:hs")) != EOF) + while ((rc = getopt(argc, argv, "Dd:fhs")) != EOF) switch (rc) { case 'D': - dump_option++; + options |= OPT_DUMP; break; case 'd': @@ -102,12 +111,16 @@ main(int argc, char **argv) die(EX_USAGE, "bad debug category or level"); break; + case 'f': + options |= OPT_FILE; + break; + case 'h': usage(); return 0; case 's': - sort_option = 1; + options |= OPT_SORT; break; default: @@ -122,25 +135,31 @@ main(int argc, char **argv) if (stat(argv[0], &st)) die(EX_UNAVAILABLE, "cannot stat input file \"%s\": %s", argv[0], strerror(errno)); - len = st.st_size; - buf = grecs_malloc(len); + fp = fopen(argv[0], "r"); if (!fp) die(EX_UNAVAILABLE, "cannot open input file \"%s\": %s", argv[0], strerror(errno)); - if (fread(buf, len, 1, fp) != 1) - die(EX_UNAVAILABLE, "error reading from \"%s\": %s", - argv[0], strerror(errno)); - fclose(fp); pt.file = argv[0]; pt.line = 1; pt.col = 0; - env = forlan_parse(buf, len, &pt); + if (options & OPT_FILE) { + env = forlan_parse_file(fp, &pt); + } else { + len = st.st_size; + buf = grecs_malloc(len); + if (fread(buf, len, 1, fp) != 1) + die(EX_UNAVAILABLE, "error reading from \"%s\": %s", + argv[0], strerror(errno)); + env = forlan_parse_buffer(buf, len, &pt); + } + fclose(fp); + if (!env) return EX_UNAVAILABLE; - if (dump_option) + if (options & OPT_DUMP) forlan_dump_tree(stdout, env); if (argv[1]) { @@ -154,7 +173,7 @@ main(int argc, char **argv) tree = parse_xml(fp); fclose(fp); - if (sort_option) + if (options & OPT_SORT) grecs_tree_sort(tree, node_ident_cmp); forlan_run(env, tree); |