]>
Commit | Line | Data |
---|---|---|
1ab84bf3 QY |
1 | /* |
2 | * Testing shim and API examples for the new CLI backend. | |
3 | * | |
4 | * This unit defines a number of commands in the old engine that can | |
5 | * be used to test and interact with the new engine. | |
6 | * | |
7 | * This shim should be removed upon integration. It is currently hooked in | |
8 | * vtysh/vtysh.c. It has no header, vtysh.c merely includes this entire unit | |
9 | * since it clutters up the makefiles less and this is only a temporary shim. | |
10 | * | |
11 | * -- | |
12 | * Copyright (C) 2016 Cumulus Networks, Inc. | |
13 | * | |
14 | * This file is part of GNU Zebra. | |
15 | * | |
16 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
17 | * under the terms of the GNU General Public License as published by the | |
18 | * Free Software Foundation; either version 2, or (at your option) any | |
19 | * later version. | |
20 | * | |
21 | * GNU Zebra is distributed in the hope that it will be useful, but | |
22 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
24 | * General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with GNU Zebra; see the file COPYING. If not, write to the Free | |
28 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
29 | * 02111-1307, USA. | |
30 | */ | |
31 | ||
51e156b3 | 32 | #include "command.h" |
9d0662e0 | 33 | #include "command_graph.h" |
478bdaeb | 34 | #include "command_parse.h" |
9d0662e0 | 35 | #include "command_match.h" |
51e156b3 QY |
36 | |
37 | #define GRAMMAR_STR "CLI grammar sandbox\n" | |
38 | ||
1ab84bf3 QY |
39 | void |
40 | grammar_sandbox_init(void); | |
41 | void | |
42 | pretty_print_graph (struct graph_node *start, int level); | |
43 | ||
44 | /* | |
45 | * Start node for testing command graph. | |
46 | * | |
47 | * Each cmd_node will have one of these that replaces the `cmdvector` member. | |
48 | * The examples below show how to install a command to the graph, calculate | |
49 | * completions for a given input line, and match input against the graph. | |
50 | */ | |
340a2b4a QY |
51 | struct graph_node * nodegraph; |
52 | ||
1ab84bf3 QY |
53 | /** |
54 | * Reference use of parsing / command installation API | |
55 | */ | |
9d0662e0 QY |
56 | DEFUN (grammar_test, |
57 | grammar_test_cmd, | |
58 | "grammar parse .COMMAND", | |
59 | GRAMMAR_STR | |
60 | "command to pass to new parser\n") | |
61 | { | |
1ab84bf3 QY |
62 | char *command = argv_concat(argv, argc, 0); |
63 | ||
64 | // initialize a pretend cmd_element | |
65 | struct cmd_element *cmd = XCALLOC(MTYPE_CMD_TOKENS, sizeof(struct cmd_element)); | |
eceb1066 | 66 | cmd->string = command; |
e648e61a QY |
67 | cmd->doc = NULL; |
68 | cmd->func = NULL; | |
e1cbb2ff | 69 | cmd->tokens = vector_init(VECTOR_MIN_SIZE); |
51e156b3 | 70 | |
1ab84bf3 QY |
71 | // parse the command and install it into the command graph |
72 | parse_command_format (nodegraph, cmd); | |
73 | ||
74 | // free resources | |
75 | free (command); | |
0aa2c2ff | 76 | |
9d0662e0 QY |
77 | return CMD_SUCCESS; |
78 | } | |
79 | ||
1ab84bf3 QY |
80 | |
81 | /** | |
82 | * Reference use of completions API | |
83 | */ | |
eceb1066 QY |
84 | DEFUN (grammar_test_complete, |
85 | grammar_test_complete_cmd, | |
86 | "grammar complete .COMMAND", | |
9d0662e0 | 87 | GRAMMAR_STR |
eceb1066 QY |
88 | "attempt to complete input on DFA\n" |
89 | "command to complete") | |
9d0662e0 | 90 | { |
1ab84bf3 QY |
91 | char *cmdstr = argv_concat (argv, argc, 0); |
92 | vector command = cmd_make_strvec (cmdstr); | |
93 | ||
94 | struct list *completions; | |
95 | enum matcher_rv result = match_command_complete (nodegraph, command, &completions); | |
18be0e59 | 96 | |
1ab84bf3 QY |
97 | // print completions or relevant error message |
98 | if (completions) | |
99 | { | |
100 | struct listnode *ln; | |
101 | struct graph_node *gn; | |
102 | for (ALL_LIST_ELEMENTS_RO(completions,ln,gn)) | |
103 | { | |
104 | if (gn->type == END_GN) | |
105 | zlog_info ("<cr> (%p)", gn->element->func); | |
106 | else | |
107 | zlog_info ("%-30s%s", gn->text, gn->doc); | |
108 | } | |
109 | list_delete (completions); | |
110 | } | |
18be0e59 | 111 | else |
1ab84bf3 QY |
112 | { |
113 | assert(MATCHER_ERROR(result)); | |
114 | zlog_info ("%% No match for \"%s\"", cmdstr); | |
880e24a1 | 115 | } |
1ab84bf3 QY |
116 | |
117 | // free resources | |
118 | cmd_free_strvec (command); | |
119 | free (cmdstr); | |
18be0e59 | 120 | |
9d0662e0 | 121 | return CMD_SUCCESS; |
340a2b4a QY |
122 | } |
123 | ||
1ab84bf3 QY |
124 | /** |
125 | * Reference use of matching API | |
126 | */ | |
eceb1066 QY |
127 | DEFUN (grammar_test_match, |
128 | grammar_test_match_cmd, | |
129 | "grammar match .COMMAND", | |
130 | GRAMMAR_STR | |
131 | "attempt to match input on DFA\n" | |
132 | "command to match") | |
133 | { | |
1ab84bf3 QY |
134 | char *cmdstr = argv_concat(argv, argc, 0); |
135 | vector command = cmd_make_strvec (cmdstr); | |
6ce82b63 | 136 | |
de9d7e4f | 137 | struct list *argvv = NULL; |
6ce82b63 | 138 | struct cmd_element *element = NULL; |
1ab84bf3 QY |
139 | enum matcher_rv result = match_command (nodegraph, command, &argvv, &element); |
140 | ||
141 | // print completions or relevant error message | |
142 | if (element) | |
143 | { | |
144 | zlog_info ("Matched: %s", element->string); | |
145 | struct listnode *ln; | |
146 | struct graph_node *gn; | |
147 | for (ALL_LIST_ELEMENTS_RO(argvv,ln,gn)) | |
148 | if (gn->type != END_GN) | |
149 | zlog_info ("func: %p", gn->element->func); | |
150 | else | |
151 | zlog_info ("%s -- %s", gn->text, gn->arg); | |
152 | ||
153 | list_delete (argvv); | |
154 | } | |
de9d7e4f | 155 | else { |
1ab84bf3 | 156 | assert(MATCHER_ERROR(result)); |
6ce82b63 QY |
157 | switch (result) { |
158 | case MATCHER_NO_MATCH: | |
1ab84bf3 | 159 | zlog_info ("%% Unknown command"); |
6ce82b63 QY |
160 | break; |
161 | case MATCHER_INCOMPLETE: | |
1ab84bf3 | 162 | zlog_info ("%% Incomplete command"); |
6ce82b63 QY |
163 | break; |
164 | case MATCHER_AMBIGUOUS: | |
1ab84bf3 | 165 | zlog_info ("%% Ambiguous command"); |
6ce82b63 QY |
166 | break; |
167 | default: | |
1ab84bf3 | 168 | zlog_info ("%% Unknown error"); |
6ce82b63 QY |
169 | break; |
170 | } | |
de9d7e4f QY |
171 | } |
172 | ||
1ab84bf3 QY |
173 | // free resources |
174 | cmd_free_strvec(command); | |
175 | free(cmdstr); | |
176 | ||
eceb1066 QY |
177 | return CMD_SUCCESS; |
178 | } | |
179 | ||
1ab84bf3 QY |
180 | /** |
181 | * Testing shim to test docstrings | |
182 | */ | |
183 | DEFUN (grammar_test_doc, | |
184 | grammar_test_doc_cmd, | |
185 | "grammar test docstring", | |
186 | GRAMMAR_STR | |
187 | "Test function for docstring\n" | |
188 | "Command end\n") | |
189 | { | |
190 | // create cmd_element with docstring | |
191 | struct cmd_element *cmd = XCALLOC(MTYPE_CMD_TOKENS, sizeof(struct cmd_element)); | |
192 | cmd->string = "test docstring <example|selector follow> (1-255) end VARIABLE [OPTION|set lol] . VARARG"; | |
193 | cmd->doc = "Test stuff\n" | |
194 | "docstring thing\n" | |
195 | "first example\n" | |
196 | "second example\n" | |
197 | "follow\n" | |
198 | "random range\n" | |
199 | "end thingy\n" | |
200 | "variable\n" | |
201 | "optional variable\n" | |
202 | "optional set\n" | |
203 | "optional lol\n" | |
204 | "vararg!\n"; | |
205 | cmd->func = NULL; | |
206 | cmd->tokens = vector_init (VECTOR_MIN_SIZE); | |
207 | ||
208 | // parse element | |
209 | parse_command_format (nodegraph, cmd); | |
210 | ||
211 | return CMD_SUCCESS; | |
212 | } | |
213 | ||
214 | /** | |
215 | * Debugging command to print command graph | |
216 | */ | |
217 | DEFUN (grammar_test_show, | |
218 | grammar_test_show_cmd, | |
219 | "grammar show graph", | |
220 | GRAMMAR_STR | |
221 | "print current accumulated DFA\n") | |
222 | { | |
223 | if (!nodegraph) | |
224 | zlog_info("nodegraph uninitialized"); | |
225 | else | |
226 | pretty_print_graph (nodegraph, 0); | |
227 | return CMD_SUCCESS; | |
228 | } | |
51e156b3 | 229 | |
1ab84bf3 | 230 | /* this is called in vtysh.c to set up the testing shim */ |
51e156b3 | 231 | void grammar_sandbox_init() { |
1ab84bf3 | 232 | zlog_info ("Initializing grammar testing shim"); |
5a5d576b | 233 | nodegraph = new_node(START_GN); |
478bdaeb | 234 | install_element (ENABLE_NODE, &grammar_test_cmd); |
340a2b4a | 235 | install_element (ENABLE_NODE, &grammar_test_show_cmd); |
9d0662e0 | 236 | install_element (ENABLE_NODE, &grammar_test_match_cmd); |
eceb1066 | 237 | install_element (ENABLE_NODE, &grammar_test_complete_cmd); |
0aa2c2ff | 238 | install_element (ENABLE_NODE, &grammar_test_doc_cmd); |
51e156b3 | 239 | } |
1ab84bf3 QY |
240 | |
241 | /* recursive pretty-print for command graph */ | |
242 | void | |
243 | pretty_print_graph (struct graph_node *start, int level) | |
244 | { | |
245 | // print this node | |
246 | fprintf (stdout, "%s[%d] ", start->text, vector_active (start->children)); | |
247 | ||
248 | if (vector_active (start->children)) | |
249 | { | |
250 | if (vector_active (start->children) == 1) | |
251 | pretty_print_graph (vector_slot (start->children, 0), level); | |
252 | else | |
253 | { | |
254 | fprintf(stdout, "\n"); | |
255 | for (unsigned int i = 0; i < vector_active (start->children); i++) | |
256 | { | |
257 | struct graph_node *r = vector_slot (start->children, i); | |
258 | for (int j = 0; j < level+1; j++) | |
259 | fprintf (stdout, " "); | |
260 | pretty_print_graph (r, level+1); | |
261 | } | |
262 | } | |
263 | } | |
264 | else | |
265 | fprintf(stdout, "\n"); | |
266 | } |