]> git.ipfire.org Git - people/ms/rstp.git/blame - rstplib/cli.c
Track and cache bridge and port MAC addresses.
[people/ms/rstp.git] / rstplib / cli.c
CommitLineData
ad02a0eb
SH
1/************************************************************************
2 * RSTP library - Rapid Spanning Tree (802.1t, 802.1w)
3 * Copyright (C) 2001-2003 Optical Access
4 * Author: Alex Rozin
5 *
6 * This file is part of RSTP library.
7 *
8 * RSTP library is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by the
10 * Free Software Foundation; version 2.1
11 *
12 * RSTP library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with RSTP library; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 **********************************************************************/
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <time.h>
26#include <string.h>
27#include <sys/wait.h>
28#include <sys/time.h>
29#include <sys/types.h>
30#include <signal.h>
31#include <unistd.h>
32#include <errno.h>
33#include <readline/readline.h>
34#include <readline/history.h>
35
36#include "cli.h"
37
38static CMD_DSCR_T* TheList = 0;
39
40static int
41cli_parse_parms (const char* line, int skip_words, char** argv)
42{
43 static char pool[MAX_CLI_BUFF];
44 register char* ptr;
45 register int argc = 0, iii;
46
47 ptr = strchr (line, '\n');
48 if (ptr) *ptr = '\0';
49 memcpy (pool, line, MAX_CLI_BUFF);
50 pool[MAX_CLI_BUFF - 1] = '\0';
51
52 for (iii = 0; iii < MAXPARAMNUM; iii++) {
53 ptr = strtok (iii ? NULL : pool, "\t\n ");
54 if (! ptr) break;
55 if (skip_words-- <= 0) {
56 /* printf ("\targv[%d]='%s' skip_words=%d\n", argc, ptr, skip_words); */
57 argv[argc++] = ptr;
58 } else {
59 /* printf ("\tskip '%s' skip_words now %d\n", ptr, skip_words); */
60 }
61 }
62
63 return argc;
64}
65
66int cli_count_words (char* line)
67{
68 static char pool[MAX_CLI_BUFF];
69 register char* ptr = NULL;
70 register int cnt;
71
72 ptr = strchr (line, '\n');
73 if (ptr) *ptr = '\0';
74 strncpy (pool, line, MAX_CLI_BUFF);
75 pool[MAX_CLI_BUFF - 1] = '\0';
76
77 for (cnt = 0;; cnt++) {
78 ptr = strtok (cnt ? NULL : pool, "\t\n ");
79 if (! ptr) {
80 break;
81 }
82 }
83
84 return cnt - 1;
85}
86
87void cli_register_language (const CMD_DSCR_T* cmd_list)
88{
89 TheList = ( CMD_DSCR_T*) cmd_list;
90}
91
92static int help_on_param (int iii, CMD_PAR_DSCR_T* par, int cry_on_empty)
93{
94 register int kkk;
95
96 if (! par->param_help) {
97 if (cry_on_empty)
98 printf ("absent parameter #%d\n", iii);
99 return 1;
100 }
101
102 printf (" arg%2d: %s", iii + 1, par->param_help);
103 switch (par->param_type) {
104 case CMD_PAR_NUMBER:
105 printf ("; integer in [%ld, %ld]",par->number_limits.min,par->number_limits.max);
106 break;
107 case CMD_PAR_STRING:
108 break;
109 case CMD_PAR_BOOL_YN:
110 case CMD_PAR_ENUM:
111 printf ("\n");
112 for (kkk = 0; par->string_selector[kkk].string_value; kkk++) {
113 printf (" %-20s\t%s\n",
114 par->string_selector[kkk].string_value,
115 par->string_selector[kkk].string_help);
116 }
117 break;
118 }
119
120 if (par->default_value) {
121 printf (" default '%s'", par->default_value);
122 }
123 printf (" \n");
124 return 0;
125}
126
127void help_on_command (CMD_DSCR_T* reg, char brief)
128{
129 register CMD_PAR_DSCR_T* par;
130 register int iii;
131
132 if (brief) {
133 printf ("%-20s %s\n", reg->cmd_name, reg->cmd_help);
134 return;
135 }
136 printf ("%s: %s\n", reg->cmd_name, reg->cmd_help);
137 for (iii = 0; iii < 2 + strlen (reg->cmd_name) + strlen (reg->cmd_help); iii++)
138 printf ("-");
139
140 printf ("\n");
141 if (reg->param->param_help)
142 printf (" arguments:\n ----------\n");
143 for (iii = 0, par = reg->param; ; iii++, par++) {
144 if (! par->param_help) break;
145 help_on_param (iii + 1, par, 0);
146 }
147 if (reg->param->param_help)
148 printf ("\n");
149}
150
151static int cli_dummy (int argc, char** argv)
152{
153 return 0;
154}
155
156static CMD_DSCR_T stdcmd[] = {
157 THE_COMMAND("exit", "'shutdown'")
158 THE_FUNC(cli_dummy)
159
160 THE_COMMAND("?", "help")
161 THE_FUNC(cli_dummy)
162
163 END_OF_LANG
164};
165
166static char* get_commnad_name (int list_index)
167{
168 register CMD_DSCR_T* reg;
169
170 if (list_index < 2 && list_index >= 0) {
171 return stdcmd[list_index].cmd_name;
172 }
173
174 list_index -= 2;
175 reg = TheList + list_index;
176 if (reg->cmd_name && *reg->cmd_name)
177 return reg->cmd_name;
178 return NULL;
179}
180
181static int find_command (const char* line, char forHelp, CMD_DSCR_T **reg_ptr)
182{
183 register CMD_DSCR_T* reg;
184 register int iii = 0;
185
186 for (reg = stdcmd; reg->cmd_name; reg++) {
187 if (! strncasecmp (reg->cmd_name, line, strlen (line))) {
188 *reg_ptr = reg; iii++;
189 if (forHelp)
190 help_on_command (reg, 1);
191 }
192 }
193
194 for (reg = TheList; reg->cmd_name; reg++) {
195 if (! strncasecmp (reg->cmd_name, line, strlen (line))) {
196 *reg_ptr = reg; iii++;
197 if (forHelp)
198 help_on_command (reg, 1);
199 }
200 }
201
202 return iii;
203}
204
205void usage (void)
206{
207 CMD_DSCR_T* reg;
208
209 if (! TheList) {
210 printf ("Sorry, command list hasn't been registered\n");
211 return;
212 }
213
214 printf ("List of possible commands:\n");
215 for (reg = TheList; reg->cmd_name; reg++) {
216 help_on_command (reg, 1);
217 }
218
219 printf ("'standard' commands:\n");
220 for (reg = stdcmd; reg->cmd_name; reg++) {
221 help_on_command (reg, 1);
222 }
223}
224
225void cli_debug_dump_args (char* title, int argc, char** argv)
226{
227 int iii;
228 printf ("in %s argc=%d\n", title, argc);
229 for (iii = 0; iii < argc; iii++)
230 printf ("\targv[%d]='%s'\n", iii, argv[iii]);
231 printf ("\n");
232}
233
234
235static int count_command_paramms (CMD_DSCR_T* reg)
236{
237 register int iii;
238 register CMD_PAR_DSCR_T* par;
239
240 for (iii = 0, par = reg->param; ; iii++, par++) {
241 if (! par->param_help) break;
242 }
243 return iii;
244}
245
246static void
247cli_help_brosed_line (int argc, char** argv, const char* line)
248{
249 char pool[MAX_CLI_BUFF];
250 CMD_DSCR_T* reg;
251 int iii, nf;
252
253 printf ("\n");
254#if 0
255 cli_debug_dump_args ("cli_help_brosed_line", argc, argv);
256#endif
257
258 memset (pool, 0, MAX_CLI_BUFF);
259 for (iii = 0; iii < argc; iii++) {
260 if (iii) strcat (pool, " ");
261 strcat (pool, argv[iii]);
262 nf = find_command (pool, 0, &reg);
263 if (1 == nf) {
264 nf = count_command_paramms (reg);
265 iii++;
266#if 0
267 printf ("iii=%d argc=%d nf=%d\n", iii, argc, nf);
268#endif
269 nf = strlen (line);
270 if (nf && ' ' == line[nf - 1])
271 argc++;
272 if (iii < argc) {
273 iii = argc - iii - 1;
274 if (! help_on_param (iii + 1, reg->param + iii, 1)) {
275 return;
276 }
277 }
278 help_on_command (reg, 0);
279 return;
280 } else if (! nf) {
281 printf ("\nunknown <%s>\n", pool);
282 usage ();
283 return;
284 }
285 }
286 find_command (pool, 1, &reg);
287}
288
289void cli_help (int argc, char** argv, const char* line)
290{
291#if 0
292 cli_debug_dump_args ("cli_help", argc, argv);
293#endif
294 if (argc > 1)
295 cli_help_brosed_line (argc - 1, argv + 1, line);
296 else
297 usage ();
298}
299
300static void cli_set_defaults (CMD_DSCR_T* reg, char** argv)
301{
302 register int iii;
303 register CMD_PAR_DSCR_T* par;
304
305 for (iii = 0, par = reg->param; ; iii++, par++) {
306 if (! par->param_help) break;
307 argv[iii + 1] = par->default_value;
308 }
309}
310
311static int cli_call_callback (CMD_DSCR_T* reg, const char* line, int* argc, char** argv)
312{
313 int cnt;
314
315 if (reg->clbk) {
316 cnt = cli_count_words (reg->cmd_name);
317 /* printf ("cli_count_words returned %d\n", cnt); */
318 cli_set_defaults (reg, argv);
319 *argc = cli_parse_parms (line, cnt, argv);
320 return (*reg->clbk) (*argc, argv);
321 }
322 printf ("<Empty command !>\n");
323 return 0;
324}
325
326int cli_execute_command (const char* line)
327{
328 CMD_DSCR_T* reg;
329 int argc, nf;
330 char *argv[MAXPARAMNUM];
331
332 if ('\n' == *line || ! *line) return 0;
333
334 /* check "common commands" */
335 if ('q' == *line || ! strncasecmp ("ex", line, 2)) {
336 return 4;
337 }
338
339 if ('?' == *line || 'h' == *line) {
340 argc = cli_parse_parms (line, 0, argv);
341 cli_help (argc, argv, line);
342 return 0;
343 }
344
345 if (! TheList) {
346 printf ("Sorry, command list hasn't been registered\n");
347 return -11;
348 }
349
350 for (reg = TheList; reg->cmd_name; reg++) {
351 if (! strncasecmp (reg->cmd_name, line, strlen (reg->cmd_name))) {
352 return cli_call_callback (reg, line, &argc, argv);
353 }
354 }
355
356 nf = find_command (line, 0, &reg);
357 if (1 == nf)
358 return cli_call_callback (reg, line, &argc, argv);
359
360 printf ("unknown command: <%s>", line);
361 usage ();
362 return 0;
363}
364
365extern char shutdown_flag;
366
367char read_cli (void)
368{
369 if (!rl_line_buffer) {
370 return 1;
371 }
372
373 if (*rl_line_buffer != 0) {
374 add_history (rl_line_buffer);
375 /** printf ("\n try to call <%s>\n", rl_line_buffer); **/
376
377 if (0 != cli_execute_command (rl_line_buffer)) {
378 printf("Goodbye, I'm a gonner\n");
379 rl_callback_handler_remove ();
380 return 2;
381 }
382 }
383
384 return 0;
385}
386
387#ifdef OLD_READLINE
388void rl_read_cli (void)
389#else
390void rl_read_cli (char *str)
391#endif
392{
393 shutdown_flag |= read_cli ();
394 rl_callback_handler_install (get_prompt (), rl_read_cli);
395}
396
397char* UT_sprint_time_stamp (void)
398{
399 time_t clock;
400 struct tm *local_tm;
401 static char time_str[20];
402
403 time(&clock);
404 local_tm = localtime (&clock);
405 strftime(time_str, 20 - 1, "%H:%M:%S", local_tm);
406 return time_str;
407}
408
409int complete_status;
410
411/* To disable readline's filename completion */
412#ifdef OLD_READLINE
413int cli_completion_entry_fucntion (int ignore, int invoking_key)
414{ return 0; }
415#else
416char* cli_completion_entry_fucntion (const char *str, int ignore)
417{ return NULL; }
418#endif
419
420#ifdef OLD_READLINE
421char* command_generator (char* text, int state)
422#else
423char* command_generator (const char* text, int state)
424#endif
425{
426 static int list_index, len;
427 char *name, dlen;
428
429/****
430 printf (" state=%d list_index=%d rl_line_buffer'%s' text'%s'\n",
431 state, list_index, rl_line_buffer, text);
432****/
433
434 dlen = strlen (rl_line_buffer) - strlen (text);
435 if (! state) {
436 list_index = 0;
437 len = strlen (rl_line_buffer);
438/****
439 printf ("\tlen=%d text<%s>\n", len, text);
440****/
441 }
442
443 for (;;) {
444 name = get_commnad_name (list_index);
445 if (! name) break;
446 list_index++;
447 if (! strncmp (rl_line_buffer, name, len)) {
448/****
449 printf (" find <%s> => return '%s'\n", name, name + dlen);
450****/
451 return strdup (name + dlen);
452 }
453 }
454
455 return ((char *)NULL);
456}
457
458#ifdef OLD_READLINE
459int cli_inline_help (void)
460#else
461int cli_inline_help (int a, int b)
462#endif
463{
464 int argc;
465 char *argv[MAXPARAMNUM];
466
467 if (! *rl_line_buffer) {
468 usage ();
469 } else {
470 argc = cli_parse_parms (rl_line_buffer, 0, argv);
471 cli_help_brosed_line (argc, argv, (const char*) rl_line_buffer);
472 }
473
474 rl_on_new_line();
475 return 0;
476
477}
478
479char **
480cli_private_completion (char *text, int start, int end)
481{
482 char **matches = NULL;
483
484#ifdef OLD_READLINE
485 matches = completion_matches (text, command_generator);
486#else
487 matches = rl_completion_matches (text, command_generator);
488#endif
489
490 return matches;
491}
492
493void rl_init ()
494{
495 /* disable completion */
496#if 0
497 rl_bind_key ('\t', rl_insert);
498#else
499 rl_callback_handler_install (get_prompt (), rl_read_cli);
500 rl_bind_key ('?', cli_inline_help);
501 rl_completion_entry_function = cli_completion_entry_fucntion;
502 rl_attempted_completion_function = (CPPFunction *)cli_private_completion;
503 rl_completion_append_character = '\0';
504#endif
505}
506
507void rl_shutdown ()
508{
509 rl_initialize ();
510}
511