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