]> git.proxmox.com Git - mirror_frr.git/blame - lib/grammar_sandbox.c
Merge remote-tracking branch 'origin/master' into EIGRP
[mirror_frr.git] / lib / grammar_sandbox.c
CommitLineData
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.
1ab84bf3
QY
6 * --
7 * Copyright (C) 2016 Cumulus Networks, Inc.
8 *
9 * This file is part of GNU Zebra.
10 *
11 * GNU Zebra is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2, or (at your option) any
14 * later version.
15 *
16 * GNU Zebra is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with GNU Zebra; see the file COPYING. If not, write to the Free
23 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 * 02111-1307, USA.
25 */
26
51e156b3 27#include "command.h"
fa133e00 28#include "memory_vty.h"
1eb5e8dc 29#include "graph.h"
0a22b979 30#include "linklist.h"
9d0662e0 31#include "command_match.h"
51e156b3
QY
32
33#define GRAMMAR_STR "CLI grammar sandbox\n"
34
fa133e00
DL
35DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
36
37#define MAXDEPTH 64
38
97c45dae 39/** headers **/
1ab84bf3 40void
1eb5e8dc 41grammar_sandbox_init (void);
1ab84bf3 42void
fa133e00 43pretty_print_graph (struct vty *vty, struct graph_node *, int, int, struct graph_node **, size_t);
818a5168
DL
44static void
45pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start,
b285cf4b
DL
46 struct graph_node **stack, size_t stackpos,
47 struct graph_node **visited, size_t *visitpos);
500b1a5b 48void
fa133e00 49init_cmdgraph (struct vty *, struct graph **);
1ab84bf3 50
97c45dae 51/** shim interface commands **/
af2567b6 52struct graph *nodegraph = NULL, *nodegraph_free = NULL;
340a2b4a 53
9d0662e0
QY
54DEFUN (grammar_test,
55 grammar_test_cmd,
fa133e00 56 "grammar parse LINE...",
9d0662e0 57 GRAMMAR_STR
fa133e00 58 "parse a command\n"
9d0662e0
QY
59 "command to pass to new parser\n")
60{
58749582 61 int idx_command = 2;
ff35126c 62 // make a string from tokenized command line
58749582 63 char *command = argv_concat (argv, argc, idx_command);
1ab84bf3 64
ff35126c 65 // create cmd_element for parser
1eb5e8dc 66 struct cmd_element *cmd = XCALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_element));
500b1a5b 67 cmd->string = command;
fa133e00 68 cmd->doc = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n";
e648e61a 69 cmd->func = NULL;
51e156b3 70
1ab84bf3 71 // parse the command and install it into the command graph
de8f7a39
DL
72 struct graph *graph = graph_new();
73 struct cmd_token *token = new_cmd_token (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
74 graph_new_node (graph, token, (void (*)(void *)) &del_cmd_token);
75
76 command_parse_format (graph, cmd);
77 cmd_merge_graphs (nodegraph, graph, +1);
1ab84bf3 78
9d0662e0
QY
79 return CMD_SUCCESS;
80}
81
eceb1066
QY
82DEFUN (grammar_test_complete,
83 grammar_test_complete_cmd,
fa133e00 84 "grammar complete COMMAND...",
9d0662e0 85 GRAMMAR_STR
eceb1066 86 "attempt to complete input on DFA\n"
fa133e00 87 "command to complete\n")
9d0662e0 88{
58749582
DW
89 int idx_command = 2;
90 char *cmdstr = argv_concat (argv, argc, idx_command);
fa133e00
DL
91 if (!cmdstr)
92 return CMD_SUCCESS;
93
1ab84bf3 94 vector command = cmd_make_strvec (cmdstr);
14878121
DL
95 if (!command)
96 {
97 XFREE (MTYPE_TMP, cmdstr);
98 return CMD_SUCCESS;
99 }
1ab84bf3 100
ff35126c 101 // generate completions of user input
795d0278 102 struct list *completions;
ff35126c 103 enum matcher_rv result = command_complete (nodegraph, command, &completions);
18be0e59 104
1ab84bf3 105 // print completions or relevant error message
ca90e051 106 if (!MATCHER_ERROR(result))
1ab84bf3 107 {
ee761cc0 108 vector comps = completions_to_vec (completions);
fa133e00 109 struct cmd_token *tkn;
ff35126c
QY
110
111 // calculate length of longest tkn->text in completions
ee761cc0
QY
112 unsigned int width = 0, i = 0;
113 for (i = 0; i < vector_active (comps); i++) {
114 tkn = vector_slot (comps, i);
115 unsigned int len = strlen (tkn->text);
116 width = len > width ? len : width;
ff35126c
QY
117 }
118
119 // print completions
ee761cc0
QY
120 for (i = 0; i < vector_active (comps); i++) {
121 tkn = vector_slot (comps, i);
fa133e00 122 vty_out (vty, " %-*s %s%s", width, tkn->text, tkn->desc, VTY_NEWLINE);
ee761cc0 123 }
795d0278
QY
124
125 for (i = 0; i < vector_active (comps); i++)
fa133e00 126 del_cmd_token ((struct cmd_token *) vector_slot (comps, i));
795d0278 127 vector_free (comps);
1ab84bf3 128 }
18be0e59 129 else
fa133e00 130 vty_out (vty, "%% No match%s", VTY_NEWLINE);
1ab84bf3
QY
131
132 // free resources
1eb5e8dc 133 list_delete (completions);
ff35126c 134 cmd_free_strvec (command);
14878121 135 XFREE (MTYPE_TMP, cmdstr);
18be0e59 136
9d0662e0 137 return CMD_SUCCESS;
340a2b4a
QY
138}
139
eceb1066
QY
140DEFUN (grammar_test_match,
141 grammar_test_match_cmd,
fa133e00 142 "grammar match COMMAND...",
eceb1066
QY
143 GRAMMAR_STR
144 "attempt to match input on DFA\n"
fa133e00 145 "command to match\n")
eceb1066 146{
58749582 147 int idx_command = 2;
fa133e00 148 if (argv[2]->arg[0] == '#')
4427e9b3
QY
149 return CMD_SUCCESS;
150
58749582 151 char *cmdstr = argv_concat(argv, argc, idx_command);
14878121
DL
152 if (!cmdstr)
153 return CMD_SUCCESS;
1ab84bf3 154 vector command = cmd_make_strvec (cmdstr);
14878121
DL
155 if (!command)
156 {
157 XFREE (MTYPE_TMP, cmdstr);
158 return CMD_SUCCESS;
159 }
6ce82b63 160
de9d7e4f 161 struct list *argvv = NULL;
fa133e00 162 const struct cmd_element *element = NULL;
55589d30 163 enum matcher_rv result = command_match (nodegraph, command, &argvv, &element);
1ab84bf3
QY
164
165 // print completions or relevant error message
166 if (element)
167 {
fa133e00 168 vty_out (vty, "Matched: %s%s", element->string, VTY_NEWLINE);
1ab84bf3 169 struct listnode *ln;
fa133e00 170 struct cmd_token *token;
97f13f08 171 for (ALL_LIST_ELEMENTS_RO(argvv,ln,token))
fa133e00 172 vty_out (vty, "%s -- %s%s", token->text, token->arg, VTY_NEWLINE);
1eb5e8dc 173
fa133e00 174 vty_out (vty, "func: %p%s", element->func, VTY_NEWLINE);
1ab84bf3
QY
175
176 list_delete (argvv);
177 }
de9d7e4f 178 else {
1ab84bf3 179 assert(MATCHER_ERROR(result));
6ce82b63
QY
180 switch (result) {
181 case MATCHER_NO_MATCH:
fa133e00 182 vty_out (vty, "%% Unknown command%s", VTY_NEWLINE);
6ce82b63
QY
183 break;
184 case MATCHER_INCOMPLETE:
fa133e00 185 vty_out (vty, "%% Incomplete command%s", VTY_NEWLINE);
6ce82b63
QY
186 break;
187 case MATCHER_AMBIGUOUS:
fa133e00 188 vty_out (vty, "%% Ambiguous command%s", VTY_NEWLINE);
6ce82b63
QY
189 break;
190 default:
fa133e00 191 vty_out (vty, "%% Unknown error%s", VTY_NEWLINE);
6ce82b63
QY
192 break;
193 }
de9d7e4f
QY
194 }
195
1ab84bf3 196 // free resources
795d0278 197 cmd_free_strvec (command);
14878121 198 XFREE (MTYPE_TMP, cmdstr);
1ab84bf3 199
eceb1066
QY
200 return CMD_SUCCESS;
201}
202
1ab84bf3
QY
203/**
204 * Testing shim to test docstrings
205 */
206DEFUN (grammar_test_doc,
207 grammar_test_doc_cmd,
208 "grammar test docstring",
209 GRAMMAR_STR
210 "Test function for docstring\n"
211 "Command end\n")
212{
213 // create cmd_element with docstring
1eb5e8dc 214 struct cmd_element *cmd = XCALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_element));
ff35126c
QY
215 cmd->string = XSTRDUP (MTYPE_CMD_TOKENS, "test docstring <example|selector follow> (1-255) end VARIABLE [OPTION|set lol] . VARARG");
216 cmd->doc = XSTRDUP (MTYPE_CMD_TOKENS,
217 "Test stuff\n"
1ab84bf3
QY
218 "docstring thing\n"
219 "first example\n"
220 "second example\n"
221 "follow\n"
222 "random range\n"
223 "end thingy\n"
224 "variable\n"
225 "optional variable\n"
226 "optional set\n"
227 "optional lol\n"
ff35126c 228 "vararg!\n");
1ab84bf3 229 cmd->func = NULL;
1ab84bf3
QY
230
231 // parse element
55589d30 232 command_parse_format (nodegraph, cmd);
1ab84bf3
QY
233
234 return CMD_SUCCESS;
235}
236
237/**
238 * Debugging command to print command graph
239 */
240DEFUN (grammar_test_show,
241 grammar_test_show_cmd,
fa133e00 242 "grammar show [doc]",
1ab84bf3 243 GRAMMAR_STR
fa133e00
DL
244 "print current accumulated DFA\n"
245 "include docstrings\n")
1ab84bf3 246{
fa133e00
DL
247 struct graph_node *stack[MAXDEPTH];
248
1ab84bf3 249 if (!nodegraph)
fa133e00 250 vty_out(vty, "nodegraph uninitialized\r\n");
1ab84bf3 251 else
fa133e00 252 pretty_print_graph (vty, vector_slot (nodegraph->nodes, 0), 0, argc >= 3, stack, 0);
1ab84bf3
QY
253 return CMD_SUCCESS;
254}
51e156b3 255
818a5168
DL
256DEFUN (grammar_test_dot,
257 grammar_test_dot_cmd,
258 "grammar dotfile OUTNAME",
259 GRAMMAR_STR
260 "print current graph for dot\n"
261 ".dot filename\n")
262{
263 struct graph_node *stack[MAXDEPTH];
264 struct graph_node *visited[MAXDEPTH*MAXDEPTH];
265 size_t vpos = 0;
266
267 if (!nodegraph) {
268 vty_out(vty, "nodegraph uninitialized\r\n");
269 return CMD_SUCCESS;
270 }
271 FILE *ofd = fopen(argv[2]->arg, "w");
272 if (!ofd) {
273 vty_out(vty, "%s: %s\r\n", argv[2]->arg, strerror(errno));
274 return CMD_SUCCESS;
275 }
276
277 fprintf(ofd, "digraph {\n graph [ rankdir = LR ];\n node [ fontname = \"Fira Mono\", fontsize = 9 ];\n\n");
278 pretty_print_dot (ofd, 0,
b285cf4b
DL
279 vector_slot (nodegraph->nodes, 0),
280 stack, 0, visited, &vpos);
818a5168
DL
281 fprintf(ofd, "}\n");
282 fclose(ofd);
283 return CMD_SUCCESS;
284}
285
0a22b979
DL
286struct cmd_permute_item
287{
288 char *cmd;
289 struct cmd_element *el;
290};
291
292static void
293cmd_permute_free (void *arg)
294{
295 struct cmd_permute_item *i = arg;
296 XFREE (MTYPE_TMP, i->cmd);
297 XFREE (MTYPE_TMP, i);
298}
299
300static int
301cmd_permute_cmp (void *a, void *b)
302{
303 struct cmd_permute_item *aa = a, *bb = b;
304 return strcmp (aa->cmd, bb->cmd);
305}
306
307static void
308cmd_graph_permute (struct list *out, struct graph_node **stack,
309 size_t stackpos, char *cmd)
310{
311 struct graph_node *gn = stack[stackpos];
312 struct cmd_token *tok = gn->data;
313 char *appendp = cmd + strlen(cmd);
314 size_t i, j;
315
316 if (tok->type < SPECIAL_TKN)
317 {
318 sprintf (appendp, "%s ", tok->text);
319 appendp += strlen (appendp);
320 }
321 else if (tok->type == END_TKN)
322 {
323 struct cmd_permute_item *i = XMALLOC (MTYPE_TMP, sizeof (*i));
324 i->el = ((struct graph_node *)vector_slot (gn->to, 0))->data;
325 i->cmd = XSTRDUP (MTYPE_TMP, cmd);
326 i->cmd[strlen(cmd) - 1] = '\0';
327 listnode_add_sort (out, i);
328 return;
329 }
330
331 if (++stackpos == MAXDEPTH)
332 return;
333
334 for (i = 0; i < vector_active (gn->to); i++)
335 {
336 struct graph_node *gnext = vector_slot (gn->to, i);
337 for (j = 0; j < stackpos; j++)
338 if (stack[j] == gnext)
339 break;
340 if (j != stackpos)
341 continue;
342
343 stack[stackpos] = gnext;
344 *appendp = '\0';
345 cmd_graph_permute (out, stack, stackpos, cmd);
346 }
347}
348
349static struct list *
350cmd_graph_permutations (struct graph *graph)
351{
352 char accumulate[2048] = "";
353 struct graph_node *stack[MAXDEPTH];
354
355 struct list *rv = list_new ();
356 rv->cmp = cmd_permute_cmp;
357 rv->del = cmd_permute_free;
358 stack[0] = vector_slot (graph->nodes, 0);
359 cmd_graph_permute (rv, stack, 0, accumulate);
360 return rv;
361}
362
363extern vector cmdvec;
364
365DEFUN (grammar_findambig,
366 grammar_findambig_cmd,
367 "grammar find-ambiguous [{printall|nodescan}]",
368 GRAMMAR_STR
369 "Find ambiguous commands\n"
370 "Print all permutations\n"
371 "Scan all nodes\n")
372{
373 struct list *commands;
374 struct cmd_permute_item *prev = NULL, *cur = NULL;
375 struct listnode *ln;
376 int i, printall, scan, scannode = 0;
37f9f36e 377 int ambig = 0;
0a22b979
DL
378
379 i = 0;
380 printall = argv_find (argv, argc, "printall", &i);
381 i = 0;
382 scan = argv_find (argv, argc, "nodescan", &i);
383
384 if (scan && nodegraph_free)
385 {
386 graph_delete_graph (nodegraph_free);
387 nodegraph_free = NULL;
388 }
389
390 if (!scan && !nodegraph)
391 {
392 vty_out(vty, "nodegraph uninitialized\r\n");
393 return CMD_WARNING;
394 }
395
396 do {
397 if (scan)
398 {
399 struct cmd_node *cnode = vector_slot (cmdvec, scannode++);
400 if (!cnode)
401 continue;
402 nodegraph = cnode->cmdgraph;
403 if (!nodegraph)
404 continue;
405 vty_out (vty, "scanning node %d%s", scannode - 1, VTY_NEWLINE);
406 }
407
408 commands = cmd_graph_permutations (nodegraph);
409 prev = NULL;
410 for (ALL_LIST_ELEMENTS_RO (commands, ln, cur))
411 {
412 int same = prev && !strcmp (prev->cmd, cur->cmd);
413 if (printall && !same)
90e40ab0 414 vty_out (vty, "'%s' [%x]%s", cur->cmd, cur->el->daemon, VTY_NEWLINE);
0a22b979
DL
415 if (same)
416 {
417 vty_out (vty, "'%s' AMBIGUOUS:%s", cur->cmd, VTY_NEWLINE);
418 vty_out (vty, " %s%s '%s'%s", prev->el->name, VTY_NEWLINE, prev->el->string, VTY_NEWLINE);
419 vty_out (vty, " %s%s '%s'%s", cur->el->name, VTY_NEWLINE, cur->el->string, VTY_NEWLINE);
420 vty_out (vty, "%s", VTY_NEWLINE);
37f9f36e 421 ambig++;
0a22b979
DL
422 }
423 prev = cur;
424 }
425 list_delete (commands);
37f9f36e
DL
426
427 vty_out (vty, "%s", VTY_NEWLINE);
0a22b979
DL
428 } while (scan && scannode < LINK_PARAMS_NODE);
429
37f9f36e
DL
430 vty_out (vty, "%d ambiguous commands found.%s", ambig, VTY_NEWLINE);
431
0a22b979
DL
432 if (scan)
433 nodegraph = NULL;
37f9f36e 434 return ambig == 0 ? CMD_SUCCESS : CMD_WARNING;
0a22b979
DL
435}
436
500b1a5b
QY
437DEFUN (grammar_init_graph,
438 grammar_init_graph_cmd,
fa133e00 439 "grammar init",
500b1a5b
QY
440 GRAMMAR_STR
441 "(re)initialize graph\n")
442{
af2567b6
DL
443 if (nodegraph_free)
444 graph_delete_graph (nodegraph_free);
445 nodegraph_free = NULL;
446
fa133e00 447 init_cmdgraph (vty, &nodegraph);
500b1a5b
QY
448 return CMD_SUCCESS;
449}
450
af2567b6
DL
451DEFUN (grammar_access,
452 grammar_access_cmd,
453 "grammar access (0-65535)",
454 GRAMMAR_STR
455 "access node graph\n"
456 "node number\n")
457{
458 if (nodegraph_free)
459 graph_delete_graph (nodegraph_free);
460 nodegraph_free = NULL;
461
462 struct cmd_node *cnode;
463
464 cnode = vector_slot (cmdvec, atoi (argv[2]->arg));
465 if (!cnode)
466 {
467 vty_out (vty, "%% no such node%s", VTY_NEWLINE);
468 return CMD_WARNING;
469 }
470
471 vty_out (vty, "node %d%s", (int)cnode->node, VTY_NEWLINE);
472 nodegraph = cnode->cmdgraph;
473 return CMD_SUCCESS;
474}
475
1ab84bf3 476/* this is called in vtysh.c to set up the testing shim */
fa133e00
DL
477void grammar_sandbox_init(void) {
478 init_cmdgraph (NULL, &nodegraph);
1eb5e8dc
QY
479
480 // install all enable elements
478bdaeb 481 install_element (ENABLE_NODE, &grammar_test_cmd);
340a2b4a 482 install_element (ENABLE_NODE, &grammar_test_show_cmd);
818a5168 483 install_element (ENABLE_NODE, &grammar_test_dot_cmd);
9d0662e0 484 install_element (ENABLE_NODE, &grammar_test_match_cmd);
eceb1066 485 install_element (ENABLE_NODE, &grammar_test_complete_cmd);
0aa2c2ff 486 install_element (ENABLE_NODE, &grammar_test_doc_cmd);
0a22b979 487 install_element (ENABLE_NODE, &grammar_findambig_cmd);
500b1a5b 488 install_element (ENABLE_NODE, &grammar_init_graph_cmd);
af2567b6 489 install_element (ENABLE_NODE, &grammar_access_cmd);
51e156b3 490}
1ab84bf3 491
fa133e00
DL
492#define item(x) { x, #x }
493struct message tokennames[] = {
494 item(WORD_TKN), // words
495 item(VARIABLE_TKN), // almost anything
496 item(RANGE_TKN), // integer range
497 item(IPV4_TKN), // IPV4 addresses
498 item(IPV4_PREFIX_TKN), // IPV4 network prefixes
499 item(IPV6_TKN), // IPV6 prefixes
500 item(IPV6_PREFIX_TKN), // IPV6 network prefixes
501
502 /* plumbing types */
0bf5b1cb
DL
503 item(FORK_TKN),
504 item(JOIN_TKN),
fa133e00
DL
505 item(START_TKN), // first token in line
506 item(END_TKN), // last token in line
507 { 0, NULL }
508};
509size_t tokennames_max = array_size(tokennames);
500b1a5b 510
97f13f08
QY
511/**
512 * Pretty-prints a graph, assuming it is a tree.
513 *
514 * @param start the node to take as the root
515 * @param level indent level for recursive calls, always pass 0
516 */
1ab84bf3 517void
fa133e00 518pretty_print_graph (struct vty *vty, struct graph_node *start, int level,
b285cf4b 519 int desc, struct graph_node **stack, size_t stackpos)
1ab84bf3
QY
520{
521 // print this node
fa133e00
DL
522 char tokennum[32];
523 struct cmd_token *tok = start->data;
524
525 snprintf(tokennum, sizeof(tokennum), "%d?", tok->type);
526 vty_out(vty, "%s", LOOKUP_DEF(tokennames, tok->type, tokennum));
527 if (tok->text)
528 vty_out(vty, ":\"%s\"", tok->text);
529 if (desc)
530 vty_out(vty, " ?'%s'", tok->desc);
531 vty_out(vty, " ");
532
533 if (stackpos == MAXDEPTH)
534 {
535 vty_out(vty, " -aborting! (depth limit)%s", VTY_NEWLINE);
536 return;
537 }
538 stack[stackpos++] = start;
1ab84bf3 539
fa133e00 540 int numto = desc ? 2 : vector_active (start->to);
97f13f08 541 if (numto)
1ab84bf3 542 {
97f13f08 543 if (numto > 1)
fa133e00 544 vty_out(vty, "%s", VTY_NEWLINE);
97f13f08 545 for (unsigned int i = 0; i < vector_active (start->to); i++)
b84f1d85 546 {
97f13f08
QY
547 struct graph_node *adj = vector_slot (start->to, i);
548 // if we're listing multiple children, indent!
549 if (numto > 1)
550 for (int j = 0; j < level+1; j++)
fa133e00 551 vty_out(vty, " ");
97f13f08
QY
552 // if this node is a vararg, just print *
553 if (adj == start)
fa133e00
DL
554 vty_out(vty, "*");
555 else if (((struct cmd_token *)adj->data)->type == END_TKN)
556 vty_out(vty, "--END%s", VTY_NEWLINE);
557 else {
558 size_t k;
559 for (k = 0; k < stackpos; k++)
560 if (stack[k] == adj) {
561 vty_out(vty, "<<loop@%zu %s", k, VTY_NEWLINE);
562 break;
563 }
564 if (k == stackpos)
565 pretty_print_graph (vty, adj, numto > 1 ? level+1 : level, desc, stack, stackpos);
566 }
567 }
1ab84bf3
QY
568 }
569 else
fa133e00 570 vty_out(vty, "%s", VTY_NEWLINE);
1eb5e8dc
QY
571}
572
818a5168
DL
573static void
574pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start,
b285cf4b
DL
575 struct graph_node **stack, size_t stackpos,
576 struct graph_node **visited, size_t *visitpos)
818a5168
DL
577{
578 // print this node
579 char tokennum[32];
580 struct cmd_token *tok = start->data;
581 const char *color;
582
583 for (size_t i = 0; i < (*visitpos); i++)
584 if (visited[i] == start)
585 return;
586 visited[(*visitpos)++] = start;
587 if ((*visitpos) == MAXDEPTH*MAXDEPTH)
588 return;
589
590 snprintf(tokennum, sizeof(tokennum), "%d?", tok->type);
591 fprintf(ofd, " n%016llx [ shape=box, label=<", (unsigned long long)start);
592
593 fprintf(ofd, "<b>%s</b>", LOOKUP_DEF(tokennames, tok->type, tokennum));
594 if (tok->attr == CMD_ATTR_DEPRECATED)
595 fprintf(ofd, " (d)");
596 else if (tok->attr == CMD_ATTR_HIDDEN)
597 fprintf(ofd, " (h)");
598 if (tok->text) {
599 if (tok->type == WORD_TKN)
600 fprintf(ofd, "<br/>\"<font color=\"#0055ff\" point-size=\"11\"><b>%s</b></font>\"", tok->text);
601 else
602 fprintf(ofd, "<br/>%s", tok->text);
603 }
604/* if (desc)
605 fprintf(ofd, " ?'%s'", tok->desc); */
606 switch (tok->type) {
607 case START_TKN: color = "#ccffcc"; break;
608 case FORK_TKN: color = "#aaddff"; break;
609 case JOIN_TKN: color = "#ddaaff"; break;
610 case WORD_TKN: color = "#ffffff"; break;
611 default: color = "#ffffff"; break;
612 }
613 fprintf(ofd, ">, style = filled, fillcolor = \"%s\" ];\n", color);
614
615 if (stackpos == MAXDEPTH)
616 return;
617 stack[stackpos++] = start;
618
619 for (unsigned int i = 0; i < vector_active (start->to); i++)
620 {
621 struct graph_node *adj = vector_slot (start->to, i);
622 // if this node is a vararg, just print *
623 if (adj == start) {
624 fprintf(ofd, " n%016llx -> n%016llx;\n",
b285cf4b
DL
625 (unsigned long long)start,
626 (unsigned long long)start);
818a5168 627 } else if (((struct cmd_token *)adj->data)->type == END_TKN) {
b285cf4b 628 //struct cmd_token *et = adj->data;
818a5168 629 fprintf(ofd, " n%016llx -> end%016llx;\n",
b285cf4b
DL
630 (unsigned long long)start,
631 (unsigned long long)adj);
632 fprintf(ofd, " end%016llx [ shape=box, label=<end>, style = filled, fillcolor = \"#ffddaa\" ];\n",
633 (unsigned long long)adj);
818a5168
DL
634 } else {
635 fprintf(ofd, " n%016llx -> n%016llx;\n",
b285cf4b
DL
636 (unsigned long long)start,
637 (unsigned long long)adj);
818a5168
DL
638 size_t k;
639 for (k = 0; k < stackpos; k++)
640 if (stack[k] == adj)
641 break;
642 if (k == stackpos) {
643 pretty_print_dot (ofd, opts, adj, stack, stackpos, visited, visitpos);
644 }
645 }
646 }
647}
648
649
1eb5e8dc 650/** stuff that should go in command.c + command.h */
97c45dae 651void
fa133e00 652init_cmdgraph (struct vty *vty, struct graph **graph)
97c45dae
QY
653{
654 // initialize graph, add start noe
655 *graph = graph_new ();
af2567b6 656 nodegraph_free = *graph;
fa133e00 657 struct cmd_token *token = new_cmd_token (START_TKN, 0, NULL, NULL);
97c45dae 658 graph_new_node (*graph, token, (void (*)(void *)) &del_cmd_token);
fa133e00
DL
659 if (vty)
660 vty_out (vty, "initialized graph%s", VTY_NEWLINE);
97c45dae 661}