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