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