1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2018, Olivier MATZ <zer0@droids-corp.org>
11 #include <ecoli_init.h>
12 #include <ecoli_strvec.h>
13 #include <ecoli_node.h>
14 #include <ecoli_parse.h>
15 #include <ecoli_complete.h>
16 #include <ecoli_yaml.h>
17 #include <ecoli_editline.h>
18 #include <ecoli_node_sh_lex.h>
20 static char *input_file;
21 static char *output_file;
24 static const char short_options[] =
27 "o:" /* output-file */
31 #define OPT_HELP "help"
32 #define OPT_INPUT_FILE "input-file"
33 #define OPT_OUTPUT_FILE "output-file"
34 #define OPT_COMPLETE "complete"
36 static const struct option long_options[] = {
37 {OPT_HELP, 0, NULL, 'h'},
38 {OPT_INPUT_FILE, 1, NULL, 'i'},
39 {OPT_OUTPUT_FILE, 1, NULL, 'o'},
40 {OPT_COMPLETE, 0, NULL, 'c'},
44 static void usage(const char *prgname)
46 fprintf(stderr, "%s -o <file.sh> -i <file.yaml>\n"
51 " --"OPT_INPUT_FILE"=<file>\n"
52 " Set the yaml input file describing the grammar.\n"
54 " --"OPT_OUTPUT_FILE"=<file>\n"
55 " Set the output file.\n"
58 " Output the completion list."
62 static int parse_args(int argc, char **argv)
66 while ((opt = getopt_long(argc, argv, short_options,
67 long_options, NULL)) != EOF) {
74 case 'i': /* input-file */
75 input_file = strdup(optarg);
78 case 'o': /* output-file */
79 output_file = strdup(optarg);
82 case 'c': /* complete */
93 if (input_file == NULL) {
94 fprintf(stderr, "No input file\n");
98 if (output_file == NULL) {
99 fprintf(stderr, "No output file\n");
111 __dump_as_shell(FILE *f, const struct ec_parse *parse, size_t *seq)
113 const struct ec_node *node = ec_parse_get_node(parse);
114 struct ec_parse *child;
115 size_t cur_seq, i, len;
121 // XXX protect strings
124 fprintf(f, "ec_node%zu_id='%s'\n", cur_seq, ec_node_id(node));
125 fprintf(f, "ec_node%zu_type='%s'\n", cur_seq,
126 ec_node_type_name(ec_node_type(node)));
128 len = ec_strvec_len(ec_parse_strvec(parse));
129 fprintf(f, "ec_node%zu_strvec_len=%zu\n", cur_seq, len);
130 for (i = 0; i < len; i++) {
131 s = ec_strvec_val(ec_parse_strvec(parse), i);
132 fprintf(f, "ec_node%zu_str%zu='%s'\n", cur_seq, i, s);
135 if (ec_parse_get_first_child(parse) != NULL) {
136 fprintf(f, "ec_node%zu_first_child='ec_node%zu'\n",
137 cur_seq, cur_seq + 1);
140 EC_PARSE_FOREACH_CHILD(child, parse) {
141 fprintf(f, "ec_node%zu_parent='ec_node%zu'\n",
143 __dump_as_shell(f, child, seq);
146 if (ec_parse_next(parse) != NULL) {
147 fprintf(f, "ec_node%zu_next='ec_node%zu'\n",
155 dump_as_shell(const struct ec_parse *parse)
161 f = fopen(output_file, "w");
165 ret = __dump_as_shell(f, parse, &seq);
173 interact(struct ec_node *node)
175 struct ec_editline *editline = NULL;
176 struct ec_parse *parse = NULL;
177 struct ec_node *shlex = NULL;
180 shlex = ec_node_sh_lex(EC_NO_ID, ec_node_clone(node)); //XXX
182 fprintf(stderr, "Failed to add lexer node\n");
186 editline = ec_editline("ecoli", stdin, stdout, stderr, 0);
187 if (editline == NULL) {
188 fprintf(stderr, "Failed to initialize editline\n");
192 parse = ec_editline_parse(editline, shlex);
196 if (!ec_parse_matches(parse))
199 //ec_parse_dump(stdout, parse);
201 if (dump_as_shell(parse) < 0) {
202 fprintf(stderr, "Failed to dump the parsed result\n");
206 ec_parse_free(parse);
207 ec_editline_free(editline);
212 ec_parse_free(parse);
213 ec_editline_free(editline);
220 complete_words(const struct ec_node *node, int argc, char *argv[])
222 struct ec_comp *comp = NULL;
223 struct ec_strvec *strvec = NULL;
224 struct ec_comp_iter *iter = NULL;
225 struct ec_comp_item *item = NULL;
230 strvec = ec_strvec_from_array((const char * const *)&argv[1],
235 comp = ec_node_complete_strvec(node, strvec);
239 count = ec_comp_count(comp, EC_COMP_UNKNOWN | EC_COMP_FULL |
242 iter = ec_comp_iter(comp,
243 EC_COMP_UNKNOWN | EC_COMP_FULL | EC_COMP_PARTIAL);
247 while ((item = ec_comp_iter_next(iter)) != NULL) {
249 /* only one match, display it fully */
251 printf("%s\n", ec_comp_item_get_str(item));
255 /* else show the 'display' part only */
256 printf("%s\n", ec_comp_item_get_display(item));
259 ec_comp_iter_free(iter);
261 ec_strvec_free(strvec);
266 ec_strvec_free(strvec);
271 main(int argc, char *argv[])
273 struct ec_node *node = NULL;
276 ret = parse_args(argc, argv);
284 fprintf(stderr, "cannot init ecoli: %s\n", strerror(errno));
288 node = ec_yaml_import(input_file);
290 fprintf(stderr, "Failed to parse file\n");
293 //ec_node_dump(stdout, node);
296 if (complete_words(node, argc, argv) < 0)
299 if (interact(node) < 0)