]>
Commit | Line | Data |
---|---|---|
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 | ||
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, ®); | |
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, ®); | |
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, ®); | |
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 |