Libecoli 0.11.5
Extensible COmmand LIne library
Loading...
Searching...
No Matches
parse-yaml.c
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2018, Olivier MATZ <zer0@droids-corp.org>
3 */
4
28
29#include <errno.h>
30#include <getopt.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35#include <ecoli.h>
36
37static char *input_file;
38static char *output_file;
39static bool complete;
40
41/* clang-format off */
42static const char short_options[] =
43 "h" /* help */
44 "i:" /* input-file */
45 "o:" /* output-file */
46 "c" /* complete */
47 ;
48/* clang-format on */
49
50#define OPT_HELP "help"
51#define OPT_INPUT_FILE "input-file"
52#define OPT_OUTPUT_FILE "output-file"
53#define OPT_COMPLETE "complete"
54
55static const struct option long_options[] = {
56 {OPT_HELP, 0, NULL, 'h'},
57 {OPT_INPUT_FILE, 1, NULL, 'i'},
58 {OPT_OUTPUT_FILE, 1, NULL, 'o'},
59 {OPT_COMPLETE, 0, NULL, 'c'},
60 {NULL, 0, NULL, 0}
61};
62
63static void usage(const char *prgname)
64{
65 fprintf(stderr,
66 "%s -o <file.sh> -i <file.yaml>\n"
67 " -h\n"
68 " --" OPT_HELP "\n"
69 " Show this help.\n"
70 " -i <input-file>\n"
71 " --" OPT_INPUT_FILE "=<file>\n"
72 " Set the yaml input file describing the grammar.\n"
73 " -o <output-file>\n"
74 " --" OPT_OUTPUT_FILE "=<file>\n"
75 " Set the output file.\n"
76 " -c\n"
77 " --" OPT_COMPLETE "\n"
78 " Output the completion list.\n",
79 prgname);
80}
81
82static int parse_args(int argc, char **argv)
83{
84 int ret, opt;
85
86 while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != EOF) {
87 switch (opt) {
88 case 'h': /* help */
89 usage(argv[0]);
90 exit(0);
91
92 case 'i': /* input-file */
93 input_file = strdup(optarg);
94 break;
95
96 case 'o': /* output-file */
97 output_file = strdup(optarg);
98 break;
99
100 case 'c': /* complete */
101 complete = 1;
102 break;
103
104 default:
105 usage(argv[0]);
106 return -1;
107 }
108 }
109
110 if (input_file == NULL) {
111 fprintf(stderr, "No input file\n");
112 usage(argv[0]);
113 return -1;
114 }
115 if (output_file == NULL) {
116 fprintf(stderr, "No output file\n");
117 usage(argv[0]);
118 return -1;
119 }
120
121 ret = optind - 1;
122 optind = 1;
123
124 return ret;
125}
126
127static int __dump_as_shell(FILE *f, const struct ec_pnode *parse, size_t *seq)
128{
129 const struct ec_node *node = ec_pnode_get_node(parse);
130 struct ec_pnode *child;
131 size_t cur_seq, i, len;
132 char *quoted;
133
134 (*seq)++;
135 cur_seq = *seq;
136
137 quoted = ec_str_quote(ec_node_id(node), '\'', true);
138 fprintf(f, "ec_node%zu_id=%s\n", cur_seq, quoted);
139 free(quoted);
140
141 quoted = ec_str_quote(ec_node_type_name(ec_node_type(node)), '\'', true);
142 fprintf(f, "ec_node%zu_type=%s\n", cur_seq, quoted);
143 free(quoted);
144
146 fprintf(f, "ec_node%zu_strvec_len=%zu\n", cur_seq, len);
147 for (i = 0; i < len; i++) {
148 quoted = ec_str_quote(ec_strvec_val(ec_pnode_get_strvec(parse), i), '\'', true);
149 fprintf(f, "ec_node%zu_str%zu=%s\n", cur_seq, i, quoted);
150 free(quoted);
151 }
152
153 if (ec_pnode_get_first_child(parse) != NULL) {
154 fprintf(f, "ec_node%zu_first_child='ec_node%zu'\n", cur_seq, cur_seq + 1);
155 }
156
157 EC_PNODE_FOREACH_CHILD (child, parse) {
158 fprintf(f, "ec_node%zu_parent='ec_node%zu'\n", *seq + 1, cur_seq);
159 __dump_as_shell(f, child, seq);
160 }
161
162 if (ec_pnode_next(parse) != NULL) {
163 fprintf(f, "ec_node%zu_next='ec_node%zu'\n", cur_seq, *seq + 1);
164 }
165
166 return 0;
167}
168
169static int dump_as_shell(const struct ec_pnode *parse)
170{
171 FILE *f;
172 size_t seq = 0;
173 int ret;
174
175 f = fopen(output_file, "w");
176 if (f == NULL)
177 return -1;
178
179 ret = __dump_as_shell(f, parse, &seq);
180
181 fclose(f);
182
183 return ret;
184}
185
186static int interact(struct ec_node *node)
187{
188 struct ec_editline *editline = NULL;
189 struct ec_pnode *parse = NULL;
190 struct ec_node *shlex = NULL;
191
192 shlex = ec_node_sh_lex(EC_NO_ID, ec_node_clone(node));
193 if (shlex == NULL) {
194 fprintf(stderr, "Failed to add lexer node\n");
195 goto fail;
196 }
197
198 editline = ec_editline("parse-yaml", stdin, stdout, stderr, 0);
199 if (editline == NULL) {
200 fprintf(stderr, "Failed to initialize editline\n");
201 goto fail;
202 }
203
204 if (ec_editline_set_node(editline, shlex) < 0) {
205 fprintf(stderr, "Failed to set editline ec_node\n");
206 goto fail;
207 }
208
209 parse = ec_editline_parse(editline);
210 if (parse == NULL)
211 goto fail;
212
213 if (!ec_pnode_matches(parse))
214 goto fail;
215
216 if (dump_as_shell(parse) < 0) {
217 fprintf(stderr, "Failed to dump the parsed result\n");
218 goto fail;
219 }
220
221 ec_pnode_free(parse);
222 ec_editline_free(editline);
223 ec_node_free(shlex);
224 return 0;
225
226fail:
227 ec_pnode_free(parse);
228 ec_editline_free(editline);
229 ec_node_free(shlex);
230 return -1;
231}
232
233static int complete_words(const struct ec_node *node, int argc, char *argv[])
234{
235 struct ec_comp *comp = NULL;
236 struct ec_strvec *strvec = NULL;
237 struct ec_comp_item *item = NULL;
238 size_t count;
239
240 if (argc <= 1)
241 goto fail;
242 strvec = ec_strvec_from_array((const char *const *)&argv[1], argc - 1);
243 if (strvec == NULL)
244 goto fail;
245
246 comp = ec_complete_strvec(node, strvec);
247 if (comp == NULL)
248 goto fail;
249
251
253 /* only one match, display it fully */
254 if (count == 1) {
255 printf("%s\n", ec_comp_item_get_str(item));
256 break;
257 }
258
259 /* else show the 'display' part only */
260 printf("%s\n", ec_comp_item_get_display(item));
261 }
262
263 ec_comp_free(comp);
264 ec_strvec_free(strvec);
265 return 0;
266
267fail:
268 ec_comp_free(comp);
269 ec_strvec_free(strvec);
270 return -1;
271}
272
273int main(int argc, char *argv[])
274{
275 struct ec_node *node = NULL;
276 int ret;
277
278 ret = parse_args(argc, argv);
279 if (ret < 0)
280 goto fail;
281
282 argc -= ret;
283 argv += ret;
284
285 if (ec_init() < 0) {
286 fprintf(stderr, "cannot init ecoli: %s\n", strerror(errno));
287 return 1;
288 }
289
290 node = ec_yaml_import(input_file);
291 if (node == NULL) {
292 fprintf(stderr, "Failed to parse file\n");
293 goto fail;
294 }
295
296 if (complete) {
297 if (complete_words(node, argc, argv) < 0)
298 goto fail;
299 } else {
300 if (interact(node) < 0)
301 goto fail;
302 }
303
304 ec_node_free(node);
305
306 return 0;
307
308fail:
309 ec_node_free(node);
310 return 1;
311}
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)
Definition complete.h:522
@ EC_COMP_FULL
Definition complete.h:49
@ EC_COMP_PARTIAL
Definition complete.h:50
@ EC_COMP_UNKNOWN
Definition complete.h:48
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)
int ec_init(void)
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)
#define EC_NO_ID
Definition node.h:64
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)
Definition parse.h:286
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)