Load grammar from YAML and parse or complete input.
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ecoli.h>
static char *input_file;
static char *output_file;
static bool complete;
static const char short_options[] = "h"
"i:"
"o:"
"c"
;
#define OPT_HELP "help"
#define OPT_INPUT_FILE "input-file"
#define OPT_OUTPUT_FILE "output-file"
#define OPT_COMPLETE "complete"
static const struct option long_options[] = {
{OPT_HELP, 0, NULL, 'h'},
{OPT_INPUT_FILE, 1, NULL, 'i'},
{OPT_OUTPUT_FILE, 1, NULL, 'o'},
{OPT_COMPLETE, 0, NULL, 'c'},
{NULL, 0, NULL, 0}
};
static void usage(const char *prgname)
{
fprintf(stderr,
"%s -o <file.sh> -i <file.yaml>\n"
" -h\n"
" --" OPT_HELP "\n"
" Show this help.\n"
" -i <input-file>\n"
" --" OPT_INPUT_FILE "=<file>\n"
" Set the yaml input file describing the grammar.\n"
" -o <output-file>\n"
" --" OPT_OUTPUT_FILE "=<file>\n"
" Set the output file.\n"
" -c\n"
" --" OPT_COMPLETE "\n"
" Output the completion list.\n",
prgname);
}
static int parse_args(int argc, char **argv)
{
int ret, opt;
while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != EOF) {
switch (opt) {
case 'h':
usage(argv[0]);
exit(0);
case 'i':
input_file = strdup(optarg);
break;
case 'o':
output_file = strdup(optarg);
break;
case 'c':
complete = 1;
break;
default:
usage(argv[0]);
return -1;
}
}
if (input_file == NULL) {
fprintf(stderr, "No input file\n");
usage(argv[0]);
return -1;
}
if (output_file == NULL) {
fprintf(stderr, "No output file\n");
usage(argv[0]);
return -1;
}
ret = optind - 1;
optind = 1;
return ret;
}
static int __dump_as_shell(FILE *f,
const struct ec_pnode *parse,
size_t *seq)
{
size_t cur_seq, i, len;
char *quoted;
(*seq)++;
cur_seq = *seq;
fprintf(f, "ec_node%zu_id=%s\n", cur_seq, quoted);
free(quoted);
fprintf(f, "ec_node%zu_type=%s\n", cur_seq, quoted);
free(quoted);
fprintf(f, "ec_node%zu_strvec_len=%zu\n", cur_seq, len);
for (i = 0; i < len; i++) {
fprintf(f, "ec_node%zu_str%zu=%s\n", cur_seq, i, quoted);
free(quoted);
}
fprintf(f, "ec_node%zu_first_child='ec_node%zu'\n", cur_seq, cur_seq + 1);
}
fprintf(f, "ec_node%zu_parent='ec_node%zu'\n", *seq + 1, cur_seq);
__dump_as_shell(f, child, seq);
}
fprintf(f, "ec_node%zu_next='ec_node%zu'\n", cur_seq, *seq + 1);
}
return 0;
}
static int dump_as_shell(
const struct ec_pnode *parse)
{
FILE *f;
size_t seq = 0;
int ret;
f = fopen(output_file, "w");
if (f == NULL)
return -1;
ret = __dump_as_shell(f, parse, &seq);
fclose(f);
return ret;
}
static int interact(
struct ec_node *node)
{
if (shlex == NULL) {
fprintf(stderr, "Failed to add lexer node\n");
goto fail;
}
editline =
ec_editline(
"parse-yaml", stdin, stdout, stderr, 0);
if (editline == NULL) {
fprintf(stderr, "Failed to initialize editline\n");
goto fail;
}
fprintf(stderr, "Failed to set editline ec_node\n");
goto fail;
}
if (parse == NULL)
goto fail;
goto fail;
if (dump_as_shell(parse) < 0) {
fprintf(stderr, "Failed to dump the parsed result\n");
goto fail;
}
return 0;
fail:
return -1;
}
static int complete_words(
const struct ec_node *node,
int argc,
char *argv[])
{
struct ec_comp_item *item = NULL;
size_t count;
if (argc <= 1)
goto fail;
if (strvec == NULL)
goto fail;
if (comp == NULL)
goto fail;
if (count == 1) {
break;
}
}
return 0;
fail:
return -1;
}
int main(int argc, char *argv[])
{
int ret;
ret = parse_args(argc, argv);
if (ret < 0)
goto fail;
argc -= ret;
argv += ret;
fprintf(stderr, "cannot init ecoli: %s\n", strerror(errno));
return 1;
}
if (node == NULL) {
fprintf(stderr, "Failed to parse file\n");
goto fail;
}
if (complete) {
if (complete_words(node, argc, argv) < 0)
goto fail;
} else {
if (interact(node) < 0)
goto fail;
}
return 0;
fail:
return 1;
}
struct ec_comp * ec_comp(void)
const char * ec_comp_item_get_display(const struct ec_comp_item *item)
struct ec_comp * ec_complete_strvec(const struct ec_node *node, const struct ec_strvec *strvec)
size_t ec_comp_count(const struct ec_comp *comp, enum ec_comp_type type)
void ec_comp_free(struct ec_comp *comp)
const char * ec_comp_item_get_str(const struct ec_comp_item *item)
#define EC_COMP_FOREACH(item, comp, type)
struct ec_editline * ec_editline(const char *prog, FILE *f_in, FILE *f_out, FILE *f_err, enum ec_editline_init_flags flags)
void ec_editline_free(struct ec_editline *editline)
struct ec_pnode * ec_editline_parse(struct ec_editline *editline)
int ec_editline_set_node(struct ec_editline *editline, const struct ec_node *node)
struct ec_node * ec_node_sh_lex(const char *id, struct ec_node *child)
struct ec_node * ec_node_clone(struct ec_node *node)
const char * ec_node_id(const struct ec_node *node)
struct ec_node * ec_node(const char *typename, const char *id)
const struct ec_node_type * ec_node_type(const struct ec_node *node)
const char * ec_node_type_name(const struct ec_node_type *type)
void ec_node_free(struct ec_node *node)
bool ec_pnode_matches(const struct ec_pnode *pnode)
struct ec_pnode * ec_pnode_next(const struct ec_pnode *pnode)
void ec_pnode_free(struct ec_pnode *pnode)
const struct ec_strvec * ec_pnode_get_strvec(const struct ec_pnode *pnode)
#define EC_PNODE_FOREACH_CHILD(child, pnode)
struct ec_pnode * ec_pnode_get_first_child(const struct ec_pnode *pnode)
const struct ec_node * ec_pnode_get_node(const struct ec_pnode *pnode)
struct ec_pnode * ec_pnode(const struct ec_node *node)
char * ec_str_quote(const char *str, char quote, bool force)
struct ec_strvec * ec_strvec_from_array(const char *const *strarr, size_t n)
void ec_strvec_free(struct ec_strvec *strvec)
const char * ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
struct ec_strvec * ec_strvec(void)
size_t ec_strvec_len(const struct ec_strvec *strvec)
struct ec_node * ec_yaml_import(const char *filename)