260502c1f305948f0adbd9982939adc5c511ad4b
[libcmdline.git] / src / genconf / commands.c
1 /*
2  * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <math.h>
29 #include <stdio.h>
30 #include <inttypes.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <sys/queue.h>
38
39 #include <cmdline_parse.h>
40 #include <cmdline_parse_ipaddr.h>
41 #include <cmdline_parse_num.h>
42 #include <cmdline_parse_string.h>
43 #include <cmdline_rdline.h>
44 #include <cmdline.h>
45
46 #include "parse_confnode.h"
47 #include "expression.h"
48 #include "conf_parser.h"
49 #include "confnode.h"
50 #include "conf_htable.h"
51 #include "dotconfig.h"
52
53 extern struct confnode *conf_cur;
54 extern struct confnode *conf_root;
55
56 /**********************************************************/
57 /* ls */
58 /**********************************************************/
59
60 struct cmd_ls_result {
61         cmdline_fixed_string_t ls;
62 };
63
64 static void do_ls(const struct confnode *n)
65 {
66         const struct confnode *c;
67
68         TAILQ_FOREACH(c, &n->children, next) {
69                 if (c->flags & CONFNODE_F_INVISIBLE)
70                         do_ls(c);
71                 else
72                         confnode_display_short(c);
73         }
74 }
75
76 static void cmd_ls_parsed(void *parsed_result,
77                           struct cmdline *cl,
78                           void *data)
79 {
80         do_ls(conf_cur);
81 }
82
83 cmdline_parse_token_string_t cmd_ls_ls =
84         TOKEN_STRING_INITIALIZER(struct cmd_ls_result, ls, "ls");
85
86 cmdline_parse_inst_t cmd_ls = {
87         .f = cmd_ls_parsed,  /* function to call */
88         .data = NULL,      /* 2nd arg of func */
89         .help_str = "<ls> list all config options in current directory",
90         .tokens = {        /* token list, NULL terminated */
91                 (void *)&cmd_ls_ls,
92                 NULL,
93         },
94 };
95
96 /**********************************************************/
97 /* ls node */
98 /**********************************************************/
99
100 struct cmd_ls_node_result {
101         cmdline_fixed_string_t ls;
102         struct confnode *node;
103 };
104
105 static void cmd_ls_node_parsed(void *parsed_result,
106                                 struct cmdline *cl,
107                                 void *data)
108 {
109         struct cmd_ls_node_result *res = parsed_result;
110         struct confnode *n = res->node;
111
112         while (n) {
113                 confnode_display_short(n);
114                 n = TAILQ_NEXT(n, user_next);
115         }
116 }
117
118 cmdline_parse_token_string_t cmd_ls_node_ls =
119         TOKEN_STRING_INITIALIZER(struct cmd_ls_node_result, ls, "ls");
120 parse_token_conf_node_t cmd_ls_node_node =
121         TOKEN_CONF_NODE_INITIALIZER(struct cmd_ls_node_result, node,
122                                     &conf_root, &conf_cur, 0, CONFNODE_F_INVISIBLE);
123
124 cmdline_parse_inst_t cmd_ls_node = {
125         .f = cmd_ls_node_parsed,  /* function to call */
126         .data = NULL,      /* 2nd arg of func */
127         .help_str = "<ls NODE> list config node(s) given in argument",
128         .tokens = {        /* token list, NULL terminated */
129                 (void *)&cmd_ls_node_ls,
130                 (void *)&cmd_ls_node_node,
131                 NULL,
132         },
133 };
134
135 /**********************************************************/
136 /* pwd */
137 /**********************************************************/
138
139 struct cmd_pwd_result {
140         cmdline_fixed_string_t pwd;
141 };
142
143 static void cmd_pwd_parsed(void *parsed_result,
144                                 struct cmdline *cl,
145                                 void *data)
146 {
147         conf_display_path(conf_cur);
148 }
149
150 cmdline_parse_token_string_t cmd_pwd_pwd =
151         TOKEN_STRING_INITIALIZER(struct cmd_pwd_result, pwd, "pwd");
152
153 cmdline_parse_inst_t cmd_pwd = {
154         .f = cmd_pwd_parsed,  /* function to call */
155         .data = NULL,      /* 2nd arg of func */
156         .help_str = "<pwd> display current directory",
157         .tokens = {        /* token list, NULL terminated */
158                 (void *)&cmd_pwd_pwd,
159                 NULL,
160         },
161 };
162
163 /**********************************************************/
164 /* cd prev */
165 /**********************************************************/
166
167 struct cmd_cd_prev_result {
168         cmdline_fixed_string_t cd;
169         cmdline_fixed_string_t prev;
170 };
171
172 static void cmd_cd_prev_parsed(void *parsed_result,
173                                struct cmdline *cl,
174                                void *data)
175 {
176         struct confnode *parent = conf_cur->parent;
177         char prompt[RDLINE_PROMPT_SIZE];
178
179         if (parent == NULL) {
180                 printf("already at top level\n");
181                 return;
182         }
183         while ((parent->flags & CONFNODE_F_INVISIBLE) && parent->parent != NULL)
184                 parent = parent->parent;
185
186         conf_cur = parent;
187         snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
188         cmdline_set_prompt(cl, prompt);
189 }
190
191 cmdline_parse_token_string_t cmd_cd_prev_cd =
192         TOKEN_STRING_INITIALIZER(struct cmd_cd_prev_result, cd, "cd");
193 cmdline_parse_token_string_t cmd_cd_prev_prev =
194         TOKEN_STRING_INITIALIZER(struct cmd_cd_prev_result, prev, "..");
195
196 cmdline_parse_inst_t cmd_cd_prev = {
197         .f = cmd_cd_prev_parsed,  /* function to call */
198         .data = NULL,      /* 2nd arg of func */
199         .help_str = "<cd ..> go up in configuration tree",
200         .tokens = {        /* token list, NULL terminated */
201                 (void *)&cmd_cd_prev_cd,
202                 (void *)&cmd_cd_prev_prev,
203                 NULL,
204         },
205 };
206
207 /**********************************************************/
208 /* cd root */
209 /**********************************************************/
210
211 struct cmd_cd_root_result {
212         cmdline_fixed_string_t cd;
213         cmdline_fixed_string_t root;
214 };
215
216 static void cmd_cd_root_parsed(void *parsed_result,
217                                struct cmdline *cl,
218                                void *data)
219 {
220         char prompt[RDLINE_PROMPT_SIZE];
221
222         conf_cur = conf_root;
223         snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
224         cmdline_set_prompt(cl, prompt);
225 }
226
227 cmdline_parse_token_string_t cmd_cd_root_cd =
228         TOKEN_STRING_INITIALIZER(struct cmd_cd_root_result, cd, "cd");
229 cmdline_parse_token_string_t cmd_cd_root_root =
230         TOKEN_STRING_INITIALIZER(struct cmd_cd_root_result, root, "/");
231
232 cmdline_parse_inst_t cmd_cd_root = {
233         .f = cmd_cd_root_parsed,  /* function to call */
234         .data = NULL,      /* 2nd arg of func */
235         .help_str = "<cd /> go to root of configuration",
236         .tokens = {        /* token list, NULL terminated */
237                 (void *)&cmd_cd_root_cd,
238                 (void *)&cmd_cd_root_root,
239                 NULL,
240         },
241 };
242
243 /**********************************************************/
244 /* cd node */
245 /**********************************************************/
246
247 struct cmd_cd_node_result {
248         cmdline_fixed_string_t cd;
249         struct confnode *node;
250 };
251
252 static void cmd_cd_node_parsed(void *parsed_result,
253                                struct cmdline *cl,
254                                void *data)
255 {
256         struct cmd_cd_node_result *res = parsed_result;
257         char prompt[RDLINE_PROMPT_SIZE];
258
259         if (TAILQ_NEXT(res->node, user_next)) {
260                 printf("ambiguous directory\n");
261                 return;
262         }
263         conf_cur = res->node;
264         snprintf(prompt, sizeof(prompt), "%s> ", conf_cur->name);
265         cmdline_set_prompt(cl, prompt);
266 }
267
268 cmdline_parse_token_string_t cmd_cd_node_cd =
269         TOKEN_STRING_INITIALIZER(struct cmd_cd_node_result, cd, "cd");
270 parse_token_conf_node_t cmd_cd_node_node =
271         TOKEN_CONF_NODE_INITIALIZER(struct cmd_cd_node_result, node,
272                                     &conf_root, &conf_cur,
273                                     CONFNODE_F_IS_DIR,
274                                     CONFNODE_F_IS_DIR|CONFNODE_F_INVISIBLE);
275
276 cmdline_parse_inst_t cmd_cd_node = {
277         .f = cmd_cd_node_parsed,  /* function to call */
278         .data = NULL,      /* 2nd arg of func */
279         .help_str = "<cd CONFNODE> go down in a configuration sub-tree",
280         .tokens = {        /* token list, NULL terminated */
281                 (void *)&cmd_cd_node_cd,
282                 (void *)&cmd_cd_node_node,
283                 NULL,
284         },
285 };
286
287 /**********************************************************/
288 /* set bool node */
289 /**********************************************************/
290
291 struct cmd_set_bool_result {
292         cmdline_fixed_string_t set;
293         struct confnode *node;
294         cmdline_fixed_string_t val;
295 };
296
297 static void cmd_set_bool_parsed(void *parsed_result,
298                                struct cmdline *cl,
299                                void *data)
300 {
301         struct cmd_set_bool_result *res = parsed_result;
302         struct confnode *n = res->node;
303         char value[BUFSIZ];
304
305         while (n) {
306                 if (confnode_set_user_strvalue(n, res->val) < 0)
307                         printf("Error, cannot set value\n");
308                 else {
309                         if (strcmp(res->val, "y") == 0)
310                                 confnode_check_deps(n, 1);
311                         if (confnode_get_value(n, value,
312                                                   sizeof(value)) < 0)
313                                 printf("Error, cannot re-read value\n");
314                 }
315                 printf("<%s> value set to %s\n", n->name, value);
316                 n = TAILQ_NEXT(n, user_next);
317         }
318 }
319
320 cmdline_parse_token_string_t cmd_set_bool_set =
321         TOKEN_STRING_INITIALIZER(struct cmd_set_bool_result, set, "set");
322 parse_token_conf_node_t cmd_set_bool_node =
323         TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_bool_result, node,
324                                     &conf_root, &conf_cur,
325                                     CONFNODE_F_BOOL,
326                                     CONFNODE_F_BOOL|CONFNODE_F_INVISIBLE);
327 cmdline_parse_token_string_t cmd_set_bool_val =
328         TOKEN_STRING_INITIALIZER(struct cmd_set_bool_result, val, "y#n");
329
330 cmdline_parse_inst_t cmd_set_bool = {
331         .f = cmd_set_bool_parsed,  /* function to call */
332         .data = NULL,      /* 2nd arg of func */
333         .help_str = "<set CONFNODE y|n> set boolean value",
334         .tokens = {        /* token list, NULL terminated */
335                 (void *)&cmd_set_bool_set,
336                 (void *)&cmd_set_bool_node,
337                 (void *)&cmd_set_bool_val,
338                 NULL,
339         },
340 };
341
342 /**********************************************************/
343 /* set int node */
344 /**********************************************************/
345
346 struct cmd_set_int_result {
347         cmdline_fixed_string_t set;
348         struct confnode *node;
349         int32_t val;
350 };
351
352 static void cmd_set_int_parsed(void *parsed_result,
353                                struct cmdline *cl,
354                                void *data)
355 {
356         struct cmd_set_int_result *res = parsed_result;
357         struct confnode *n = res->node;
358         char value[BUFSIZ];
359
360         while (n) {
361                 snprintf(value, sizeof(value), "%"PRIi32, res->val);
362                 if (confnode_set_user_strvalue(n, value) < 0)
363                         printf("Error, cannot set value\n");
364                 else {
365                         if (res->val)
366                                 confnode_check_deps(n, 1);
367                         if (confnode_get_value(n, value,
368                                                   sizeof(value)) < 0)
369                                 printf("Error, cannot re-read value\n");
370                 }
371                 printf("<%s> value set to %s\n", n->name, value);
372                 n = TAILQ_NEXT(n, user_next);
373         }
374 }
375
376 cmdline_parse_token_string_t cmd_set_int_set =
377         TOKEN_STRING_INITIALIZER(struct cmd_set_int_result, set, "set");
378 parse_token_conf_node_t cmd_set_int_node =
379         TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_int_result, node,
380                                     &conf_root, &conf_cur,
381                                     CONFNODE_F_INT,
382                                     CONFNODE_F_INT|CONFNODE_F_INVISIBLE);
383 cmdline_parse_token_num_t cmd_set_int_val =
384         TOKEN_NUM_INITIALIZER(struct cmd_set_int_result, val, INT32);
385
386 cmdline_parse_inst_t cmd_set_int = {
387         .f = cmd_set_int_parsed,  /* function to call */
388         .data = NULL,      /* 2nd arg of func */
389         .help_str = "<set CONFNODE INT> set integer value",
390         .tokens = {        /* token list, NULL terminated */
391                 (void *)&cmd_set_int_set,
392                 (void *)&cmd_set_int_node,
393                 (void *)&cmd_set_int_val,
394                 NULL,
395         },
396 };
397
398 /**********************************************************/
399 /* set str node */
400 /**********************************************************/
401
402 struct cmd_set_str_result {
403         cmdline_fixed_string_t set;
404         struct confnode *node;
405 };
406
407 static int get_str(struct cmdline *cl, char *buf, int len)
408 {
409         struct rdline rl;
410         int ret = 0, n;
411         char c;
412         char *s;
413
414         buf[0] = '\0';
415
416         rdline_init(&rl, cmdline_write_char, NULL, NULL);
417         rl.opaque = cl;
418         rdline_newline(&rl, "edit> ");
419
420         while (ret == 0 || ret == 2) {
421                 n = read(cl->s_in, &c, 1);
422                 if (n <= 0)
423                         return -1;
424                 ret = rdline_char_in(&rl, c);
425                 if (ret == 1) {
426                         snprintf(buf, len, "%s", rdline_get_buffer(&rl));
427                         s = strchr(buf, '\n');
428                         if (s)
429                                 *s = '\0';
430                         return 0;
431                 }
432         }
433
434         return -1;
435 }
436
437 static void cmd_set_str_parsed(void *parsed_result,
438                                struct cmdline *cl,
439                                void *data)
440 {
441         struct cmd_set_str_result *res = parsed_result;
442         struct confnode *n = res->node;
443         char value[BUFSIZ];
444
445         if (confnode_get_value(res->node, value, sizeof(value)) < 0) {
446                 printf("Error, cannot read value\n");
447                 return;
448         }
449         printf("Previous value is %s\n", value);
450         printf("type CTRL-d on an empty line to abort\n");
451         if (get_str(cl, value, sizeof(value))) {
452                 printf("Aborted\n");
453                 return;
454         }
455         while (n) {
456                 snprintf(res->node->value, sizeof(res->node->value),
457                          "%s", value);
458                 if (strcmp(value, ""))
459                         confnode_check_deps(n, 1);
460                 if (confnode_get_value(n, value,
461                                        sizeof(value)) < 0)
462                         printf("Error, cannot re-read value\n");
463                 printf("<%s> value set to %s\n", n->name, value);
464                 n = TAILQ_NEXT(n, user_next);
465         }
466 }
467
468 cmdline_parse_token_string_t cmd_set_str_set =
469         TOKEN_STRING_INITIALIZER(struct cmd_set_str_result, set, "set");
470 parse_token_conf_node_t cmd_set_str_node =
471         TOKEN_CONF_NODE_INITIALIZER(struct cmd_set_str_result, node,
472                                     &conf_root, &conf_cur,
473                                     CONFNODE_F_STR,
474                                     CONFNODE_F_STR|CONFNODE_F_INVISIBLE);
475
476 cmdline_parse_inst_t cmd_set_str = {
477         .f = cmd_set_str_parsed,  /* function to call */
478         .data = NULL,      /* 2nd arg of func */
479         .help_str = "<set CONFNODE> set str value",
480         .tokens = {        /* token list, NULL terminated */
481                 (void *)&cmd_set_str_set,
482                 (void *)&cmd_set_str_node,
483                 NULL,
484         },
485 };
486
487 /**********************************************************/
488 /* show node */
489 /**********************************************************/
490
491 struct cmd_show_node_result {
492         cmdline_fixed_string_t show;
493         cmdline_fixed_string_t all;
494         struct confnode *node;
495 };
496
497 static void cmd_show_node_parsed(void *parsed_result,
498                                struct cmdline *cl,
499                                void *data)
500 {
501         struct cmd_show_node_result *res = parsed_result;
502         struct confnode *n = res->node;
503         int details = 0;
504
505         if (data)
506                 details = 1;
507
508         while (n) {
509                 confnode_display_long(n);
510                 n = TAILQ_NEXT(n, user_next);
511         }
512 }
513
514 cmdline_parse_token_string_t cmd_show_node_show =
515         TOKEN_STRING_INITIALIZER(struct cmd_show_node_result, show, "show");
516 cmdline_parse_token_string_t cmd_show_node_all =
517         TOKEN_STRING_INITIALIZER(struct cmd_show_node_result, all, "-a");
518 parse_token_conf_node_t cmd_show_node_node =
519         TOKEN_CONF_NODE_INITIALIZER(struct cmd_show_node_result, node,
520                                     &conf_root, &conf_cur, 0, CONFNODE_F_INVISIBLE);
521
522 cmdline_parse_inst_t cmd_show_node = {
523         .f = cmd_show_node_parsed,  /* function to call */
524         .data = NULL,      /* 2nd arg of func */
525         .help_str = "<show CONFNODE> display infos on the config option",
526         .tokens = {        /* token list, NULL terminated */
527                 (void *)&cmd_show_node_show,
528                 (void *)&cmd_show_node_node,
529                 NULL,
530         },
531 };
532
533 cmdline_parse_inst_t cmd_show_node_a = {
534         .f = cmd_show_node_parsed,  /* function to call */
535         .data = (void *)1,      /* 2nd arg of func */
536         .help_str = "<show -a CONFNODE> display detailed infos on the config option",
537         .tokens = {        /* token list, NULL terminated */
538                 (void *)&cmd_show_node_show,
539                 (void *)&cmd_show_node_all,
540                 (void *)&cmd_show_node_node,
541                 NULL,
542         },
543 };
544
545 /**********************************************************/
546 /* load / load file */
547 /**********************************************************/
548
549 struct cmd_load_result {
550         cmdline_fixed_string_t load;
551         cmdline_fixed_string_t file;
552 };
553
554 static void cmd_load_parsed(void *parsed_result,
555                             struct cmdline *cl,
556                             void *data)
557 {
558         char prompt[RDLINE_PROMPT_SIZE];
559         struct cmd_load_result *res = parsed_result;
560         const char *filename;
561
562         if (data)
563                 filename = data;
564         else
565                 filename = res->file;
566
567         conf_cur = conf_reset_and_read(conf_root, filename);
568         if (conf_root == NULL) {
569                 printf("error loading <%s>\n", filename);
570                 return;
571         }
572         conf_cur = conf_root;
573         snprintf(prompt, sizeof(prompt), "root> ");
574
575         printf("%s loaded\n", filename);
576 }
577
578 cmdline_parse_token_string_t cmd_load_load =
579         TOKEN_STRING_INITIALIZER(struct cmd_load_result, load, "load");
580
581 cmdline_parse_inst_t cmd_load = {
582         .f = cmd_load_parsed,  /* function to call */
583         .data = ".config",      /* 2nd arg of func */
584         .help_str = "<load> reload the .config file",
585         .tokens = {        /* token list, NULL terminated */
586                 (void *)&cmd_load_load,
587                 NULL,
588         },
589 };
590
591 cmdline_parse_token_string_t cmd_load_file =
592         TOKEN_STRING_INITIALIZER(struct cmd_load_result, file, NULL);
593
594 cmdline_parse_inst_t cmd_loadfile = {
595         .f = cmd_load_parsed,  /* function to call */
596         .data = NULL,      /* 2nd arg of func */
597         .help_str = "<load FILE> load another .config file",
598         .tokens = {        /* token list, NULL terminated */
599                 (void *)&cmd_load_load,
600                 (void *)&cmd_load_file,
601                 NULL,
602         },
603 };
604
605 /**********************************************************/
606 /* save / save file */
607 /**********************************************************/
608
609 struct cmd_save_result {
610         cmdline_fixed_string_t save;
611         cmdline_fixed_string_t file;
612 };
613
614 static void cmd_save_parsed(void *parsed_result,
615                             struct cmdline *cl,
616                             void *data)
617 {
618         struct cmd_save_result *res = parsed_result;
619         const char *filename;
620
621         if (data)
622                 filename = data;
623         else
624                 filename = res->file;
625
626         if (dotconfig_write(filename, conf_root) < 0) {
627                 printf("error saving <%s>\n", filename);
628                 return;
629         }
630         printf("%s saved\n", filename);
631 }
632
633 cmdline_parse_token_string_t cmd_save_save =
634         TOKEN_STRING_INITIALIZER(struct cmd_save_result, save, "save");
635
636 cmdline_parse_inst_t cmd_save = {
637         .f = cmd_save_parsed,  /* function to call */
638         .data = ".config",      /* 2nd arg of func */
639         .help_str = "<save> write the .config file",
640         .tokens = {        /* token list, NULL terminated */
641                 (void *)&cmd_save_save,
642                 NULL,
643         },
644 };
645
646 cmdline_parse_token_string_t cmd_save_file =
647         TOKEN_STRING_INITIALIZER(struct cmd_save_result, file, NULL);
648
649 cmdline_parse_inst_t cmd_savefile = {
650         .f = cmd_save_parsed,  /* function to call */
651         .data = NULL,      /* 2nd arg of func */
652         .help_str = "<save FILE> save in another .config file",
653         .tokens = {        /* token list, NULL terminated */
654                 (void *)&cmd_save_save,
655                 (void *)&cmd_save_file,
656                 NULL,
657         },
658 };
659
660 /**********************************************************/
661
662
663 /**********************************************************/
664 /**********************************************************/
665 /****** CONTEXT (list of instruction) */
666
667 /* in progmem */
668 cmdline_parse_ctx_t main_ctx[] = {
669         (cmdline_parse_inst_t *)&cmd_ls,
670         (cmdline_parse_inst_t *)&cmd_ls_node,
671         (cmdline_parse_inst_t *)&cmd_pwd,
672         (cmdline_parse_inst_t *)&cmd_cd_prev,
673         (cmdline_parse_inst_t *)&cmd_cd_root,
674         (cmdline_parse_inst_t *)&cmd_cd_node,
675         (cmdline_parse_inst_t *)&cmd_set_bool,
676         (cmdline_parse_inst_t *)&cmd_set_int,
677         (cmdline_parse_inst_t *)&cmd_set_str,
678         (cmdline_parse_inst_t *)&cmd_show_node,
679         (cmdline_parse_inst_t *)&cmd_show_node_a,
680         (cmdline_parse_inst_t *)&cmd_load,
681         (cmdline_parse_inst_t *)&cmd_loadfile,
682         (cmdline_parse_inst_t *)&cmd_save,
683         (cmdline_parse_inst_t *)&cmd_savefile,
684         NULL,
685 };
686