Initial revision
[fw/sdcc] / debugger / mcs51 / sdcdb.c
1 /*-------------------------------------------------------------------------
2   sdcdb.c - main source file for sdcdb debugger
3               Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
4
5    This program is free software; you can redistribute it and/or modify it
6    under the terms of the GNU General Public License as published by the
7    Free Software Foundation; either version 2, or (at your option) any
8    later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18    
19    In other words, you are welcome to use, share and improve this program.
20    You are forbidden to forbid anyone else to use, share and improve
21    what you give them.   Help stamp out software-hoarding!  
22 -------------------------------------------------------------------------*/
23
24 #include "sdcdb.h"
25 #include "symtab.h"
26 #include "simi.h"
27 #include "break.h"
28 #include "cmd.h"
29
30 char *currModName = NULL;
31 cdbrecs *recsRoot = NULL ;
32 set  *modules = NULL;    /* set of all modules */
33 set  *functions = NULL ; /* set of functions */
34 set  *symbols = NULL   ; /* set of symbols */
35 int nStructs = 0 ;
36 structdef **structs = NULL ; /* all structures */
37 int nLinkrecs = 0;
38 linkrec **linkrecs = NULL; /* all linkage editor records */
39 context *currCtxt = NULL;
40 short fullname = 0;
41 char *ssdirl = SDCC_LIB_DIR ":" SDCC_LIB_DIR "/small" ;
42 char *simArgs[8];
43 int nsimArgs = 0;
44
45 /* command table */
46 struct cmdtab
47 {
48     char      *cmd ;  /* command the user will enter */       
49     int (*cmdfunc)(char *,context *);   /* function to execute when command is entered */
50     char *htxt ;    /* short help text */    
51     
52 } cmdTab[] = {
53     /* NOTE:- the search is done from the top, so "break" should
54        precede the synonym "b" */
55     /* break point */
56     { "break"    ,  cmdSetUserBp  ,
57       "{b}reak\t\t\t [LINE |  FILE:LINE | FILE:FUNCTION | FUNCTION]\n",
58     },
59     { "b"        ,  cmdSetUserBp  , NULL },
60
61     { "clear"    ,  cmdClrUserBp  ,
62       "{cl}ear\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
63     },
64     { "cl"       ,  cmdClrUserBp  , NULL },
65
66     { "continue" ,  cmdContinue   ,
67       "{c}ontinue\t\t Continue program being debugged, after breakpoint.\n"
68     },
69     { "c"        ,  cmdContinue   , NULL },
70
71     { "delete" ,  cmdDelUserBp  ,
72       "{d}elete n\t\t clears break point number n\n"
73     },
74     { "d"        ,  cmdDelUserBp  , NULL },
75
76     { "help"     ,  cmdHelp       ,
77       "{h|?}elp\t\t this message\n"
78     },    
79     { "?"        ,  cmdHelp       , NULL },
80     { "h"        ,  cmdHelp       , NULL },
81     
82     { "info"     ,  cmdInfo       ,
83       "info\n"
84       "\t {break}\t list all break points\n"
85       "\t {stack}\t information about call stack\n"
86       "\t {frame}\t current frame information\n"
87       "\t {registers}\t display value of all registers\n"
88     },
89
90     { "listasm"  ,  cmdListAsm    ,
91       "listasm {la}\t\t list assembler code for the current C line\n"
92     },
93     { "la"       ,  cmdListAsm    , NULL },
94     { "list"     ,  cmdListSrc    ,
95       "{l}ist\t\t\t [LINE | FILE:LINE | FILE:FUNCTION | FUNCTION]\n"
96     },    
97     { "l"        ,  cmdListSrc    , NULL },
98     { "show"     ,  cmdShow       ,
99       "show\n"
100       "\t {copying}\t copying & distribution terms\n"
101       "\t {warranty}\t warranty information\n"
102     },
103     { "set"      ,  cmdSetOption  , NULL },    
104     { "step"     ,  cmdStep       ,
105       "{s}tep\t\t\t Step program until it reaches a different source line.\n"
106     },
107     { "s"        ,  cmdStep       , NULL },
108     { "next"     ,  cmdNext       , 
109       "{n}ext\t\t\t Step program, proceeding through subroutine calls.\n"
110     },
111     { "n"        ,  cmdNext       , NULL },
112     { "run"      ,  cmdRun        , 
113       "{r}un\t\t\t Start debugged program. \n"
114     },
115     { "r"        ,  cmdRun        , NULL },
116     { "ptype"    ,  cmdPrintType  , 
117       "{pt}ype <variable>\t print type information of a variable\n"
118     },
119     { "pt"       ,  cmdPrintType  , NULL },
120     { "print"    ,  cmdPrint      , 
121       "{p}rint <variable>\t print value of given variable\n"
122     },
123     { "p"        ,  cmdPrint      , NULL },
124     { "file"     ,  cmdFile       ,
125       "file <filename>\t\t load symbolic information from <filename>\n"
126     },  
127     { "frame"    ,  cmdFrame      , 
128       "{fr}ame\t\t\t print information about the current Stack\n"
129     },
130     { "finish"   ,  cmdFinish     ,
131       "{fi}nish\t\t execute till return of current function\n"
132     },
133     { "fi"       ,  cmdFinish     , NULL },
134     { "fr"       ,  cmdFrame      , NULL },
135     { "f"        ,  cmdFrame      , NULL },
136     { "!"        ,  cmdSimulator  , 
137       "!<simulator command>\t send a command directly to the simulator\n"
138     },
139     { "quit"     ,  cmdQuit       , 
140       "{q}uit\t\t\t \"Watch me now. Iam going Down. My name is Bobby Brown\"\n"
141     },
142     { "q"        ,  cmdQuit       , NULL }
143 };
144
145 /*-----------------------------------------------------------------*/
146 /* alloccpy - allocate copy and return a new string                */
147 /*-----------------------------------------------------------------*/
148 char *alloccpy ( char *s, int size)
149 {
150     char *d;
151
152     if (!size)
153         return NULL;
154
155     ALLOC(d,size+1);
156     memcpy(d,s,size);
157     d[size] = '\0';
158
159     return d;
160 }
161
162 /*-----------------------------------------------------------------*/
163 /* resize - resizes array of type with new size                    */
164 /*-----------------------------------------------------------------*/
165 void **resize (void **array, int newSize)
166 {
167     void **vptr;
168
169     if (array)
170         vptr = GC_realloc(array,newSize*(sizeof(void **)));
171     else
172         vptr = GC_malloc(sizeof(void **));
173     
174     if (!vptr) {
175         fprintf(stderr,"sdcdb: out of memory \n");
176         exit(1);
177     }
178
179     return vptr;
180         
181 }
182
183 /*-----------------------------------------------------------------*/
184 /* readCdb - reads the cdb files & puts the records into cdbLine   */
185 /*           linked list                                           */
186 /*-----------------------------------------------------------------*/
187 static int readCdb (FILE *file)
188 {
189     cdbrecs *currl ;
190     char buffer[1024];
191     char *bp ;
192     
193     if (!(bp = fgets(buffer,sizeof(buffer),file)))
194             return 0;
195     
196     ALLOC(currl,sizeof(cdbrecs));
197     recsRoot = currl ;
198
199     while (1) {
200         
201         /* make sure this is a cdb record */
202         if (strchr("STLFM",*bp) && *(bp+1) == ':') {
203             /* depending on the record type */
204             
205             switch (*bp) {
206             case 'S':
207                 /* symbol record */
208                 currl->type = SYM_REC;
209                 break;
210             case 'T':
211                 currl->type = STRUCT_REC;
212                 break;
213             case 'L':
214                 currl->type = LNK_REC;
215                 break;
216             case 'F':
217                 currl->type = FUNC_REC;
218                 break;
219             case 'M':
220                 currl->type = MOD_REC ;
221             }
222             
223             bp += 2;
224             ALLOC(currl->line,strlen(bp));
225             strncpy(currl->line,bp,strlen(bp)-1);
226             currl->line[strlen(bp)-1] = '\0';
227         }
228         
229         if (!(bp = fgets(buffer,sizeof(buffer),file)))
230             break;
231         
232         if (feof(file))
233             break;
234         
235         ALLOC(currl->next,sizeof(cdbrecs));
236         currl = currl->next;
237     }
238
239     return (recsRoot->line ? 1 : 0);
240 }
241
242 /*-----------------------------------------------------------------*/
243 /* searchDirsFname - search directory list & return the filename   */
244 /*-----------------------------------------------------------------*/
245 char *searchDirsFname (char *fname)
246 {
247     char *dirs , *sdirs;
248     FILE *rfile = NULL;
249     char buffer[128];
250
251     /* first try the current directory */
252     if ((rfile = fopen(fname,"r"))) {
253         fclose(rfile);
254         return strdup(fname) ;
255     }
256
257     if (!ssdirl)
258         return strdup(fname);
259
260     /* make a copy of the source directories */
261     dirs = sdirs = strdup(ssdirl);    
262    
263     /* assume that the separator is ':' 
264        and try for each directory in the search list */
265     dirs = strtok(dirs,":");
266     while (dirs) {
267         if (dirs[strlen(dirs)] == '/')
268             sprintf(buffer,"%s%s",dirs,fname);
269         else
270             sprintf(buffer,"%s/%s",dirs,fname);
271         if ((rfile = fopen(buffer,"r")))
272             break ;
273         dirs = strtok(NULL,":");
274     }
275     
276     free(sdirs);
277     if (rfile) {
278         fclose(rfile);
279         return strdup(buffer);
280     } else
281         return strdup(fname);    
282 }
283
284 /*-----------------------------------------------------------------*/
285 /* searchDirsFopen - go thru list of directories for filename given*/
286 /*-----------------------------------------------------------------*/
287 FILE *searchDirsFopen(char *fname)
288 {
289     char *dirs , *sdirs;
290     FILE *rfile = NULL;
291     char buffer[128];
292
293     /* first try the current directory */
294     if ((rfile = fopen(fname,"r")))
295         return rfile;
296
297     if (!ssdirl)
298         return NULL;
299     /* make a copy of the source directories */
300     dirs = sdirs = strdup(ssdirl);    
301    
302     /* assume that the separator is ':' 
303        and try for each directory in the search list */
304     dirs = strtok(dirs,":");
305     while (dirs) {
306         sprintf(buffer,"%s/%s",dirs,fname);
307         if ((rfile = fopen(buffer,"r")))
308             break ;
309         dirs = strtok(NULL,":");
310     }
311     
312     free(sdirs);
313     return rfile ;
314     
315 }
316
317 /*-----------------------------------------------------------------*/
318 /* loadFile - loads a file into module buffer                      */
319 /*-----------------------------------------------------------------*/
320 srcLine **loadFile (char *name, int *nlines)
321 {
322     FILE *mfile ;
323     char buffer[512];
324     char *bp;
325     srcLine **slines = NULL;
326     
327     
328     if (!(mfile = searchDirsFopen(name))) {
329         fprintf(stderr,"sdcdb: cannot open module %s -- use '--directory=<source directory> option\n",name);
330         return NULL;
331     }
332
333     while ((bp = fgets(buffer,sizeof(buffer),mfile))) {
334         (*nlines)++;
335
336         slines = (srcLine **)resize((void **)slines,*nlines);
337
338         ALLOC(slines[(*nlines)-1],sizeof(srcLine));
339         slines[(*nlines)-1]->src = alloccpy(bp,strlen(bp));     
340     }
341
342     fclose(mfile);
343     return slines;
344 }
345
346
347 /*-----------------------------------------------------------------*/
348 /* loadModules - reads the source files into module structure      */
349 /*-----------------------------------------------------------------*/
350 static void loadModules ()
351 {
352     cdbrecs *loop;
353     module *currMod;
354     char *rs;
355
356     /* go thru the records & find out the module
357        records & load the modules specified */
358     for ( loop = recsRoot ; loop ; loop = loop->next ) {
359         
360         switch (loop->type) {
361         /* for module records do */
362         case MOD_REC: 
363             currMod = parseModule(loop->line,TRUE);
364             currModName = currMod->name ;
365             
366             currMod->cfullname = searchDirsFname(currMod->c_name);
367
368             /* load it into buffer */
369             currMod->cLines = loadFile (currMod->c_name,
370                                         &currMod->ncLines);
371
372             /* do the same for the assembler file */
373             currMod->afullname = searchDirsFname(currMod->asm_name);
374             currMod->asmLines=loadFile (currMod->asm_name,
375                                         &currMod->nasmLines);
376             break;
377
378         /* if this is a function record */
379         case FUNC_REC:
380             parseFunc(loop->line);
381             break;
382
383         /* if this is a structure record */
384         case STRUCT_REC:
385             parseStruct(loop->line);
386             break;
387
388         /* if symbol then parse the symbol */
389         case  SYM_REC:
390             parseSymbol(loop->line,&rs);
391             break;      
392
393         case LNK_REC:
394             parseLnkRec(loop->line);
395             break;
396         }
397     }
398 }
399
400 /*-----------------------------------------------------------------*/
401 /* functionPoints - determine the execution points within a func   */
402 /*-----------------------------------------------------------------*/
403 static void functionPoints ()
404 {
405     function *func;
406     symbol *sym;
407
408     /* for all functions do */
409     for ( func = setFirstItem(functions); func;
410           func = setNextItem(functions)) {
411         int j ;
412         module *mod;
413        
414         sym = func->sym;
415
416 #ifdef SDCDB_DEBUG      
417         printf("func '%s' has entry '%x' exit '%x'\n",
418                func->sym->name,
419                func->sym->addr,
420                func->sym->eaddr);
421 #endif
422         if (!func->sym->addr && !func->sym->eaddr)
423             continue ;
424
425         /* for all source lines in the module find
426            the ones with address >= start and <= end
427            and put them in the point */
428         mod = NULL ;
429         if (! applyToSet(modules,moduleWithName,func->modName,&mod))
430             continue ;
431         func->mod = mod ;       
432         func->entryline= INT_MAX;
433         func->exitline =  0;
434         func->aentryline = INT_MAX ;
435         func->aexitline = 0;
436
437         /* do it for the C Lines first */
438         for ( j = 0 ; j < mod->ncLines ; j++ ) {
439             if (mod->cLines[j]->addr >= sym->addr &&
440                 mod->cLines[j]->addr <= sym->eaddr ) {
441                 
442                 exePoint *ep ;
443
444                 /* add it to the execution point */
445                 if (func->entryline > j)
446                     func->entryline = j;
447
448                 if (func->exitline < j)
449                     func->exitline = j;
450
451                 ALLOC(ep,sizeof(exePoint));
452                 ep->addr =  mod->cLines[j]->addr ;
453                 ep->line = j;
454                 ep->block= mod->cLines[j]->block;
455                 ep->level= mod->cLines[j]->level;
456                 addSet(&func->cfpoints,ep);
457             }
458         }
459
460         /* do the same for asm execution points */
461         for ( j = 0 ; j < mod->nasmLines ; j++ ) {
462             if (mod->asmLines[j]->addr >= sym->addr &&
463                 mod->asmLines[j]->addr <= sym->eaddr ) {
464                 
465                 exePoint *ep ;
466                 /* add it to the execution point */
467                 if (func->aentryline > j)
468                     func->aentryline = j;
469
470                 if (func->aexitline < j)
471                     func->aexitline = j;
472
473                 /* add it to the execution point */
474                 ALLOC(ep,sizeof(exePoint));
475                 ep->addr =  mod->asmLines[j]->addr ;
476                 ep->line = j;
477                 addSet(&func->afpoints,ep);     
478             }
479         }
480
481 #ifdef SDCDB_DEBUG
482         printf("function '%s' has the following C exePoints\n",
483                func->sym->name);
484         {
485             exePoint *ep;
486
487             for (ep = setFirstItem(func->cfpoints); ep;
488                  ep = setNextItem(func->cfpoints))
489                 fprintf (stdout,"{%x,%d} %s",ep->addr,ep->line,mod->cLines[ep->line]->src);
490
491             fprintf(stdout," and the following ASM exePoints\n");
492             for (ep = setFirstItem(func->afpoints); ep;
493                  ep = setNextItem(func->afpoints))
494                 fprintf (stdout,"{%x,%d} %s",ep->addr,ep->line,mod->asmLines[ep->line]->src);
495                     
496         }
497 #endif
498     }
499 }
500
501
502 /*-----------------------------------------------------------------*/
503 /* setEntryExitBP - set the entry & exit Break Points for functions*/
504 /*-----------------------------------------------------------------*/
505 DEFSETFUNC(setEntryExitBP)
506 {
507     function *func = item;
508
509     if (func->sym && func->sym->addr && func->sym->eaddr) {
510
511         /* set the entry break point */
512         setBreakPoint (func->sym->addr , CODE , FENTRY , 
513                        fentryCB ,func->mod->c_name , func->entryline);
514
515         /* set the exit break point */
516         setBreakPoint (func->sym->eaddr , CODE , FEXIT  ,
517                        fexitCB  ,func->mod->c_name , func->exitline );
518     }
519
520     return 0;
521 }
522
523 /*-----------------------------------------------------------------*/
524 /* cmdFile - load file into the debugger                           */
525 /*-----------------------------------------------------------------*/
526 int cmdFile (char *s,context *cctxt)
527 {
528     FILE *cdbFile;
529     char buffer[128];
530     char *bp;
531
532     while (isspace(*s)) s++;
533     if (!*s) {
534         fprintf(stdout,"No exec file now.\nNo symbol file now.\n");
535         return 0;
536     }
537
538     sprintf(buffer,"%s.cdb",s);
539     /* try creating the cdbfile */
540     if (!(cdbFile = searchDirsFopen(buffer))) {
541         fprintf(stdout,"Cannot open file\"%s\"",buffer);
542         return 0;
543     }
544
545     /* allocate for context */
546     ALLOC(currCtxt ,sizeof(context));
547     
548     /* readin the debug information */
549     if (!readCdb (cdbFile)) {
550         fprintf(stdout,"No symbolic information found in file %s.cdb\n",s);
551         return 0;
552     }   
553         
554     /* parse and load the modules required */
555     loadModules();
556     
557     /* determine the execution points for this
558        module */
559     functionPoints();
560
561     /* start the simulator & setup connection to it */
562     openSimulator((char **)simArgs,nsimArgs);
563     fprintf(stdout,"%s",simResponse());
564     /* now send the filename to be loaded to the simulator */    
565     sprintf(buffer,"%s.ihx",s);
566     bp=searchDirsFname(buffer);
567     simLoadFile(bp);
568     free(bp);
569
570     /*set the break points
571        required by the debugger . i.e. the function entry
572        and function exit break points */
573     applyToSet(functions,setEntryExitBP);
574
575     /* ad we are done */
576     return 0;
577 }
578
579 /*-----------------------------------------------------------------*/
580 /* cmdHelp - help command                                          */
581 /*-----------------------------------------------------------------*/
582 int cmdHelp (char *s, context *cctxt)
583 {   
584     int i ;
585         
586     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
587         
588         /* command string matches */
589         if (cmdTab[i].htxt)
590             fprintf(stdout,"%s",cmdTab[i].htxt);
591     }
592             
593     return 0;
594 }
595
596 #define MAX_CMD_LEN 512
597 char *prompt = "(sdcdb) ";
598 char cmdbuff[MAX_CMD_LEN];
599
600 /*-----------------------------------------------------------------*/
601 /* interpretCmd - interpret and do the command                     */
602 /*-----------------------------------------------------------------*/
603 int interpretCmd (char *s)
604 {
605     static char *pcmd = NULL;
606     int i ;
607     int rv = 0 ;
608     /* if nothing & previous command exists then
609        execute the previous command again */
610     if (*s == '\n' && pcmd)
611         strcpy(s,pcmd);
612     /* if previous command exists & is different
613        from the current command then copy it */
614     if (pcmd) {
615         if (strcmp(pcmd,s)) {
616             free(pcmd);
617             pcmd = strdup(s);
618         }
619     } else
620         pcmd = strdup(s);
621     /* lookup the command table and do the
622        task required */
623     strtok(s,"\n");
624
625     for (i = 0 ; i < (sizeof(cmdTab)/sizeof(struct cmdtab)) ; i++) {
626         
627         /* command string matches */
628         if (strncmp(s,cmdTab[i].cmd,strlen(cmdTab[i].cmd)) == 0) {
629             if (!cmdTab[i].cmdfunc)
630                 return 1;
631             rv = (*cmdTab[i].cmdfunc)(s + strlen(cmdTab[i].cmd),currCtxt);
632             
633             /* if full name then give the file name & position */
634             if (fullname && currCtxt && currCtxt->func) {
635                 if (srcMode == SRC_CMODE)
636                     fprintf(stdout,"\032\032%s:%d:1\n",
637                             currCtxt->func->mod->cfullname,
638                             currCtxt->cline+1);
639                 else
640                     fprintf(stdout,"\032\032%s:%d:1\n",
641                             currCtxt->func->mod->afullname,
642                             currCtxt->asmline+1); 
643             }
644             goto ret;
645         }
646     }
647    
648     fprintf(stdout,"Undefined command: \"%s\".  Try \"help\".\n",s);
649  ret:
650     return rv;
651 }
652
653 /*-----------------------------------------------------------------*/
654 /* commandLoop - the main command loop                             */
655 /*-----------------------------------------------------------------*/
656 void commandLoop()
657 {
658
659     while (1) {
660         fprintf(stdout,"%s",prompt);
661         fflush(stdout);
662
663         if (fgets(cmdbuff,sizeof(cmdbuff),stdin) == NULL)
664             break;
665
666         if (interpretCmd(cmdbuff))
667             break;
668         
669     }
670 }
671
672 /*-----------------------------------------------------------------*/
673 /* printVersionInfo - print the version information                */
674 /*-----------------------------------------------------------------*/
675 static void printVersionInfo()
676 {
677     fprintf(stdout,
678             "SDCDB is free software and you are welcome to distribute copies of it\n"
679             "under certain conditions; type \"show copying\" to see the conditions.\n"
680             "There is absolutely no warranty for SDCDB; type \"show warranty\" for details.\n"
681             "SDCDB 0.8 . Copyright (C) 1999 Sandeep Dutta (sandeep.dutta@usa.net)\n"
682             "Type ? for help\n");
683
684 }
685
686 /*-----------------------------------------------------------------*/
687 /* parseCmdLine - parse the commandline arguments                  */
688 /*-----------------------------------------------------------------*/
689 static void parseCmdLine (int argc, char **argv)
690 {
691     int i ;
692     char *filename = NULL;
693     char buffer[100];
694     for ( i = 1; i < argc ; i++) {
695         fprintf(stdout,"%s\n",argv[i]);
696         
697         /* if this is an option */
698         if (argv[i][0] == '-') {
699             
700             /* if directory then mark directory */
701             if (strncmp(argv[i],"--directory=",12) == 0) {
702                 if (!ssdirl)
703                     ssdirl = &argv[i][12];
704                 else {
705                     char *p = malloc(strlen(ssdirl)+strlen(&argv[i][12])+2);
706                     strcat(strcat(strcpy(p,&argv[i][12]),":"),ssdirl);
707                     ssdirl = p;
708                 }
709                 continue;
710             }
711             
712             if (strncmp(argv[i],"-fullname",9) == 0) {
713                 fullname = TRUE;
714                 continue;
715             }
716             
717             if (strcmp(argv[i],"-cd") == 0) {
718                 i++;
719                 chdir(argv[i]);
720                 continue;
721             }
722             
723             if (strncmp(argv[i],"-cd=",4) == 0) {
724                 chdir(argv[i][4]);
725                 continue;
726             }
727             
728             /* the simulator arguments */
729
730             /* cpu */
731             if (strcmp(argv[i],"-t") == 0 ||
732                 strcmp(argv[i],"-cpu") == 0) {
733
734                     simArgs[nsimArgs++] = "-t";          
735                     simArgs[nsimArgs++] = strdup(argv[++i]);
736                     continue ;
737             }
738             
739             /* XTAL Frequency */
740             if (strcmp(argv[i],"-X") == 0 ||
741                 strcmp(argv[i],"-frequency") == 0) {
742                     simArgs[nsimArgs++] = "-X";
743                     simArgs[nsimArgs++] = strdup(argv[++i]);
744                     continue ;
745             }
746
747             /* serial port */
748             if (strcmp(argv[i],"-s") == 0) {
749                     simArgs[nsimArgs++] = "-s";         
750                     simArgs[nsimArgs++] = strdup(argv[++i]);
751                     continue ;
752             }
753
754             if (strcmp(argv[i],"-S") == 0) {
755                     simArgs[nsimArgs++] = "-s";         
756                     simArgs[nsimArgs++] = strdup(argv[++i]);
757                     continue ;
758             }   
759
760             fprintf(stderr,"unknown option %s --- ignored\n",
761                     argv[i]);
762         } else {
763             /* must be file name */
764             if (filename) {
765                 fprintf(stderr,"too many filenames .. parameter '%s' ignored\n",
766                         argv[i]);
767                 continue ;
768             }
769
770             filename = strtok(argv[i],".");
771
772         }           
773     }
774     
775     if (filename)
776         cmdFile(filename,NULL);
777 }
778   
779 /*-----------------------------------------------------------------*/
780 /* main -                                                          */
781 /*-----------------------------------------------------------------*/
782
783 int main ( int argc, char **argv)
784 {
785     printVersionInfo();
786     /* parse command line */
787     parseCmdLine(argc,argv);
788
789     commandLoop();
790     
791     return 0;
792 }