e58a225118a3a6ed9476154613b3ff84cd53b54e
[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   bool match;
367   while (*p &&
368          parm)
369     {
370       //printf("Checking %s as %c\n",parm->get_svalue(),*p);
371       if (uc)
372         switch (*p)
373           {
374           case SY_ADDR:
375             match= parm->as_address(uc);
376             if (!match)
377               return(match);
378             //printf("ADDRESS match %lx\n",parm->value.address);
379             break;
380           case SY_MEMORY:
381             match= parm->as_memory(uc);
382             if (!match)
383               return(DD_FALSE);
384             //printf("MEMORY match %s\n",parm->value.memory->class_name);
385             break;
386           case SY_BIT:
387             if (!parm->as_bit(uc))
388               return(DD_FALSE);
389             break;
390           }
391       switch (*p)
392         {
393         case SY_ADDR: case SY_MEMORY: case SY_BIT: break;
394         case SY_NUMBER:
395           if (!parm->as_number())
396             return(DD_FALSE);
397           break;
398         case SY_DATA:
399           if (!parm->as_data())
400             return(DD_FALSE);
401           break;
402         case SY_HW:
403           if (!parm->as_hw(uc))
404             return(DD_FALSE);
405           break;
406         case SY_STRING:
407           if (!parm->as_string())
408             return(DD_FALSE);
409           break;
410         case SY_DATALIST:
411           if (!set_data_list(parm, &iparam))
412             return(DD_FALSE);
413           break;
414         default:
415           return(DD_FALSE);
416         }
417       p++;
418       iparam++;
419       if (iparam < params->count)
420         parm= (class cl_cmd_arg *)(params->at(iparam));
421       else
422         parm= 0;
423     }
424   if (!*p &&
425       !parm)
426     {
427       matched_syntax= syntax;
428       return(DD_TRUE);
429     }
430   return(DD_FALSE);
431 }
432
433 bool
434 cl_cmdline::set_data_list(class cl_cmd_arg *parm, int *iparm)
435 {
436   class cl_cmd_arg *next_parm;
437   int len, i, j;
438   t_mem *array;
439
440   len= 0;
441   array= 0;
442   for (i= *iparm, next_parm= param(i); next_parm; i++, next_parm= param(i))
443     {
444       if (next_parm->is_string())
445         {
446           int l;
447           char *s;
448           //s= proc_escape(next_parm->get_svalue(), &l);
449           if (!next_parm->as_string())
450             continue;
451           s= next_parm->value.string.string;
452           l= next_parm->value.string.len;
453           if (!array)
454             array= (t_mem*)malloc(sizeof(t_mem)*l);
455           else
456             array= (t_mem*)realloc(array, sizeof(t_mem)*(l+len));
457           for (j= 0; j < l; j++)
458             {
459               array[len]= s[j];
460               len++;
461             }
462           //if (s)
463           //free(s);
464         }
465       else
466         {
467           if (!next_parm->as_data())
468             {
469               if (array)
470                 free(array);
471               return(DD_FALSE);
472             }
473           if (!array)
474             array= (t_mem*)malloc(sizeof(t_mem));
475           else
476             array= (t_mem*)realloc(array, sizeof(t_mem)*(1+len));
477           array[len]= next_parm->value.data;
478           len++;
479         }
480     }
481   *iparm= i;
482   parm->value.data_list.array= array;
483   parm->value.data_list.len= len;
484   return(DD_TRUE);
485 }
486
487
488 /*
489  * Command
490  *____________________________________________________________________________
491  */
492
493 cl_cmd::cl_cmd(enum cmd_operate_on op_on,
494                char *aname,
495                int can_rep,
496                char *short_hlp,
497                char *long_hlp):
498   cl_base()
499 {
500   operate_on= op_on;
501   names= new cl_strings(1, 1);
502   names->add(aname?strdup(aname):strdup("unknown"));
503   can_repeat= can_rep;
504   short_help= short_hlp?strdup(short_hlp):NULL;
505   long_help= long_hlp?strdup(long_hlp):NULL;
506 }
507
508 /*cl_cmd::cl_cmd(class cl_sim *asim):
509   cl_base()
510 {
511   sim= asim;
512   name= short_help= long_help= 0;
513   can_repeat= 0;
514 }*/
515
516 cl_cmd::~cl_cmd(void)
517 {
518   delete names;
519   if (short_help)
520     free(short_help);
521   if (long_help)
522     free(long_help);
523 }
524
525 void
526 cl_cmd::add_name(char *nam)
527 {
528   if (nam)
529     names->add(strdup(nam));
530 }
531
532 int
533 cl_cmd::name_match(char *aname, int strict)
534 {
535   int i;
536   
537   if (names->count == 0 &&
538       !aname)
539     return(1);
540   if (!aname)
541     return(0);
542   if (strict)
543     {
544       for (i= 0; i < names->count; i++)
545         {
546           char *n= (char*)(names->at(i));
547           if (strcmp(aname, n) == 0)
548             return(1);
549         }
550     }
551   else
552     {
553       for (i= 0; i < names->count; i++)
554         {
555           char *n= (char*)(names->at(i));
556           if (strstr(n, aname) == n)
557             return(1);
558         }
559     }
560   return(0);
561 }
562
563 int
564 cl_cmd::name_match(class cl_cmdline *cmdline, int strict)
565 {
566   return(name_match(cmdline->get_name(), strict));
567 }
568
569 int
570 cl_cmd::syntax_ok(class cl_cmdline *cmdline)
571 {
572   return(1);
573 }
574
575 int
576 cl_cmd::work(class cl_app *app,
577              class cl_cmdline *cmdline, class cl_console *con)
578 {
579   if (!syntax_ok(cmdline))
580     return(0);
581   class cl_sim *sim= app->get_sim();
582   class cl_uc *uc= 0;
583   if (sim)
584     uc= sim->uc;
585   switch (operate_on)
586     {
587     case operate_on_app:
588       if (!app)
589         {
590           con->dd_printf("There is no application to work on!\n");
591           return(DD_TRUE);
592         }
593       return(do_work(app, cmdline, con));
594     case operate_on_sim:
595       if (!sim)
596         {
597           con->dd_printf("There is no simulator to work on!\n");
598           return(DD_TRUE);
599         }
600       return(do_work(sim, cmdline, con));
601     case operate_on_uc:
602       if (!sim)
603         {
604           con->dd_printf("There is no microcontroller to work on!\n");
605           return(DD_TRUE);
606         }
607       return(do_work(uc, cmdline, con));
608     default:
609       return(do_work(cmdline, con));
610     }
611 }
612
613 int
614 cl_cmd::do_work(class cl_cmdline *cmdline, class cl_console *con)
615 {
616   con->dd_printf("Command \"%s\" does nothing.\n",
617                  (char*)(names->at(0)));
618   return(0);
619 }
620
621 int
622 cl_cmd::do_work(class cl_app *app,
623                 class cl_cmdline *cmdline, class cl_console *con)
624 {
625   con->dd_printf("Command \"%s\" does nothing on application.\n",
626                  (char*)(names->at(0)));
627   return(0);
628 }
629
630 int
631 cl_cmd::do_work(class cl_sim *sim,
632                 class cl_cmdline *cmdline, class cl_console *con)
633 {
634   con->dd_printf("Command \"%s\" does nothing on simulator.\n",
635                  (char*)(names->at(0)));
636   return(0);
637 }
638
639 int
640 cl_cmd::do_work(class cl_uc *uc,
641                 class cl_cmdline *cmdline, class cl_console *con)
642 {
643   con->dd_printf("Command \"%s\" does nothing on microcontroller.\n",
644                  (char*)(names->at(0)));
645   return(0);
646 }
647
648
649 /*
650  * Set of commands
651  *____________________________________________________________________________
652  */
653
654 cl_cmdset::cl_cmdset(void):
655   cl_list(5, 5)
656 {
657   //sim= 0;
658   last_command= 0;
659 }
660
661 /*cl_cmdset::cl_cmdset(class cl_sim *asim):
662   cl_list(5, 5)
663 {
664   sim= asim;
665   last_command= 0;
666 }*/
667
668 class cl_cmd *
669 cl_cmdset::get_cmd(class cl_cmdline *cmdline)
670 {
671   int i;
672
673   if (cmdline->repeat())
674     {
675       if (last_command)
676         return(last_command);
677       else
678         return(0);
679     }
680   // exact match
681   for (i= 0; i < count; i++)
682     {
683       class cl_cmd *c= (class cl_cmd *)at(i);
684       if (c->name_match(cmdline, 1))
685         return(c);
686     }
687   // not exact match
688   class cl_cmd *c_matched= 0;
689   for (i= 0; i < count; i++)
690     {
691       class cl_cmd *c= (class cl_cmd *)at(i);
692       if (c->name_match(cmdline, 0))
693         {
694           if (!c_matched)
695             c_matched= c;
696           else
697             return(0);
698         }
699     }
700   return(c_matched);
701   //return(0);
702 }
703
704 class cl_cmd *
705 cl_cmdset::get_cmd(char *cmd_name)
706 {
707   int i;
708
709   for (i= 0; i < count; i++)
710     {
711       class cl_cmd *c= (class cl_cmd *)at(i);
712       if (c->name_match(cmd_name, 1))
713         return(c);
714     }
715   return(0);
716 }
717
718 void
719 cl_cmdset::del(char *nam)
720 {
721   int i;
722
723   if (!nam)
724     return;
725   for (i= 0; i < count; i++)
726     {
727       class cl_cmd *cmd= (class cl_cmd *)(at(i));
728       if (cmd->name_match(nam, 1))
729         free_at(i);
730     }
731 }
732
733 void
734 cl_cmdset::replace(char *nam, class cl_cmd *cmd)
735 {
736   int i;
737
738   if (!nam)
739     return;
740   for (i= 0; i < count; i++)
741     {
742       class cl_cmd *c= (class cl_cmd *)(at(i));
743       if (c->name_match(nam, 1))
744         {
745           delete c;
746           put_at(i, cmd);
747         }
748     }
749 }
750
751
752 /*
753  * Composed command: subset of commands
754  *____________________________________________________________________________
755  */
756
757 cl_super_cmd::cl_super_cmd(char *aname,
758                            int  can_rep,
759                            char *short_hlp,
760                            char *long_hlp,
761                            class cl_cmdset *acommands):
762   cl_cmd(operate_on_none, aname, can_rep, short_hlp, long_hlp)
763 {
764   commands= acommands;
765 }
766
767 cl_super_cmd::~cl_super_cmd(void)
768 {
769   if (commands)
770     delete commands;
771 }
772
773 int
774 cl_super_cmd::work(class cl_app *app,
775                    class cl_cmdline *cmdline, class cl_console *con)
776 {
777   class cl_cmd *cmd= 0;
778
779   if (!commands)
780     return(0);
781   
782   if (!cmdline->shift())
783     {
784       if ((cmd= commands->get_cmd("_no_parameters_")) != 0)
785         return(cmd->work(app, cmdline, con));
786       int i;
787       con->dd_printf("\"%s\" must be followed by the name of a subcommand\n"
788                      "List of subcommands:\n", (char*)(names->at(0)));
789       for (i= 0; i < commands->count; i++)
790         {
791           cmd= (class cl_cmd *)(commands->at(i));
792           con->dd_printf("%s\n", cmd->short_help);
793         }
794       return(0);
795     }
796   if ((cmd= commands->get_cmd(cmdline)) == NULL)
797     {
798       con->dd_printf("Undefined subcommand: \"%s\". Try \"help %s\".\n",
799                      cmdline->get_name(), (char*)(names->at(0)));
800       return(0);
801     }
802   return(cmd->work(app, cmdline, con));
803 }
804
805
806 /* End of cmd.src/command.cc */