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