1 /*
2 * Simulator of microcontrollers (cmd.src/command.cc)
3 *
4 * Copyright (C) 2002,02 Drotos Daniel, Talker Bt.
5 *
6 * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
7 *
8 */
9
10 /* This file is part of microcontroller simulator: ucsim.
11
12 UCSIM is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 UCSIM is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with UCSIM; see the file COPYING. If not, write to the Free
24 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 02111-1307, USA. */
26 /*@1@*/
27
28 #include "ddconfig.h"
29
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include "i_string.h"
33
34 // prj
35 #include "fiocl.h"
36 #include "utils.h"
37 #include "appcl.h"
38
39 // local, cmd
40 #include "commandcl.h"
41 #include "argcl.h"
42
43
44 /*
45 * Command line
46 *____________________________________________________________________________
47 */
48
cl_cmdline(class cl_app * the_app,char * acmd,class cl_console_base * acon)49 cl_cmdline::cl_cmdline(class cl_app *the_app,
50 char *acmd, class cl_console_base *acon):
51 cl_base()
52 {
53 app= the_app;
54 cmd= strdup(acmd);
55 params= new cl_list(2, 2, "command line params");
56 tokens= new cl_ustrings(2, 2, "command line tokens");
57 set_name(0);
58 matched_syntax= 0;
59 con= acon;
60 }
61
~cl_cmdline(void)62 cl_cmdline::~cl_cmdline(void)
63 {
64 if (cmd)
65 free(cmd);
66 delete params;
67 delete tokens;
68 }
69
70 int
init(void)71 cl_cmdline::init(void)
72 {
73 rest= NULL;
74 params->free_all();
75 tokens->free_all();
76 split();
77 return(0);
78 }
79
80 char *
skip_delims(char * start)81 cl_cmdline::skip_delims(char *start)
82 {
83 while (*start &&
84 strchr(" \t\v\r,", *start))
85 start++;
86 return(start);
87 }
88
89 int
split(void)90 cl_cmdline::split(void)
91 {
92 //class cl_sim *sim;
93 char *start= cmd;
94 int i;//, j;
95 class cl_cmd_arg *arg;
96
97 set_name("\n");
98 if (!cmd ||
99 !*cmd)
100 return(0);
101 start+= strspn(start, " \t\v\r,");
102 if (!start)
103 return 0;
104 set_name(0);
105 if (*start == '\n')
106 {
107 // never, as \n stripped by readline
108 set_name("\n");
109 return(0);
110 }
111 else if (*start == '#')
112 return *start= 0;
113 else if (*start == ';')
114 {
115 rest= start+1;
116 *start= 0;
117 return 0;
118 }
119 if (!*start)
120 return(0);
121 // start now points to first word
122 i= strcspn(start, " \t\v\r,;#");
123 // i should be at end of it
124 if (i)
125 {
126 if (*start == '#')
127 return set_name("\n"), *start= 0;
128 char *n= (char*)malloc(i+1);
129 strncpy(n, start, i);
130 n[i]= '\0';
131 set_name(n);
132 free(n);
133 }
134 start+= i;
135 start= skip_delims(start);
136 while (*start)
137 {
138 char *end= start, *param_str;
139 if (*start == '#')
140 return *start= '\0';
141 else if (*start == ';')
142 {
143 rest= start+1;
144 *start= 0;
145 return 0;
146 }
147 else if (*start == '"')
148 split_out_string(&start, &end);
149 else if (*start == '>')
150 split_out_output_redirection(&start, &end);
151 else
152 {
153 char *dot;
154 i= strcspn(start, " \t\v\r,#;");
155 end= start+i;
156 param_str= (char *)malloc(i+1);
157 strncpy(param_str, start, i);
158 param_str[i]= '\0';
159 tokens->add(strdup(param_str));
160 if ((dot= strchr(param_str, '.')) != NULL)
161 split_out_bit(dot, param_str);
162 else if ((dot= strchr(param_str, '[')) != NULL)
163 split_out_array(dot, param_str);
164 else if (param_str[0] == '0' && param_str[1] == 'b')
165 {
166 long n= 0;
167 for (int i= 2; param_str[i] == '0' || param_str[i] == '1'; i++)
168 n = (n << 1) | (param_str[i] == '0' ? 0 : 1);
169 params->add(arg= new cl_cmd_int_arg(n));
170 arg->init();
171 }
172 else if (strchr("0123456789-+", *param_str) != NULL)
173 {
174 // number
175 params->add(arg= new cl_cmd_int_arg((long)
176 strtol(param_str, 0, 0)));
177 arg->init();
178 }
179 else
180 {
181 // symbol
182 params->add(arg= new cl_cmd_sym_arg(param_str));
183 arg->init();
184 }
185 free(param_str);
186 }
187 start= end;
188 start= skip_delims(start);
189 }
190 return(0);
191 }
192
193 void
split_out_string(char ** _start,char ** _end)194 cl_cmdline::split_out_string(char **_start, char **_end)
195 {
196 char *start= *_start, *end;
197 start++;
198 end= start;
199 while (*end &&
200 *end != '"')
201 {
202 if (*end == '\\')
203 {
204 end++;
205 if (*end)
206 end++;
207 }
208 else
209 end++;
210 }
211 if (*end == '"')
212 end--;
213 else
214 con->dd_printf("Unterminated string\n");
215 char *param_str= (char *)malloc(end-start+2);
216 strncpy(param_str, start, 1+end-start);
217 param_str[1+end-start]= '\0';
218 tokens->add(strdup(param_str));
219 class cl_cmd_arg *arg;
220 params->add(arg= new cl_cmd_str_arg(param_str));
221 arg->init();
222 free(param_str);
223 if (*end)
224 end++;
225 if (*end == '"')
226 end++;
227 *_start= start;
228 *_end= end;
229 }
230
231 void
split_out_output_redirection(char ** _start,char ** _end)232 cl_cmdline::split_out_output_redirection(char **_start, char **_end)
233 {
234 char *start= *_start, *end/*= *_end*/;
235 int i;
236 char mode[2];
237
238 mode[0]= 'w';
239 mode[1]= '\0';
240 start++;
241 i= strcspn(start, " \t\v\r,");
242 end= start+i;
243 char *param_str= (char *)malloc(i+1);
244 char *n= param_str;
245 strncpy(param_str, start, i);
246 param_str[i]= '\0';
247 if (param_str &&
248 param_str[0] == '>')
249 {
250 n++;
251 mode[0]= 'a';
252 }
253 tokens->add(strdup(n));
254 con->redirect(n, mode);
255 free(param_str);
256 *_start= start;
257 *_end= end;
258 }
259
260 void
split_out_bit(char * dot,char * param_str)261 cl_cmdline::split_out_bit(char *dot, char *param_str)
262 {
263 class cl_cmd_arg *sfr, *bit;
264
265 *dot= '\0';
266 dot++;
267 if (strchr("0123456789", *param_str) != NULL)
268 {
269 sfr= new cl_cmd_int_arg((long)strtol(param_str, 0, 0));
270 sfr->init();
271 }
272 else
273 {
274 sfr= new cl_cmd_sym_arg(param_str);
275 sfr->init();
276 }
277 if (*dot == '\0')
278 {
279 bit= 0;
280 con->dd_printf("Uncomplete bit address\n");
281 delete sfr;
282 }
283 else
284 {
285 if (strchr("0123456789", *dot) != NULL)
286 {
287 bit= new cl_cmd_int_arg((long)strtol(dot, 0, 0));
288 bit->init();
289 }
290 else
291 {
292 bit= new cl_cmd_sym_arg(dot);
293 bit->init();
294 }
295 class cl_cmd_arg *arg;
296 params->add(arg= new cl_cmd_bit_arg(sfr, bit));
297 arg->init();
298 }
299 }
300
301 void
split_out_array(char * dot,char * param_str)302 cl_cmdline::split_out_array(char *dot, char *param_str)
303 {
304 class cl_cmd_arg *aname, *aindex;
305
306 *dot= '\0';
307 dot++;
308 if (strchr("0123456789", *param_str) != NULL)
309 {
310 aname= new cl_cmd_int_arg((long)strtol(param_str, 0, 0));
311 aname->init();
312 }
313 else
314 {
315 aname= new cl_cmd_sym_arg(param_str);
316 aname->init();
317 }
318 if (*dot == '\0')
319 {
320 aname= 0;
321 con->dd_printf("Uncomplete array\n");
322 }
323 else
324 {
325 char *p;
326 p= dot + strlen(dot) - 1;
327 while (p > dot &&
328 *p != ']')
329 {
330 *p= '\0';
331 p--;
332 }
333 if (*p == ']')
334 *p= '\0';
335 if (strlen(dot) == 0)
336 {
337 con->dd_printf("Uncomplete array index\n");
338 delete aname;
339 }
340 else
341 {
342 if (strchr("0123456789", *dot) != NULL)
343 {
344 aindex= new cl_cmd_int_arg((long)strtol(dot, 0, 0));
345 aindex->init();
346 }
347 else
348 {
349 aindex= new cl_cmd_sym_arg(dot);
350 aindex->init();
351 }
352 class cl_cmd_arg *arg;
353 params->add(arg= new cl_cmd_array_arg(aname, aindex));
354 arg->init();
355 }
356 }
357 }
358
359 int
shift(void)360 cl_cmdline::shift(void)
361 {
362 char *s= skip_delims(cmd);
363
364 params->free_all();
365 tokens->free_all();
366 set_name(0);
367 if (s && *s)
368 {
369 while (*s &&
370 strchr(" \t\v\r,;#", *s) == NULL)
371 s++;
372 s= skip_delims(s);
373 char *p= strdup(s), *r= rest?strdup(rest):NULL;
374 free(cmd);
375 cmd= p;
376 rest= r;
377 //params= new cl_list(2, 2, "params");
378 split();
379 if (strcmp(get_name(), "\n") == 0)
380 set_name(0);
381 }
382 return(have_real_name());
383 }
384
385 int
repeat(void)386 cl_cmdline::repeat(void)
387 {
388 const char *n;
389 return((n= get_name()) &&
390 *n == '\n');
391 }
392
393 class cl_cmd_arg *
param(int num)394 cl_cmdline::param(int num)
395 {
396 if (num >= params->count)
397 return(0);
398 return((class cl_cmd_arg *)(params->at(num)));
399 }
400
401 void
insert_param(int pos,class cl_cmd_arg * param)402 cl_cmdline::insert_param(int pos, class cl_cmd_arg *param)
403 {
404 if (pos >= params->count)
405 params->add(param);
406 else
407 params->add_at(pos, param);
408 }
409
410 bool
syntax_match(class cl_uc * uc,const char * syntax)411 cl_cmdline::syntax_match(class cl_uc *uc, const char *syntax)
412 {
413 if (!syntax)
414 return(false);
415 if (!*syntax &&
416 !params->count)
417 {
418 matched_syntax= syntax;
419 return(true);
420 }
421 if (!params->count)
422 return(false);
423 //printf("syntax %s?\n",syntax);
424 const char *p= syntax;
425 int iparam= 0;
426 class cl_cmd_arg *parm= (class cl_cmd_arg *)(params->at(iparam));
427 while (*p &&
428 parm)
429 {
430 //printf("***Checking %s as %c\n",parm->get_svalue(),*p);
431 if (uc)
432 {
433 switch (*p)
434 {
435 case SY_ADDR:
436 if (!parm->as_address(uc))
437 return(false);
438 //printf("ADDRESS match %lx\n",parm->value.address);
439 break;
440 case SY_MEMORY:
441 if (!parm->as_memory(uc))
442 return(false);
443 //printf("MEMORY match %s\n",parm->value.memory->class_name);
444 break;
445 case SY_BIT:
446 if (!parm->as_bit(uc))
447 return(false);
448 break;
449 case SY_HW:
450 if (!parm->as_hw(uc))
451 return(false);
452 break;
453 case SY_CELL:
454 if (!parm->as_cell(uc))
455 return false;
456 break;
457 }
458 }
459 //else
460 {
461 switch (*p)
462 {
463 case SY_ADDR: case SY_MEMORY: case SY_BIT: break;
464 case SY_NUMBER:
465 if (!parm->as_number())
466 return(false);
467 break;
468 case SY_DATA:
469 if (!parm->as_data())
470 return(false);
471 break;
472 case SY_STRING:
473 if (!parm->as_string())
474 return(false);
475 break;
476 case SY_DATALIST:
477 if (!set_data_list(parm, &iparam))
478 return(false);
479 break;
480 //default: return(false);
481 }
482 }
483 p++;
484 iparam++;
485 if (iparam < params->count)
486 parm= (class cl_cmd_arg *)(params->at(iparam));
487 else
488 parm= 0;
489 }
490 if (!*p &&
491 !parm)
492 {
493 matched_syntax= syntax;
494 return(true);
495 }
496 return(false);
497 }
498
499 bool
set_data_list(class cl_cmd_arg * parm,int * iparm)500 cl_cmdline::set_data_list(class cl_cmd_arg *parm, int *iparm)
501 {
502 class cl_cmd_arg *next_parm;
503 int len, i, j;
504 t_mem *array;
505
506 len= 0;
507 array= 0;
508 for (i= *iparm, next_parm= param(i); next_parm; i++, next_parm= param(i))
509 {
510 if (next_parm->is_string())
511 {
512 int l;
513 char *s;
514 //s= proc_escape(next_parm->get_svalue(), &l);
515 if (!next_parm->as_string())
516 continue;
517 s= next_parm->value.string.string;
518 l= next_parm->value.string.len;
519 if (!array)
520 array= (t_mem*)malloc(sizeof(t_mem)*l);
521 else
522 array= (t_mem*)realloc(array, sizeof(t_mem)*(l+len));
523 for (j= 0; j < l; j++)
524 {
525 array[len]= s[j];
526 len++;
527 }
528 //if (s)
529 //free(s);
530 }
531 else
532 {
533 if (!next_parm->as_data())
534 {
535 if (array)
536 free(array);
537 return(false);
538 }
539 if (!array)
540 array= (t_mem*)malloc(sizeof(t_mem));
541 else
542 array= (t_mem*)realloc(array, sizeof(t_mem)*(1+len));
543 array[len]= next_parm->value.data;
544 len++;
545 }
546 }
547 *iparm= i;
548 parm->value.data_list.array= array;
549 parm->value.data_list.len= len;
550 return(true);
551 }
552
553 bool
restart_at_rest(void)554 cl_cmdline::restart_at_rest(void)
555 {
556 char *newcmd;
557 if ((rest == NULL) ||
558 (*rest == 0))
559 {
560 return false;
561 }
562 newcmd= strdup(rest);
563 if (cmd)
564 free(cmd);
565 cmd= newcmd;
566 return true;
567 }
568
569
570 /*
571 * Command
572 *____________________________________________________________________________
573 */
574
cl_cmd(enum cmd_operate_on op_on,const char * aname,int can_rep)575 cl_cmd::cl_cmd(enum cmd_operate_on op_on,
576 const char *aname,
577 int can_rep):
578 cl_base()
579 {
580 operate_on= op_on;
581 names= new cl_strings(1, 1, "names of a command");
582 names->add(aname?strdup(aname):strdup("unknown"));
583 can_repeat= can_rep;
584 usage_help= 0;
585 short_help= 0;//short_hlp;//?strdup(short_hlp):NULL;
586 long_help= 0;//long_hlp;//?strdup(long_hlp):NULL;
587 }
588
589 /*cl_cmd::cl_cmd(class cl_sim *asim):
590 cl_base()
591 {
592 sim= asim;
593 name= short_help= long_help= 0;
594 can_repeat= 0;
595 }*/
596
597 void
set_help(const char * usage_hlp,const char * short_hlp,const char * long_hlp)598 cl_cmd::set_help(const char *usage_hlp, const char *short_hlp, const char *long_hlp)
599 {
600 usage_help= usage_hlp;
601 short_help= short_hlp;
602 long_help= long_hlp;
603 }
604
~cl_cmd(void)605 cl_cmd::~cl_cmd(void)
606 {
607 delete names;
608 //if (short_help) free((void*)short_help);
609 //if (long_help) free((void*)long_help);
610 }
611
612 void
add_name(const char * nam)613 cl_cmd::add_name(const char *nam)
614 {
615 if (nam)
616 names->add(strdup(nam));
617 }
618
619 int
name_match(const char * aname,int strict)620 cl_cmd::name_match(const char *aname, int strict)
621 {
622 int i;
623
624 if (names->count == 0 &&
625 !aname)
626 return(1);
627 if (!aname)
628 return(0);
629 if (strict)
630 {
631 for (i= 0; i < names->count; i++)
632 {
633 char *n= (char*)(names->at(i));
634 if (strcmp(aname, n) == 0)
635 return(1);
636 }
637 }
638 else
639 {
640 for (i= 0; i < names->count; i++)
641 {
642 char *n= (char*)(names->at(i));
643 if (strstr(n, aname) == n)
644 return(1);
645 }
646 }
647 return(0);
648 }
649
650 int
name_match(class cl_cmdline * cmdline,int strict)651 cl_cmd::name_match(class cl_cmdline *cmdline, int strict)
652 {
653 return(name_match(cmdline->get_name(), strict));
654 }
655
656 int
syntax_ok(class cl_cmdline * cmdline)657 cl_cmd::syntax_ok(class cl_cmdline *cmdline)
658 {
659 return(1);
660 }
661
662 int
work(class cl_app * app,class cl_cmdline * cmdline,class cl_console_base * con)663 cl_cmd::work(class cl_app *app,
664 class cl_cmdline *cmdline, class cl_console_base *con)
665 {
666 if (!syntax_ok(cmdline))
667 return(0);
668 class cl_sim *sim= app->get_sim();
669 class cl_uc *uc= 0;
670 if (sim)
671 uc= sim->uc;
672 switch (operate_on)
673 {
674 case operate_on_app:
675 if (!app)
676 {
677 con->dd_printf("There is no application to work on!\n");
678 return(false);
679 }
680 return(do_work(app, cmdline, con));
681 case operate_on_sim:
682 if (!sim)
683 {
684 con->dd_printf("There is no simulator to work on!\n");
685 return(false);
686 }
687 return(do_work(sim, cmdline, con));
688 case operate_on_uc:
689 if (!sim)
690 {
691 con->dd_printf("There is no microcontroller to work on!\n");
692 return(false);
693 }
694 return(do_work(uc, cmdline, con));
695 default:
696 return(do_work(cmdline, con));
697 }
698 }
699
700 int
do_work(class cl_cmdline * cmdline,class cl_console_base * con)701 cl_cmd::do_work(class cl_cmdline *cmdline, class cl_console_base *con)
702 {
703 con->dd_printf("Command \"%s\" does nothing.\n",
704 (char*)(names->at(0)));
705 return(0);
706 }
707
708 int
do_work(class cl_app * app,class cl_cmdline * cmdline,class cl_console_base * con)709 cl_cmd::do_work(class cl_app *app,
710 class cl_cmdline *cmdline, class cl_console_base *con)
711 {
712 con->dd_printf("Command \"%s\" does nothing on application.\n",
713 (char*)(names->at(0)));
714 return(0);
715 }
716
717 int
do_work(class cl_sim * sim,class cl_cmdline * cmdline,class cl_console_base * con)718 cl_cmd::do_work(class cl_sim *sim,
719 class cl_cmdline *cmdline, class cl_console_base *con)
720 {
721 con->dd_printf("Command \"%s\" does nothing on simulator.\n",
722 (char*)(names->at(0)));
723 return(0);
724 }
725
726 int
do_work(class cl_uc * uc,class cl_cmdline * cmdline,class cl_console_base * con)727 cl_cmd::do_work(class cl_uc *uc,
728 class cl_cmdline *cmdline, class cl_console_base *con)
729 {
730 con->dd_printf("Command \"%s\" does nothing on microcontroller.\n",
731 (char*)(names->at(0)));
732 return(0);
733 }
734
735 void
print_short(class cl_console_base * con)736 cl_cmd::print_short(class cl_console_base *con)
737 {
738 int l= usage_help.len();
739
740 if (!con)
741 return;
742
743 if (usage_help.nempty())
744 con->dd_printf("%s", (char*)usage_help);
745 if (l > 19)
746 {
747 con->dd_printf("\n");
748 l=0;
749 }
750 while (l < 20)
751 {
752 con->dd_printf(" ");
753 l++;
754 }
755 if (short_help.nempty())
756 {
757 con->dd_printf("%s", (char*)short_help);
758 }
759 else
760 con->dd_printf("%s", (char*)(names->at(0)));
761 con->dd_printf("\n");
762 }
763
764 void
syntax_error(class cl_console_base * con)765 cl_cmd::syntax_error(class cl_console_base *con)
766 {
767 if (con)
768 {
769 if (short_help.nempty())
770 print_short(con);
771 else
772 con->dd_printf("Error: wrong syntax\n");
773 }
774 }
775
776 /*
777 * Set of commands
778 *____________________________________________________________________________
779 */
780
cl_cmdset(void)781 cl_cmdset::cl_cmdset(void):
782 cl_list(5, 5, "cmdset")
783 {
784 //sim= 0;
785 //last_command= 0;
786 }
787
788 /*cl_cmdset::cl_cmdset(class cl_sim *asim):
789 cl_list(5, 5)
790 {
791 sim= asim;
792 last_command= 0;
793 }*/
794
795 class cl_cmd *
get_cmd(class cl_cmdline * cmdline,bool accept_last)796 cl_cmdset::get_cmd(class cl_cmdline *cmdline, bool accept_last)
797 {
798 int i;
799
800 // exact match
801 for (i= 0; i < count; i++)
802 {
803 class cl_cmd *c= (class cl_cmd *)at(i);
804 if (c->name_match(cmdline, 1))
805 return(c);
806 }
807 // not exact match
808 class cl_cmd *c_matched= 0;
809 for (i= 0; i < count; i++)
810 {
811 class cl_cmd *c= (class cl_cmd *)at(i);
812 if (c->name_match(cmdline, 0))
813 {
814 if (!c_matched)
815 c_matched= c;
816 else
817 return(0);
818 }
819 }
820 return(c_matched);
821 //return(0);
822 }
823
824 class cl_cmd *
get_cmd(const char * cmd_name)825 cl_cmdset::get_cmd(const char *cmd_name)
826 {
827 int i;
828
829 for (i= 0; i < count; i++)
830 {
831 class cl_cmd *c= (class cl_cmd *)at(i);
832 if (c->name_match(cmd_name, 1))
833 return(c);
834 }
835 return(0);
836 }
837
838 void
del(char * nam)839 cl_cmdset::del(char *nam)
840 {
841 int i;
842
843 if (!nam)
844 return;
845 for (i= 0; i < count; i++)
846 {
847 class cl_cmd *cmd= (class cl_cmd *)(at(i));
848 if (cmd->name_match(nam, 1))
849 free_at(i);
850 }
851 }
852
853 void
replace(char * nam,class cl_cmd * cmd)854 cl_cmdset::replace(char *nam, class cl_cmd *cmd)
855 {
856 int i;
857
858 if (!nam)
859 return;
860 for (i= 0; i < count; i++)
861 {
862 class cl_cmd *c= (class cl_cmd *)(at(i));
863 if (c->name_match(nam, 1))
864 {
865 delete c;
866 put_at(i, cmd);
867 }
868 }
869 }
870
871
872 /*
873 * Composed command: subset of commands
874 *____________________________________________________________________________
875 */
876
cl_super_cmd(const char * aname,int can_rep,class cl_cmdset * acommands)877 cl_super_cmd::cl_super_cmd(const char *aname,
878 int can_rep,
879 class cl_cmdset *acommands):
880 cl_cmd(operate_on_none, aname, can_rep)
881 {
882 commands= acommands;
883 }
884
~cl_super_cmd(void)885 cl_super_cmd::~cl_super_cmd(void)
886 {
887 if (commands)
888 delete commands;
889 }
890
891 int
work(class cl_app * app,class cl_cmdline * cmdline,class cl_console_base * con)892 cl_super_cmd::work(class cl_app *app,
893 class cl_cmdline *cmdline, class cl_console_base *con)
894 {
895 class cl_cmd *cmd= 0;
896
897 if (!commands)
898 return(0);
899
900 if (!cmdline->shift())
901 {
902 if ((cmd= commands->get_cmd("_no_parameters_")) != 0)
903 return(cmd->work(app, cmdline, con));
904 int i;
905 con->dd_printf("\"%s\" must be followed by the name of a subcommand\n"
906 "List of subcommands:\n", (char*)(names->at(0)));
907 for (i= 0; i < commands->count; i++)
908 {
909 cmd= (class cl_cmd *)(commands->at(i));
910 //con->dd_printf("%s\n", (char*)cmd->short_help);
911 cmd->print_short(con);
912 }
913 return(0);
914 }
915 if ((cmd= commands->get_cmd(cmdline, con->is_interactive())) == NULL)
916 {
917 con->dd_printf("Undefined subcommand: \"%s\". Try \"help %s\".\n",
918 cmdline->get_name(), (char*)(names->at(0)));
919 return(0);
920 }
921 return(cmd->work(app, cmdline, con));
922 }
923
924
925 /* End of cmd.src/command.cc */
926