Imported Upstream version 2.9.0
[debian/cc1111] / sim / ucsim / cmd.src / command.cc
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 "i_string.h"
32
33 // prj
34
35 // local, cmd
36 #include "commandcl.h"
37
38
39 /*
40  * Command line
41  *____________________________________________________________________________
42  */
43
44 cl_cmdline::cl_cmdline(class cl_app *the_app,
45                        char *acmd, class cl_console_base *acon):
46   cl_base()
47 {
48   app= the_app;
49   cmd= strdup(acmd);
50   params= new cl_list(2, 2, "command line params");
51   tokens= new cl_ustrings(2, 2, "command line tokens");
52   set_name(0);
53   matched_syntax= 0;
54   con= acon;
55 }
56
57 cl_cmdline::~cl_cmdline(void)
58 {
59   if (cmd)
60     free(cmd);
61   delete params;
62   delete tokens;
63 }
64
65 int
66 cl_cmdline::init(void)
67 {
68   split();
69   return(0);
70 }
71
72 char *
73 cl_cmdline::skip_delims(char *start)
74 {
75   while (*start &&
76          strchr(" \t\v\r,", *start))
77     start++;
78   return(start);
79 }
80
81 int
82 cl_cmdline::split(void)
83 {
84   //class cl_sim *sim;
85   char *start= cmd;
86   int i;
87   class cl_cmd_arg *arg;
88
89   //sim= app->get_sim();
90   set_name("\n");
91   if (!cmd ||
92       !*cmd)
93     return(0);
94   start+= strspn(start, " \t\v\r,");
95   if (start &&
96       *start == '\n')
97     {
98       char *n= (char*)malloc(2);
99       strcpy(n, "\n");
100       set_name(n);
101       return(0);
102     }
103   if (!*start)
104     return(0);
105   i= strcspn(start, " \t\v\r,");
106   if (i)
107     {
108       char *n= (char*)malloc(i+1);
109       strncpy(n, start, i);
110       n[i]= '\0';
111       set_name(n);
112     }
113   start+= i;
114   start= skip_delims(start);
115   // skip delimiters
116   while (*start)
117     {
118       char *end= start, *param_str;
119       if (*start == '"')
120         split_out_string(&start, &end);
121       else if (*start == '>')
122         split_out_output_redirection(&start, &end);
123       else
124         {
125           char *dot;
126           i= strcspn(start, " \t\v\r,");
127           end= start+i;
128           param_str= (char *)malloc(i+1);
129           strncpy(param_str, start, i);
130           param_str[i]= '\0';
131           tokens->add(strdup(param_str));
132           if ((dot= strchr(param_str, '.')) != NULL)
133             split_out_bit(dot, param_str);
134           else if ((dot= strchr(param_str, '[')) != NULL)
135             split_out_array(dot, param_str);
136           else if (strchr("0123456789-+", *param_str) != NULL)
137             {
138               // number
139               params->add(arg= new cl_cmd_int_arg((long)
140                                                   strtol(param_str, 0, 0)));
141               arg->init();
142             }
143           else
144             {
145               // symbol
146               params->add(arg= new cl_cmd_sym_arg(param_str));
147               arg->init();
148             }
149           free(param_str);
150         }
151       start= end;
152       start= skip_delims(start);
153     }
154   return(0);
155 }
156
157 void
158 cl_cmdline::split_out_string(char **_start, char **_end)
159 {
160   char *start= *_start, *end;
161   start++;
162   end= start;
163   while (*end &&
164         *end != '"')
165     {
166       if (*end == '\\')
167        {
168          end++;
169          if (*end)
170            end++;
171        }
172       else
173        end++;
174     }
175   if (*end == '"')
176     end--;
177   else
178     con->dd_printf("Unterminated string\n");
179   char *param_str= (char *)malloc(end-start+2);
180   strncpy(param_str, start, 1+end-start);
181   param_str[1+end-start]= '\0';
182   tokens->add(strdup(param_str));
183   class cl_cmd_arg *arg;
184   params->add(arg= new cl_cmd_str_arg(param_str));
185   arg->init();
186   free(param_str);
187   if (*end)
188     end++;
189   if (*end == '"')
190     end++;
191   *_start= start;
192   *_end= end;
193 }
194
195 void
196 cl_cmdline::split_out_output_redirection(char **_start, char **_end)
197 {
198   char *start= *_start, *end/*= *_end*/;
199   int i;
200   char mode[2];
201
202   mode[0]= 'w';
203   mode[1]= '\0';
204   start++;
205   i= strcspn(start, " \t\v\r,");
206   end= start+i;
207   char *param_str= (char *)malloc(i+1);
208   char *n= param_str;
209   strncpy(param_str, start, i);
210   param_str[i]= '\0';
211   if (param_str &&
212       param_str[0] == '>')
213     {
214       n++;
215       mode[0]= 'a';
216     }
217   tokens->add(strdup(n));
218   con->redirect(n, mode);
219   free(param_str);
220   *_start= start;
221   *_end= end;
222 }
223
224 void
225 cl_cmdline::split_out_bit(char *dot, char *param_str)
226 {
227   class cl_cmd_arg *sfr, *bit;
228
229   *dot= '\0';
230   dot++;
231   if (strchr("0123456789", *param_str) != NULL)
232     {
233       sfr= new cl_cmd_int_arg((long)strtol(param_str, 0, 0));
234       sfr->init();
235     }
236   else
237     {
238       sfr= new cl_cmd_sym_arg(param_str);
239       sfr->init();
240     }
241   if (*dot == '\0')
242     {
243       bit= 0;
244       con->dd_printf("Uncomplete bit address\n");
245       delete sfr;
246     }
247   else
248     {
249       if (strchr("0123456789", *dot) != NULL)
250        {
251          bit= new cl_cmd_int_arg((long)strtol(dot, 0, 0));
252          bit->init();
253        }
254       else
255        {
256          bit= new cl_cmd_sym_arg(dot);
257          bit->init();
258        }
259       class cl_cmd_arg *arg;
260       params->add(arg= new cl_cmd_bit_arg(sfr, bit));
261       arg->init();
262     }
263 }
264
265 void
266 cl_cmdline::split_out_array(char *dot, char *param_str)
267 {
268   class cl_cmd_arg *aname, *aindex;
269        
270   *dot= '\0';
271   dot++;
272   if (strchr("0123456789", *param_str) != NULL)
273     {
274       aname= new cl_cmd_int_arg((long)strtol(param_str, 0, 0));
275       aname->init();
276     }
277   else
278     {
279       aname= new cl_cmd_sym_arg(param_str);
280       aname->init();
281     }
282   if (*dot == '\0')
283     {
284       aname= 0;
285       con->dd_printf("Uncomplete array\n");
286     }
287   else
288     {
289       char *p;
290       p= dot + strlen(dot) - 1;
291       while (p > dot &&
292             *p != ']')
293        {
294          *p= '\0';
295          p--;
296        }
297       if (*p == ']')
298        *p= '\0';
299       if (strlen(dot) == 0)
300        {
301          con->dd_printf("Uncomplete array index\n");
302          delete aname;
303        }
304       else    
305        {
306          if (strchr("0123456789", *dot) != NULL)
307            {
308              aindex= new cl_cmd_int_arg((long)strtol(dot, 0, 0));
309              aindex->init();
310            }
311          else
312            {
313              aindex= new cl_cmd_sym_arg(dot);
314              aindex->init();
315            }
316          class cl_cmd_arg *arg;
317          params->add(arg= new cl_cmd_array_arg(aname, aindex));
318          arg->init();
319        }
320     }
321 }
322
323 int
324 cl_cmdline::shift(void)
325 {
326   char *s= skip_delims(cmd);
327
328   set_name(0);
329   if (s && *s)
330     {
331       while (*s &&
332              strchr(" \t\v\r,", *s) == NULL)
333         s++;
334       s= skip_delims(s);
335       char *p= strdup(s);
336       free(cmd);
337       cmd= p;
338       delete params;
339       params= new cl_list(2, 2, "params");
340       split();
341       if (strcmp(get_name(), "\n") == 0)
342         set_name(0);
343     }
344   return(have_real_name());
345 }
346
347 int
348 cl_cmdline::repeat(void)
349 {
350   const char *n;
351   return((n= get_name()) &&
352          *n == '\n');
353 }
354
355 class cl_cmd_arg *
356 cl_cmdline::param(int num)
357 {
358   if (num >= params->count)
359     return(0);
360   return((class cl_cmd_arg *)(params->at(num)));
361 }
362
363 void
364 cl_cmdline::insert_param(int pos, class cl_cmd_arg *param)
365 {
366   if (pos >= params->count)
367     params->add(param);
368   else
369     params->add_at(pos, param);
370 }
371
372 bool
373 cl_cmdline::syntax_match(class cl_uc *uc, const char *syntax)
374 {
375   if (!syntax)
376     return(DD_FALSE);
377   if (!*syntax &&
378       !params->count)
379     {
380       matched_syntax= syntax;
381       return(DD_TRUE);
382     }
383   if (!params->count)
384     return(DD_FALSE);
385   //printf("syntax %s?\n",syntax);
386   const char *p= syntax;
387   int iparam= 0;
388   class cl_cmd_arg *parm= (class cl_cmd_arg *)(params->at(iparam));
389   while (*p &&
390          parm)
391     {
392       //printf("***Checking %s as %c\n",parm->get_svalue(),*p);
393       if (uc)
394         switch (*p)
395           {
396           case SY_ADDR:
397             if (!parm->as_address(uc))
398               return(DD_FALSE);
399             //printf("ADDRESS match %lx\n",parm->value.address);
400             break;
401           case SY_MEMORY:
402             if (!parm->as_memory(uc))
403               return(DD_FALSE);
404             //printf("MEMORY match %s\n",parm->value.memory->class_name);
405             break;
406           case SY_BIT:
407             if (!parm->as_bit(uc))
408               return(DD_FALSE);
409             break;
410           }
411       switch (*p)
412         {
413         case SY_ADDR: case SY_MEMORY: case SY_BIT: break;
414         case SY_NUMBER:
415           if (!parm->as_number())
416             return(DD_FALSE);
417           break;
418         case SY_DATA:
419           if (!parm->as_data())
420             return(DD_FALSE);
421           break;
422         case SY_HW:
423           if (!parm->as_hw(uc))
424             return(DD_FALSE);
425           break;
426         case SY_STRING:
427           if (!parm->as_string())
428             return(DD_FALSE);
429           break;
430         case SY_DATALIST:
431           if (!set_data_list(parm, &iparam))
432             return(DD_FALSE);
433           break;
434         default:
435           return(DD_FALSE);
436         }
437       p++;
438       iparam++;
439       if (iparam < params->count)
440         parm= (class cl_cmd_arg *)(params->at(iparam));
441       else
442         parm= 0;
443     }
444   if (!*p &&
445       !parm)
446     {
447       matched_syntax= syntax;
448       return(DD_TRUE);
449     }
450   return(DD_FALSE);
451 }
452
453 bool
454 cl_cmdline::set_data_list(class cl_cmd_arg *parm, int *iparm)
455 {
456   class cl_cmd_arg *next_parm;
457   int len, i, j;
458   t_mem *array;
459
460   len= 0;
461   array= 0;
462   for (i= *iparm, next_parm= param(i); next_parm; i++, next_parm= param(i))
463     {
464       if (next_parm->is_string())
465         {
466           int l;
467           char *s;
468           //s= proc_escape(next_parm->get_svalue(), &l);
469           if (!next_parm->as_string())
470             continue;
471           s= next_parm->value.string.string;
472           l= next_parm->value.string.len;
473           if (!array)
474             array= (t_mem*)malloc(sizeof(t_mem)*l);
475           else
476             array= (t_mem*)realloc(array, sizeof(t_mem)*(l+len));
477           for (j= 0; j < l; j++)
478             {
479               array[len]= s[j];
480               len++;
481             }
482           //if (s)
483           //free(s);
484         }
485       else
486         {
487           if (!next_parm->as_data())
488             {
489               if (array)
490                 free(array);
491               return(DD_FALSE);
492             }
493           if (!array)
494             array= (t_mem*)malloc(sizeof(t_mem));
495           else
496             array= (t_mem*)realloc(array, sizeof(t_mem)*(1+len));
497           array[len]= next_parm->value.data;
498           len++;
499         }
500     }
501   *iparm= i;
502   parm->value.data_list.array= array;
503   parm->value.data_list.len= len;
504   return(DD_TRUE);
505 }
506
507
508 /*
509  * Command
510  *____________________________________________________________________________
511  */
512
513 cl_cmd::cl_cmd(enum cmd_operate_on op_on,
514                const char *aname,
515                int can_rep,
516                const char *short_hlp,
517                const char *long_hlp):
518   cl_base()
519 {
520   operate_on= op_on;
521   names= new cl_strings(1, 1, "names of a command");
522   names->add(aname?strdup(aname):strdup("unknown"));
523   can_repeat= can_rep;
524   short_help= short_hlp?strdup(short_hlp):NULL;
525   long_help= long_hlp?strdup(long_hlp):NULL;
526 }
527
528 /*cl_cmd::cl_cmd(class cl_sim *asim):
529   cl_base()
530 {
531   sim= asim;
532   name= short_help= long_help= 0;
533   can_repeat= 0;
534 }*/
535
536 cl_cmd::~cl_cmd(void)
537 {
538   delete names;
539 }
540
541 void
542 cl_cmd::add_name(const char *nam)
543 {
544   if (nam)
545     names->add(strdup(nam));
546 }
547
548 int
549 cl_cmd::name_match(const char *aname, int strict)
550 {
551   int i;
552   
553   if (names->count == 0 &&
554       !aname)
555     return(1);
556   if (!aname)
557     return(0);
558   if (strict)
559     {
560       for (i= 0; i < names->count; i++)
561         {
562           char *n= (char*)(names->at(i));
563           if (strcmp(aname, n) == 0)
564             return(1);
565         }
566     }
567   else
568     {
569       for (i= 0; i < names->count; i++)
570         {
571           char *n= (char*)(names->at(i));
572           if (strstr(n, aname) == n)
573             return(1);
574         }
575     }
576   return(0);
577 }
578
579 int
580 cl_cmd::name_match(class cl_cmdline *cmdline, int strict)
581 {
582   return(name_match(cmdline->get_name(), strict));
583 }
584
585 int
586 cl_cmd::syntax_ok(class cl_cmdline *cmdline)
587 {
588   return(1);
589 }
590
591 int
592 cl_cmd::work(class cl_app *app,
593              class cl_cmdline *cmdline, class cl_console_base *con)
594 {
595   if (!syntax_ok(cmdline))
596     return(0);
597   class cl_sim *sim= app->get_sim();
598   class cl_uc *uc= 0;
599   if (sim)
600     uc= sim->uc;
601   switch (operate_on)
602     {
603     case operate_on_app:
604       if (!app)
605         {
606           con->dd_printf("There is no application to work on!\n");
607           return(DD_TRUE);
608         }
609       return(do_work(app, cmdline, con));
610     case operate_on_sim:
611       if (!sim)
612         {
613           con->dd_printf("There is no simulator to work on!\n");
614           return(DD_TRUE);
615         }
616       return(do_work(sim, cmdline, con));
617     case operate_on_uc:
618       if (!sim)
619         {
620           con->dd_printf("There is no microcontroller to work on!\n");
621           return(DD_TRUE);
622         }
623       return(do_work(uc, cmdline, con));
624     default:
625       return(do_work(cmdline, con));
626     }
627 }
628
629 int
630 cl_cmd::do_work(class cl_cmdline *cmdline, class cl_console_base *con)
631 {
632   con->dd_printf("Command \"%s\" does nothing.\n",
633                  (char*)(names->at(0)));
634   return(0);
635 }
636
637 int
638 cl_cmd::do_work(class cl_app *app,
639                 class cl_cmdline *cmdline, class cl_console_base *con)
640 {
641   con->dd_printf("Command \"%s\" does nothing on application.\n",
642                  (char*)(names->at(0)));
643   return(0);
644 }
645
646 int
647 cl_cmd::do_work(class cl_sim *sim,
648                 class cl_cmdline *cmdline, class cl_console_base *con)
649 {
650   con->dd_printf("Command \"%s\" does nothing on simulator.\n",
651                  (char*)(names->at(0)));
652   return(0);
653 }
654
655 int
656 cl_cmd::do_work(class cl_uc *uc,
657                 class cl_cmdline *cmdline, class cl_console_base *con)
658 {
659   con->dd_printf("Command \"%s\" does nothing on microcontroller.\n",
660                  (char*)(names->at(0)));
661   return(0);
662 }
663
664
665 /*
666  * Set of commands
667  *____________________________________________________________________________
668  */
669
670 cl_cmdset::cl_cmdset(void):
671   cl_list(5, 5, "cmdset")
672 {
673   //sim= 0;
674   //last_command= 0;
675 }
676
677 /*cl_cmdset::cl_cmdset(class cl_sim *asim):
678   cl_list(5, 5)
679 {
680   sim= asim;
681   last_command= 0;
682 }*/
683
684 class cl_cmd *
685 cl_cmdset::get_cmd(class cl_cmdline *cmdline, bool accept_last)
686 {
687   int i;
688
689   // exact match
690   for (i= 0; i < count; i++)
691     {
692       class cl_cmd *c= (class cl_cmd *)at(i);
693       if (c->name_match(cmdline, 1))
694         return(c);
695     }
696   // not exact match
697   class cl_cmd *c_matched= 0;
698   for (i= 0; i < count; i++)
699     {
700       class cl_cmd *c= (class cl_cmd *)at(i);
701       if (c->name_match(cmdline, 0))
702         {
703           if (!c_matched)
704             c_matched= c;
705           else
706             return(0);
707         }
708     }
709   return(c_matched);
710   //return(0);
711 }
712
713 class cl_cmd *
714 cl_cmdset::get_cmd(const char *cmd_name)
715 {
716   int i;
717
718   for (i= 0; i < count; i++)
719     {
720       class cl_cmd *c= (class cl_cmd *)at(i);
721       if (c->name_match(cmd_name, 1))
722         return(c);
723     }
724   return(0);
725 }
726
727 void
728 cl_cmdset::del(char *nam)
729 {
730   int i;
731
732   if (!nam)
733     return;
734   for (i= 0; i < count; i++)
735     {
736       class cl_cmd *cmd= (class cl_cmd *)(at(i));
737       if (cmd->name_match(nam, 1))
738         free_at(i);
739     }
740 }
741
742 void
743 cl_cmdset::replace(char *nam, class cl_cmd *cmd)
744 {
745   int i;
746
747   if (!nam)
748     return;
749   for (i= 0; i < count; i++)
750     {
751       class cl_cmd *c= (class cl_cmd *)(at(i));
752       if (c->name_match(nam, 1))
753         {
754           delete c;
755           put_at(i, cmd);
756         }
757     }
758 }
759
760
761 /*
762  * Composed command: subset of commands
763  *____________________________________________________________________________
764  */
765
766 cl_super_cmd::cl_super_cmd(const char *aname,
767                            int  can_rep,
768                            const char *short_hlp,
769                            const char *long_hlp,
770                            class cl_cmdset *acommands):
771   cl_cmd(operate_on_none, aname, can_rep, short_hlp, long_hlp)
772 {
773   commands= acommands;
774 }
775
776 cl_super_cmd::~cl_super_cmd(void)
777 {
778   if (commands)
779     delete commands;
780 }
781
782 int
783 cl_super_cmd::work(class cl_app *app,
784                    class cl_cmdline *cmdline, class cl_console_base *con)
785 {
786   class cl_cmd *cmd= 0;
787
788   if (!commands)
789     return(0);
790   
791   if (!cmdline->shift())
792     {
793       if ((cmd= commands->get_cmd("_no_parameters_")) != 0)
794         return(cmd->work(app, cmdline, con));
795       int i;
796       con->dd_printf("\"%s\" must be followed by the name of a subcommand\n"
797                      "List of subcommands:\n", (char*)(names->at(0)));
798       for (i= 0; i < commands->count; i++)
799         {
800           cmd= (class cl_cmd *)(commands->at(i));
801           con->dd_printf("%s\n", cmd->short_help);
802         }
803       return(0);
804     }
805   if ((cmd= commands->get_cmd(cmdline, con->accept_last())) == NULL)
806     {
807       con->dd_printf("Undefined subcommand: \"%s\". Try \"help %s\".\n",
808                      cmdline->get_name(), (char*)(names->at(0)));
809       return(0);
810     }
811   return(cmd->work(app, cmdline, con));
812 }
813
814
815 /* End of cmd.src/command.cc */