]> git.ipfire.org Git - people/ms/rstp.git/blob - rstplib/cli.c
Fix rstpctl usage
[people/ms/rstp.git] / rstplib / cli.c
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
38 static CMD_DSCR_T* TheList = 0;
39
40 static int
41 cli_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
66 int 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
87 void cli_register_language (const CMD_DSCR_T* cmd_list)
88 {
89 TheList = ( CMD_DSCR_T*) cmd_list;
90 }
91
92 static 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
127 void 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
151 static int cli_dummy (int argc, char** argv)
152 {
153 return 0;
154 }
155
156 static 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
166 static 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
181 static 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
205 void 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
225 void 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
235 static 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
246 static void
247 cli_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
289 void 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
300 static 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
311 static 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
326 int 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
365 extern char shutdown_flag;
366
367 char 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
388 void rl_read_cli (void)
389 #else
390 void 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
397 char* 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
409 int complete_status;
410
411 /* To disable readline's filename completion */
412 #ifdef OLD_READLINE
413 int cli_completion_entry_fucntion (int ignore, int invoking_key)
414 { return 0; }
415 #else
416 char* cli_completion_entry_fucntion (const char *str, int ignore)
417 { return NULL; }
418 #endif
419
420 #ifdef OLD_READLINE
421 char* command_generator (char* text, int state)
422 #else
423 char* 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
459 int cli_inline_help (void)
460 #else
461 int 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
479 char **
480 cli_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
493 void 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
507 void rl_shutdown ()
508 {
509 rl_initialize ();
510 }
511