]> git.sur5r.net Git - cc65/blob - src/dbginfo/dbgsh.c
Fixed the " til " typos.
[cc65] / src / dbginfo / dbgsh.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  dbgsh.c                                  */
4 /*                                                                           */
5 /*                           debug info test shell                           */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2011,      Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <time.h>
41 #include <errno.h>
42
43 /* common */
44 #include "attrib.h"
45 #include "chartype.h"
46 #include "cmdline.h"
47 #include "coll.h"
48
49 /* dbginfo */
50 #include "dbginfo.h"
51
52
53
54 /*****************************************************************************/
55 /*                         Command handler forwards                          */
56 /*****************************************************************************/
57
58
59
60 static void CmdHelp (Collection* Args attribute ((unused)));
61 /* Output a help text */
62
63 static void CmdLoad (Collection* Args);
64 /* Load a debug info file */
65
66 static void CmdQuit (Collection* Args attribute ((unused)));
67 /* Terminate the application */
68
69 static void CmdShow (Collection* Args);
70 /* Show items from the debug info file */
71
72 static void CmdShowHelp (Collection* Args);
73 /* Print help for the show command */
74
75 static void CmdShowChildScopes (Collection* Args);
76 /* Show child scopes from the debug info file */
77
78 static void CmdShowCSymbol (Collection* Args);
79 /* Show c symbols from the debug info file */
80
81 static void CmdShowFunction (Collection* Args);
82 /* Show C functions from the debug info file */
83
84 static void CmdShowLibrary (Collection* Args);
85 /* Show libraries from the debug info file */
86
87 static void CmdShowLine (Collection* Args);
88 /* Show lines from the debug info file */
89
90 static void CmdShowModule (Collection* Args);
91 /* Show modules from the debug info file */
92
93 static void CmdShowScope (Collection* Args);
94 /* Show scopes from the debug info file */
95
96 static void CmdShowSegment (Collection* Args);
97 /* Show segments from the debug info file */
98
99 static void CmdShowSource (Collection* Args);
100 /* Show source files from the debug info file */
101
102 static void CmdShowSpan (Collection* Args);
103 /* Show spans from the debug info file */
104
105 static void CmdShowSymbol (Collection* Args);
106 /* Show symbols */
107
108 static void CmdShowSymDef (Collection* Args);
109 /* Show lines from the debug info file */
110
111 static void CmdShowSymRef (Collection* Args);
112 /* Show lines from the debug info file */
113
114 static void CmdShowType (Collection* Args);
115 /* Show types from the debug info file */
116
117 static void CmdUnload (Collection* Args attribute ((unused)));
118 /* Unload a debug info file */
119
120
121
122 /*****************************************************************************/
123 /*                                   Data                                    */
124 /*****************************************************************************/
125
126
127
128 /* Terminate flag - end program when set to true */
129 static int Terminate = 0;
130
131 /* The debug file data */
132 static cc65_dbginfo     Info = 0;
133
134 /* Error and warning counters */
135 static unsigned FileErrors   = 0;
136 static unsigned FileWarnings = 0;
137
138 /* Type of an id */
139 enum {
140     InvalidId,
141     CSymbolId,
142     LibraryId,
143     LineId,
144     ModuleId,
145     ScopeId,
146     SegmentId,
147     SourceId,
148     SpanId,
149     SymbolId,
150     TypeId
151 };
152
153 /* Structure that contains a command description */
154 typedef struct CmdEntry CmdEntry;
155 struct CmdEntry {
156     char        Cmd[12];
157     const char* Help;
158     int         ArgCount;
159     void        (*Func) (Collection*);
160 };
161
162 /* Table with main commands */
163 static const CmdEntry MainCmds[] = {
164     {
165         "exit",
166         0,
167         1,
168         CmdQuit
169     }, {
170         "help",
171         "Show available commands",
172         1,
173         CmdHelp
174     }, {
175         "load",
176         "Load a debug info file",
177         2,
178         CmdLoad
179     }, {
180         "quit",
181         "Terminate the shell",
182         1,
183         CmdQuit
184     }, {
185         "show",
186         "Show items from the info file",
187         -2,
188         CmdShow
189     }, {
190         "unload",
191         "Unload a debug info file",
192         1,
193         CmdUnload
194     },
195 };
196
197 /* Table with show commands */
198 static const CmdEntry ShowCmds[] = {
199     {
200         "childscopes",
201         "Show child scopes of other scopes.",
202         -2,
203         CmdShowChildScopes
204     }, {
205         "csym",
206         0,
207         -1,
208         CmdShowCSymbol
209     }, {
210         "csymbol",
211         "Show c symbols.",
212         -1,
213         CmdShowCSymbol
214     }, {
215         "func",
216         0,
217         -2,
218         CmdShowFunction
219     }, {
220         "function",
221         "Show c functions.",
222         -2,
223         CmdShowFunction
224     }, {
225         "help",
226         "Show available subcommands.",
227         1,
228         CmdShowHelp
229     }, {
230         "line",
231         "Show line info. May be followed by one or more line ids.",
232         -2,
233         CmdShowLine
234     }, {
235         "library",
236         "Show libraries. May be followed by one or more library ids.",
237         -1,
238         CmdShowLibrary
239     }, {
240         "module",
241         "Show modules. May be followed by one or more module ids.",
242         -1,
243         CmdShowModule
244     }, {
245         "scope",
246         "Show scopes. May be followed by one or more segment ids.",
247         -1,
248         CmdShowScope
249     }, {
250         "segment",
251         "Show segments. May be followed by one or more segment ids.",
252         -1,
253         CmdShowSegment
254     }, {
255         "source",
256         "Show sources. May be followed by one or more source file ids.",
257         -1,
258         CmdShowSource
259     }, {
260         "span",
261         "Show spans. May be followed by one or more span ids.",
262         -1,
263         CmdShowSpan
264     }, {
265         "symbol",
266         "Show symbols. May be followed by one or more symbol or scope ids.",
267         -2,
268         CmdShowSymbol
269     }, {
270         "symdef",
271         "Show where a symbol was defined. May be followed by one or more symbol ids.",
272         -2,
273         CmdShowSymDef
274     }, {
275         "symref",
276         "Show where a symbol was referenced. May be followed by one or more symbol ids.",
277         -2,
278         CmdShowSymRef
279     }, {
280         "type",
281         "Show type information. May be followed by one or more type ids.",
282         -2,
283         CmdShowType
284     },
285 };
286
287
288
289 /*****************************************************************************/
290 /*                                  Helpers                                  */
291 /*****************************************************************************/
292
293
294
295 static void NewLine (void)
296 /* Output a newline */
297 {
298     putchar ('\n');
299 }
300
301
302
303 static void Print (const char* Format, ...) attribute((format(printf,1,2)));
304 static void Print (const char* Format, ...)
305 /* Print a piece of output (no linefeed added) */
306 {
307     va_list ap;
308     va_start (ap, Format);
309     vprintf (Format, ap);
310     va_end (ap);
311 }
312
313
314
315 static void PrintLine (const char* Format, ...) attribute((format(printf,1,2)));
316 static void PrintLine (const char* Format, ...)
317 /* Print one line of output. The linefeed is supplied by the function */
318 {
319     va_list ap;
320     va_start (ap, Format);
321     vprintf (Format, ap);
322     NewLine ();
323     va_end (ap);
324 }
325
326
327
328 static void PrintSeparator (void)
329 /* Print a separator line */
330 {
331     PrintLine ("---------------------------------------------------------------------------");
332 }
333
334
335
336 static void FileError (const cc65_parseerror* Info)
337 /* Callback function - is called in case of errors */
338 {
339     /* Output a message */
340     PrintLine ("%s:%s(%lu): %s",
341                Info->type? "Error" : "Warning",
342                Info->name,
343                (unsigned long) Info->line,
344                Info->errormsg);
345
346     /* Bump the counters */
347     switch (Info->type) {
348         case CC65_WARNING:      ++FileWarnings;         break;
349         default:                ++FileErrors;           break;
350     }
351 }
352
353
354
355 static const CmdEntry* FindCmd (const char* Cmd, const CmdEntry* Tab, unsigned Count)
356 /* Search for a command in the given table */
357 {
358     unsigned I;
359     for (I = 0; I < Count; ++I, ++Tab) {
360         if (strcmp (Cmd, Tab->Cmd) == 0) {
361             return Tab;
362         }
363     }
364     return 0;
365 }
366
367
368
369 static void ExecCmd (Collection* Args, const CmdEntry* Tab, unsigned Count)
370 /* Search for the command in slot 0 of the given collection. If found, check
371 ** the argument count, then execute it. If there are problems, output a
372 ** diagnostic.
373 */
374 {
375     /* Search for the command, check number of args, then execute it */
376     const char* Cmd = CollAt (Args, 0);
377     const CmdEntry* E = FindCmd (Cmd, Tab, Count);
378     if (E == 0) {
379         PrintLine ("No such command: %s", Cmd);
380         return;
381     }
382
383     /* Check the number of arguments. Zero means that the function will check
384     ** itself. A negative count means that the function needs at least
385     ** abs(count) arguments. A positive count means that the function needs
386     ** exactly this number of arguments.
387     ** Note: The number includes the command itself.
388     */
389     if (E->ArgCount > 0 && (int)CollCount (Args) != E->ArgCount) {
390         /* Argument number mismatch */
391         switch (E->ArgCount) {
392
393             case 1:
394                 PrintLine ("Command doesn't accept an argument");
395                 return;
396
397             case 2:
398                 PrintLine ("Command requires an argument");
399                 return;
400
401             default:
402                 PrintLine ("Command requires %d arguments", E->ArgCount-1);
403                 return;
404         }
405     } else if (E->ArgCount < 0 && (int)CollCount (Args) < -E->ArgCount) {
406         /* Argument number mismatch */
407         switch (E->ArgCount) {
408
409             case -2:
410                 PrintLine ("Command requires at least one argument");
411                 return;
412
413             default:
414                 PrintLine ("Command requires at least %d arguments", E->ArgCount-1);
415                 return;
416         }
417     } else {
418         /* Remove the command from the argument list, then execute it */
419         CollDelete (Args, 0);
420         E->Func (Args);
421     }
422 }
423
424
425
426 static void PrintHelp (const CmdEntry* Tab, unsigned Count)
427 /* Output help for one command table */
428 {
429     while (Count--) {
430         /* Ignore the commands without help text */
431         if (Tab->Help) {
432             PrintLine ("%-*s%s", (int) sizeof (Tab->Cmd) + 2, Tab->Cmd, Tab->Help);
433         }
434         ++Tab;
435     }
436 }
437
438
439
440 static unsigned FindIdType (const char* TypeName)
441 /* Find an id type by its name. Returns the type or InvalidId. */
442 {
443     static const struct {
444         char            Name[8];
445         unsigned        Type;
446     } TypeTab[] = {
447         {   "l",        LineId          },
448         {   "lib",      LibraryId       },
449         {   "library",  LibraryId       },
450         {   "line",     LineId          },
451         {   "m",        ModuleId        },
452         {   "mod",      ModuleId        },
453         {   "module",   ModuleId        },
454         {   "s",        SymbolId        },
455         {   "sc",       ScopeId         },
456         {   "scope",    ScopeId         },
457         {   "seg",      SegmentId       },
458         {   "segment",  SegmentId       },
459         {   "source",   SourceId        },
460         {   "src",      SourceId        },
461         {   "sp",       SpanId          },
462         {   "span",     SpanId          },
463         {   "sym",      SymbolId        },
464         {   "symbol",   SymbolId        },
465         {   "t",        TypeId          },
466         {   "type",     TypeId          },
467     };
468
469     unsigned I;
470     for (I = 0; I < sizeof(TypeTab) / sizeof(TypeTab[0]); ++I) {
471         if (strcmp (TypeName, TypeTab[I].Name) == 0) {
472             return TypeTab[I].Type;
473         }
474     }
475     return InvalidId;
476 }
477
478
479
480 static int GetId (const char* S, unsigned* Id, unsigned* IdType)
481 /* Parse a string for an id. If a valid id is found, it is placed in Id and
482 ** the function returns true. If an optional type is found, it is placed in
483 ** IdType, otherwise IdType is left unchanged. If no id is found, the
484 ** function returns false.
485 */
486 {
487     char TypeBuf[20];
488     char C;
489     if (sscanf (S, "%u%c", Id, &C) == 1) {
490         /* Just an id found, return it */
491         return 1;
492     }
493     if (sscanf (S, "%19[a-z]:%u%c", TypeBuf, Id, &C) == 2) {
494         *IdType = FindIdType (TypeBuf);
495         return (*IdType != InvalidId);
496     }
497
498     /* Not a valid id */
499     return 0;
500 }
501
502
503
504 /*****************************************************************************/
505 /*                      Output functions for item lists                      */
506 /*****************************************************************************/
507
508
509
510 static void PrintAddr (cc65_addr Addr, unsigned FieldWidth)
511 /* Output an address */
512 {
513     Print ("$%06lX", (unsigned long) Addr);
514     if (FieldWidth > 7) {
515         Print ("%*s", FieldWidth - 7, "");
516     }
517 }
518
519
520
521 static void PrintNumber (long Num, unsigned Width, unsigned FieldWidth)
522 /* Output a number */
523 {
524     Print ("%*ld", Width, Num);
525     if (FieldWidth > Width) {
526         Print ("%*s", FieldWidth - Width, "");
527     }
528 }
529
530
531
532 static void PrintId (unsigned Id, unsigned FieldWidth)
533 /* Output an id field */
534 {
535     if (Id == CC65_INV_ID) {
536         Print ("   -");
537     } else {
538         Print ("%4u", Id);
539     }
540     if (FieldWidth > 4) {
541         Print ("%*s", FieldWidth - 4, "");
542     }
543 }
544
545
546
547 static void PrintSize (cc65_size Size, unsigned FieldWidth)
548 /* Output a size */
549 {
550     Print ("$%04lX", (unsigned long) Size);
551     if (FieldWidth > 5) {
552         Print ("%*s", FieldWidth - 5, "");
553     }
554 }
555
556
557
558 static void PrintTime (time_t T, unsigned FieldWidth)
559 /* Output a time stamp of some sort */
560 {
561     /* Convert to string */
562     char Buf[100];
563     unsigned Len = strftime (Buf, sizeof (Buf), "%Y-%m-%d %H:%M:%S", localtime (&T));
564
565     /* Output */
566     Print ("%s", Buf);
567     if (FieldWidth > Len) {
568         Print ("%*s", FieldWidth - Len, "");
569     }
570 }
571
572
573
574 static void PrintCSymbolHeader (void)
575 /* Output a header for a list of C symbols */
576 {
577     /* Header */
578     PrintLine ("  id  name                        type  kind   sc   offs  symbol scope");
579     PrintSeparator ();
580 }
581
582
583
584 static void PrintCSymbols (const cc65_csyminfo* S)
585 /* Output a list of C symbols */
586 {
587     unsigned I;
588     const cc65_csymdata* D;
589
590     /* Segments */
591     for (I = 0, D = S->data; I < S->count; ++I, ++D) {
592         PrintId (D->csym_id, 6);
593         Print ("%-28s", D->csym_name);
594         PrintId (D->type_id, 6);
595         PrintNumber (D->csym_kind, 4, 6);
596         PrintNumber (D->csym_sc, 4, 6);
597         PrintNumber (D->csym_offs, 4, 8);
598         PrintId (D->symbol_id, 6);
599         PrintId (D->scope_id, 0);
600         NewLine ();
601     }
602 }
603
604
605
606 static void PrintLibraryHeader (void)
607 /* Output the header for a library list */
608 {
609     PrintLine ("  id    name");
610     PrintSeparator ();
611 }
612
613
614
615 static void PrintLibraries (const cc65_libraryinfo* L)
616 /* Output a list of libraries */
617 {
618     unsigned I;
619     const cc65_librarydata* D;
620
621     /* Libraries */
622     for (I = 0, D = L->data; I < L->count; ++I, ++D) {
623         PrintId (D->library_id, 8);
624         Print ("%-24s", D->library_name);
625         NewLine ();
626     }
627 }
628
629
630
631 static void PrintLineHeader (void)
632 /* Output a header for a line list */
633 {
634     /* Header */
635     PrintLine ("  id    source  line    type  count");
636     PrintSeparator ();
637 }
638
639
640
641 static void PrintLines (const cc65_lineinfo* L)
642 /* Output a list of lines */
643 {
644     unsigned I;
645     const cc65_linedata* D;
646
647     /* Lines */
648     for (I = 0, D = L->data; I < L->count; ++I, ++D) {
649         PrintId (D->line_id, 8);
650         PrintId (D->source_id, 8);
651         PrintNumber (D->source_line, 6, 9);
652         PrintNumber (D->line_type, 4, 6);
653         PrintNumber (D->count, 3, 0);
654         NewLine ();
655     }
656 }
657
658
659
660 static void PrintModuleHeader (void)
661 /* Output a header for a module list */
662 {
663     /* Header */
664     PrintLine ("  id    name                    source  library  scope");
665     PrintSeparator ();
666 }
667
668
669
670 static void PrintModules (const cc65_moduleinfo* M)
671 /* Output a list of modules */
672 {
673     unsigned I;
674     const cc65_moduledata* D;
675
676     /* Modules */
677     for (I = 0, D = M->data; I < M->count; ++I, ++D) {
678         PrintId (D->module_id, 8);
679         Print ("%-24s", D->module_name);
680         PrintId (D->source_id, 8);
681         PrintId (D->library_id, 9);
682         PrintId (D->scope_id, 6);
683         NewLine ();
684     }
685 }
686
687
688
689 static void PrintScopeHeader (void)
690 /* Output a header for a list of scopes */
691 {
692     /* Header */
693     PrintLine ("  id    name                    type    size   parent  symbol  module");
694     PrintSeparator ();
695 }
696
697
698
699 static void PrintScopes (const cc65_scopeinfo* S)
700 /* Output a list of scopes */
701 {
702     unsigned I;
703     const cc65_scopedata* D;
704
705     /* Segments */
706     for (I = 0, D = S->data; I < S->count; ++I, ++D) {
707         PrintId (D->scope_id, 8);
708         Print ("%-24s", D->scope_name);
709         PrintNumber (D->scope_type, 4, 8);     /* ## */
710         PrintSize (D->scope_size, 8);
711         PrintId (D->parent_id, 8);
712         PrintId (D->symbol_id, 8);
713         PrintId (D->module_id, 0);
714         NewLine ();
715     }
716 }
717
718
719
720 static void PrintSegmentHeader (void)
721 /* Output a header for a list of segments */
722 {
723     /* Header */
724     PrintLine ("  id    name            address  size   output file     offs");
725     PrintSeparator ();
726 }
727
728
729
730 static void PrintSegments (const cc65_segmentinfo* S)
731 /* Output a list of segments */
732 {
733     unsigned I;
734     const cc65_segmentdata* D;
735
736     /* Segments */
737     for (I = 0, D = S->data; I < S->count; ++I, ++D) {
738         PrintId (D->segment_id, 8);
739         Print ("%-16s", D->segment_name);
740         PrintAddr (D->segment_start, 9);
741         PrintSize (D->segment_size, 7);
742         Print ("%-16s", D->output_name? D->output_name : "");
743         PrintSize (D->output_offs, 6);
744         NewLine ();
745     }
746 }
747
748
749
750 static void PrintSourceHeader (void)
751 /* Output a header for a list of source files */
752 {
753     /* Header */
754     PrintLine ("  id    name                            size   modification time");
755     PrintSeparator ();
756 }
757
758
759
760 static void PrintSources (const cc65_sourceinfo* S)
761 /* Output a list of sources */
762 {
763     unsigned I;
764     const cc65_sourcedata* D;
765
766     /* Segments */
767     for (I = 0, D = S->data; I < S->count; ++I, ++D) {
768         PrintId (D->source_id, 8);
769         Print ("%-30s", D->source_name);
770         PrintNumber (D->source_size, 7, 9);
771         PrintTime (D->source_mtime, 0);
772         NewLine ();
773     }
774 }
775
776
777
778 static void PrintSpanHeader (void)
779 /* Output a header for a list of spans */
780 {
781     /* Header */
782     PrintLine ("  id    start    end     seg   type   lines  scopes");
783     PrintSeparator ();
784 }
785
786
787
788 static void PrintSpans (const cc65_spaninfo* S)
789 /* Output a list of spans */
790 {
791     unsigned I;
792     const cc65_spandata* D;
793
794     /* Segments */
795     for (I = 0, D = S->data; I < S->count; ++I, ++D) {
796         PrintId (D->span_id, 7);
797         PrintAddr (D->span_start, 8);
798         PrintAddr (D->span_end, 9);
799         PrintId (D->segment_id, 7);
800         PrintId (D->type_id, 6);
801         PrintNumber (D->line_count, 6, 7);
802         PrintNumber (D->scope_count, 7, 0);
803         NewLine ();
804     }
805 }
806
807
808
809 static void PrintSymbolHeader (void)
810 /* Output a header for a list of symbols */
811 {
812     /* Header */
813     PrintLine ("  id  name                    type  size  value  export  seg  scope parent");
814     PrintSeparator ();
815 }
816
817
818
819 static void PrintSymbols (const cc65_symbolinfo* S)
820 /* Output a list of symbols */
821 {
822     unsigned I;
823     const cc65_symboldata* D;
824
825     /* Segments */
826     for (I = 0, D = S->data; I < S->count; ++I, ++D) {
827         PrintId (D->symbol_id, 6);
828         Print ("%-24s", D->symbol_name);
829         PrintNumber (D->symbol_type, 4, 6);
830         PrintNumber (D->symbol_size, 4, 6);
831         PrintNumber (D->symbol_value, 5, 7);
832         PrintId (D->export_id, 7);
833         PrintId (D->segment_id, 6);
834         PrintId (D->scope_id, 6);
835         PrintId (D->parent_id, 0);
836         NewLine ();
837     }
838 }
839
840
841
842 static void PrintTypeHeader (void)
843 /* Output a header for a list of types */
844 {
845     /* Header */
846     PrintLine ("  id  description");
847     PrintSeparator ();
848 }
849
850
851
852 static void PrintType (unsigned Id, const cc65_typedata* T)
853 /* Output one type */
854 {
855     /* Output the id */
856     PrintId (Id, 6);
857
858     while (1) {
859         switch (T->what) {
860
861             case CC65_TYPE_VOID:
862                 Print ("VOID");
863                 goto ExitPoint;
864
865             case CC65_TYPE_BYTE:
866                 Print ("BYTE");
867                 goto ExitPoint;
868
869             case CC65_TYPE_WORD:
870                 Print ("WORD");
871                 goto ExitPoint;
872
873             case CC65_TYPE_DBYTE:
874                 Print ("DBYTE");
875                 goto ExitPoint;
876
877             case CC65_TYPE_DWORD:
878                 Print ("DWORD");
879                 goto ExitPoint;
880
881             case CC65_TYPE_FARPTR:
882                 Print ("FAR ");
883                 /* FALLTHROUGH */
884
885             case CC65_TYPE_PTR:
886                 Print ("POINTER TO ");
887                 T = T->data.ptr.ind_type;
888                 break;
889
890             case CC65_TYPE_ARRAY:
891                 Print ("ARRAY[%u] OF ", T->data.array.ele_count);
892                 T = T->data.array.ele_type;
893                 break;
894
895             default:
896                 /* Anything else is currently not implemented */
897                 Print ("***NOT IMPLEMENTED***");
898                 goto ExitPoint;
899         }
900     }
901
902 ExitPoint:
903     NewLine ();
904 }
905
906
907
908 /*****************************************************************************/
909 /*                            Debug file handling                            */
910 /*****************************************************************************/
911
912
913
914 static void UnloadFile (void)
915 /* Unload the debug info file */
916 {
917     if (Info) {
918         cc65_free_dbginfo (Info);
919         Info = 0;
920     }
921 }
922
923
924
925 static int FileIsLoaded (void)
926 /* Return true if the file is open and has loaded without errors: If not,
927 ** print an error message and return false.
928 */
929 {
930     /* File open? */
931     if (Info == 0) {
932         PrintLine ("No debug info file");
933         return 0;
934     }
935
936     /* Errors on load? */
937     if (FileErrors > 0) {
938         PrintLine ("File had load errors!");
939         return 0;
940     }
941
942     /* Warnings on load? */
943     if (FileWarnings > 0) {
944         PrintLine ("Beware - file had load warnings!");
945     }
946
947     /* Ok */
948     return 1;
949 }
950
951
952
953 /*****************************************************************************/
954 /*                             Command handlers                              */
955 /*****************************************************************************/
956
957
958
959 static void CmdHelp (Collection* Args attribute ((unused)))
960 /* Output a help text */
961 {
962     PrintHelp (MainCmds, sizeof (MainCmds) / sizeof (MainCmds[0]));
963 }
964
965
966
967 static void CmdLoad (Collection* Args)
968 /* Load a debug info file */
969 {
970     /* Unload a loaded file */
971     UnloadFile ();
972
973     /* Clear the counters */
974     FileErrors   = 0;
975     FileWarnings = 0;
976
977     /* Open the debug info file */
978     Info = cc65_read_dbginfo (CollAt (Args, 0), FileError);
979
980     /* Print a status */
981     if (FileErrors > 0) {
982         PrintLine ("File loaded with %u errors", FileErrors);
983     } else if (FileWarnings > 0) {
984         PrintLine ("File loaded with %u warnings", FileWarnings);
985     } else {
986         PrintLine ("File loaded successfully");
987     }
988 }
989
990
991
992 static void CmdQuit (Collection* Args attribute ((unused)))
993 /* Terminate the application */
994 {
995     UnloadFile ();
996     Terminate = 1;
997 }
998
999
1000
1001 static void CmdShow (Collection* Args)
1002 /* Show items from the debug info file */
1003 {
1004     /* Search for the subcommand, check number of args, then execute it */
1005     ExecCmd (Args, ShowCmds, sizeof (ShowCmds) / sizeof (ShowCmds[0]));
1006 }
1007
1008
1009
1010 static void CmdShowHelp (Collection* Args attribute ((unused)))
1011 /* Print help for the show command */
1012 {
1013     PrintHelp (ShowCmds, sizeof (ShowCmds) / sizeof (ShowCmds[0]));
1014 }
1015
1016
1017
1018 static void CmdShowChildScopes (Collection* Args)
1019 /* Show child scopes from the debug info file */
1020 {
1021     const cc65_scopeinfo* S;
1022     unsigned I;
1023
1024     /* Be sure a file is loaded */
1025     if (!FileIsLoaded ()) {
1026         return;
1027     }
1028
1029     /* Output the header */
1030     PrintScopeHeader ();
1031
1032     /* Output child scopes for all arguments */
1033     for (I = 0; I < CollCount (Args); ++I) {
1034
1035         /* Parse the argument */
1036         unsigned Id;
1037         unsigned IdType = ScopeId;
1038         if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1039             /* Fetch list depending on type */
1040             switch (IdType) {
1041                 case ScopeId:
1042                     S = cc65_childscopes_byid (Info, Id);
1043                     break;
1044                 default:
1045                     S = 0;
1046                     PrintLine ("Invalid id type");
1047                     break;
1048             }
1049         } else {
1050             /* Invalid id */
1051             S = 0;
1052         }
1053
1054         /* Output the list */
1055         if (S) {
1056             PrintScopes (S);
1057             cc65_free_scopeinfo (Info, S);
1058         }
1059     }
1060 }
1061
1062
1063
1064 static void CmdShowCSymbol (Collection* Args)
1065 /* Show C symbols from the debug info file */
1066 {
1067     const cc65_csyminfo* S;
1068
1069     /* Be sure a file is loaded */
1070     if (!FileIsLoaded ()) {
1071         return;
1072     }
1073
1074     /* Output the header */
1075     PrintCSymbolHeader ();
1076
1077     /* No arguments means show all libraries */
1078     if (CollCount (Args) == 0) {
1079
1080         /* Fetch the list of c symbols */
1081         S = cc65_get_csymlist (Info);
1082
1083         /* Output the c symbols */
1084         PrintCSymbols (S);
1085
1086         /* Free the list */
1087         cc65_free_csyminfo (Info, S);
1088
1089     } else {
1090
1091         /* Output c symbols for all arguments */
1092         unsigned I;
1093         for (I = 0; I < CollCount (Args); ++I) {
1094
1095             /* Parse the argument */
1096             unsigned Id;
1097             unsigned IdType = CSymbolId;
1098             if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1099                 /* Fetch list depending on type */
1100                 switch (IdType) {
1101                     case CSymbolId:
1102                         S = cc65_csym_byid (Info, Id);
1103                         break;
1104                     case ScopeId:
1105                         S = cc65_csym_byscope (Info, Id);
1106                         break;
1107                     default:
1108                         S = 0;
1109                         PrintLine ("Invalid id type");
1110                         break;
1111                 }
1112             } else {
1113                 /* Invalid id */
1114                 S = 0;
1115             }
1116
1117             /* Output the list */
1118             if (S) {
1119                 PrintCSymbols (S);
1120                 cc65_free_csyminfo (Info, S);
1121             }
1122         }
1123     }
1124 }
1125
1126
1127
1128 static void CmdShowFunction (Collection* Args)
1129 /* Show C functions from the debug info file */
1130 {
1131     const cc65_csyminfo* S;
1132     unsigned I;
1133
1134     /* Be sure a file is loaded */
1135     if (!FileIsLoaded ()) {
1136         return;
1137     }
1138
1139     /* Output the header */
1140     PrintCSymbolHeader ();
1141
1142     /* Output c symbols for all arguments */
1143     for (I = 0; I < CollCount (Args); ++I) {
1144
1145         /* Parse the argument */
1146         unsigned Id;
1147         unsigned IdType = ModuleId;
1148         if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1149             /* Fetch list depending on type */
1150             switch (IdType) {
1151                 case ModuleId:
1152                     S = cc65_cfunc_bymodule (Info, Id);
1153                     break;
1154                 default:
1155                     S = 0;
1156                     PrintLine ("Invalid id type");
1157                     break;
1158             }
1159         } else {
1160             /* An invalid id may be a function name */
1161             S = cc65_cfunc_byname (Info, CollConstAt (Args, I));
1162         }
1163
1164         /* Output the list */
1165         if (S) {
1166             PrintCSymbols (S);
1167             cc65_free_csyminfo (Info, S);
1168         }
1169     }
1170 }
1171
1172
1173
1174 static void CmdShowLine (Collection* Args)
1175 /* Show lines from the debug info file */
1176 {
1177     const cc65_lineinfo* L;
1178     unsigned I;
1179
1180     /* Be sure a file is loaded */
1181     if (!FileIsLoaded ()) {
1182         return;
1183     }
1184
1185     /* Output the header */
1186     PrintLineHeader ();
1187
1188     for (I = 0; I < CollCount (Args); ++I) {
1189
1190         /* Parse the argument */
1191         unsigned Id;
1192         unsigned IdType = LineId;
1193         if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1194             /* Fetch list depending on type */
1195             switch (IdType) {
1196
1197                 case LineId:
1198                     L = cc65_line_byid (Info, Id);
1199                     break;
1200
1201                 case SourceId:
1202                     L = cc65_line_bysource (Info, Id);
1203                     break;
1204
1205                 case SymbolId:
1206                     /* ### not very clean */
1207                     L = cc65_line_bysymdef (Info, Id);
1208                     if (L) {
1209                         PrintLines (L);
1210                         cc65_free_lineinfo (Info, L);
1211                     }
1212                     L = cc65_line_bysymref (Info, Id);
1213                     break;
1214
1215                 default:
1216                     L = 0;
1217                     PrintLine ("Invalid id type");
1218                     break;
1219             }
1220         } else {
1221             /* Ignore the invalid id */
1222             L = 0;
1223         }
1224
1225         /* Output the list */
1226         if (L) {
1227             PrintLines (L);
1228             cc65_free_lineinfo (Info, L);
1229         }
1230
1231     }
1232 }
1233
1234
1235
1236 static void CmdShowLibrary (Collection* Args)
1237 /* Show libraries from the debug info file */
1238 {
1239     const cc65_libraryinfo* L;
1240
1241     /* Be sure a file is loaded */
1242     if (!FileIsLoaded ()) {
1243         return;
1244     }
1245
1246     /* Output the header */
1247     PrintLibraryHeader ();
1248
1249     /* No arguments means show all libraries */
1250     if (CollCount (Args) == 0) {
1251
1252         /* Fetch the list of libraries */
1253         L = cc65_get_librarylist (Info);
1254
1255         /* Output the libraries */
1256         PrintLibraries (L);
1257
1258         /* Free the list */
1259         cc65_free_libraryinfo (Info, L);
1260
1261     } else {
1262
1263         unsigned I;
1264         for (I = 0; I < CollCount (Args); ++I) {
1265
1266             /* Parse the argument */
1267             unsigned Id;
1268             unsigned IdType = LibraryId;
1269             if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1270                 /* Fetch list depending on type */
1271                 switch (IdType) {
1272                     case LibraryId:
1273                         L = cc65_library_byid (Info, Id);
1274                         break;
1275                     default:
1276                         L = 0;
1277                         PrintLine ("Invalid id type");
1278                         break;
1279                 }
1280             } else {
1281                 /* Ignore the invalid id */
1282                 L = 0;
1283             }
1284
1285             /* Output the list */
1286             if (L) {
1287                 PrintLibraries (L);
1288                 cc65_free_libraryinfo (Info, L);
1289             }
1290         }
1291     }
1292 }
1293
1294
1295
1296 static void CmdShowModule (Collection* Args)
1297 /* Show modules from the debug info file */
1298 {
1299     const cc65_moduleinfo* M;
1300
1301     /* Be sure a file is loaded */
1302     if (!FileIsLoaded ()) {
1303         return;
1304     }
1305
1306     /* Output the header */
1307     PrintModuleHeader ();
1308
1309     /* No arguments means show all modules */
1310     if (CollCount (Args) == 0) {
1311
1312         /* Fetch the list of modules */
1313         M = cc65_get_modulelist (Info);
1314
1315         /* Output the modules */
1316         PrintModules (M);
1317
1318         /* Free the list */
1319         cc65_free_moduleinfo (Info, M);
1320
1321     } else {
1322
1323         unsigned I;
1324         for (I = 0; I < CollCount (Args); ++I) {
1325
1326             /* Parse the argument */
1327             unsigned Id;
1328             unsigned IdType = ModuleId;
1329             if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1330                 /* Fetch list depending on type */
1331                 switch (IdType) {
1332                     case ModuleId:
1333                         M = cc65_module_byid (Info, Id);
1334                         break;
1335                     default:
1336                         M = 0;
1337                         PrintLine ("Invalid id type");
1338                         break;
1339                 }
1340             } else {
1341                 /* Ignore the invalid id */
1342                 M = 0;
1343             }
1344
1345             /* Output the list */
1346             if (M) {
1347                 PrintModules (M);
1348                 cc65_free_moduleinfo (Info, M);
1349             }
1350
1351         }
1352     }
1353 }
1354
1355
1356
1357 static void CmdShowScope (Collection* Args)
1358 /* Show scopes from the debug info file */
1359 {
1360     const cc65_scopeinfo* S;
1361
1362     /* Be sure a file is loaded */
1363     if (!FileIsLoaded ()) {
1364         return;
1365     }
1366
1367     /* Output the header */
1368     PrintScopeHeader ();
1369
1370     /* No arguments means show all modules */
1371     if (CollCount (Args) == 0) {
1372
1373         /* Fetch the list of segments */
1374         S = cc65_get_scopelist (Info);
1375
1376         /* Output the segments */
1377         PrintScopes (S);
1378
1379         /* Free the list */
1380         cc65_free_scopeinfo (Info, S);
1381
1382     } else {
1383
1384         unsigned I;
1385         for (I = 0; I < CollCount (Args); ++I) {
1386
1387             /* Parse the argument */
1388             unsigned Id;
1389             unsigned IdType = ScopeId;
1390             if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1391                 /* Fetch list depending on type */
1392                 switch (IdType) {
1393                     case ModuleId:
1394                         S = cc65_scope_bymodule (Info, Id);
1395                         break;
1396                     case ScopeId:
1397                         S = cc65_scope_byid (Info, Id);
1398                         break;
1399                     default:
1400                         S = 0;
1401                         PrintLine ("Invalid id type");
1402                         break;
1403                 }
1404             } else {
1405                 /* An invalid id may be a scope name */
1406                 S = cc65_scope_byname (Info, CollConstAt (Args, I));
1407             }
1408
1409             /* Output the list */
1410             if (S) {
1411                 PrintScopes (S);
1412                 cc65_free_scopeinfo (Info, S);
1413             }
1414         }
1415     }
1416 }
1417
1418
1419
1420 static void CmdShowSegment (Collection* Args)
1421 /* Show segments from the debug info file */
1422 {
1423     const cc65_segmentinfo* S;
1424
1425     /* Be sure a file is loaded */
1426     if (!FileIsLoaded ()) {
1427         return;
1428     }
1429
1430     /* Output the header */
1431     PrintSegmentHeader ();
1432
1433     /* No arguments means show all modules */
1434     if (CollCount (Args) == 0) {
1435
1436         /* Fetch the list of segments */
1437         S = cc65_get_segmentlist (Info);
1438
1439         /* Output the segments */
1440         PrintSegments (S);
1441
1442         /* Free the list */
1443         cc65_free_segmentinfo (Info, S);
1444
1445     } else {
1446
1447         unsigned I;
1448         for (I = 0; I < CollCount (Args); ++I) {
1449
1450             /* Parse the argument */
1451             unsigned Id;
1452             unsigned IdType = SegmentId;
1453             if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1454                 /* Fetch list depending on type */
1455                 switch (IdType) {
1456                     case SegmentId:
1457                         S = cc65_segment_byid (Info, Id);
1458                         break;
1459                     default:
1460                         S = 0;
1461                         PrintLine ("Invalid id type");
1462                         break;
1463                 }
1464             } else {
1465                 /* An invalid id may be a segment name */
1466                 S = cc65_segment_byname (Info, CollConstAt (Args, I));
1467             }
1468
1469             /* Output the list */
1470             if (S) {
1471                 PrintSegments (S);
1472                 cc65_free_segmentinfo (Info, S);
1473             }
1474         }
1475     }
1476 }
1477
1478
1479
1480 static void CmdShowSource (Collection* Args)
1481 /* Show source files from the debug info file */
1482 {
1483     const cc65_sourceinfo* S;
1484
1485     /* Be sure a file is loaded */
1486     if (!FileIsLoaded ()) {
1487         return;
1488     }
1489
1490     /* Output the header */
1491     PrintSourceHeader ();
1492
1493     /* No arguments means show all modules */
1494     if (CollCount (Args) == 0) {
1495
1496         /* Fetch the list of source files */
1497         S = cc65_get_sourcelist (Info);
1498
1499         /* Output the source files */
1500         PrintSources (S);
1501
1502         /* Free the list */
1503         cc65_free_sourceinfo (Info, S);
1504
1505     } else {
1506
1507         unsigned I;
1508         for (I = 0; I < CollCount (Args); ++I) {
1509
1510             /* Parse the argument */
1511             unsigned Id;
1512             unsigned IdType = SourceId;
1513             if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1514                 /* Fetch list depending on type */
1515                 switch (IdType) {
1516                     case ModuleId:
1517                         S = cc65_source_bymodule (Info, Id);
1518                         break;
1519                     case SourceId:
1520                         S = cc65_source_byid (Info, Id);
1521                         break;
1522                     default:
1523                         S = 0;
1524                         PrintLine ("Invalid id type");
1525                         break;
1526                 }
1527             } else {
1528                 /* Ignore the invalid id */
1529                 S = 0;
1530             }
1531
1532             /* Output the list */
1533             if (S) {
1534                 PrintSources (S);
1535                 cc65_free_sourceinfo (Info, S);
1536             }
1537         }
1538     }
1539 }
1540
1541
1542
1543 static void CmdShowSpan (Collection* Args)
1544 /* Show spans from the debug info file */
1545 {
1546     const cc65_spaninfo* S;
1547     unsigned I;
1548
1549     /* Be sure a file is loaded */
1550     if (!FileIsLoaded ()) {
1551         return;
1552     }
1553
1554     /* Output the header */
1555     PrintSpanHeader ();
1556
1557     for (I = 0; I < CollCount (Args); ++I) {
1558
1559         /* Parse the argument */
1560         unsigned Id;
1561         unsigned IdType = SpanId;
1562         if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1563             /* Fetch list depending on type */
1564             switch (IdType) {
1565                 case LineId:
1566                     S = cc65_span_byline (Info, Id);
1567                     break;
1568
1569                 case ScopeId:
1570                     S = cc65_span_byscope (Info, Id);
1571                     break;
1572                 case SpanId:
1573                     S = cc65_span_byid (Info, Id);
1574                     break;
1575                 default:
1576                     S = 0;
1577                     PrintLine ("Invalid id type");
1578                     break;
1579             }
1580         } else {
1581             /* Ignore the invalid id */
1582             S = 0;
1583         }
1584
1585         /* Output the list */
1586         if (S) {
1587             PrintSpans (S);
1588             cc65_free_spaninfo (Info, S);
1589         }
1590     }
1591 }
1592
1593
1594
1595 static void CmdShowSymbol (Collection* Args)
1596 /* Show symbols from the debug info file */
1597 {
1598     const cc65_symbolinfo* S;
1599     unsigned I;
1600
1601     /* Be sure a file is loaded */
1602     if (!FileIsLoaded ()) {
1603         return;
1604     }
1605
1606     /* Output the header */
1607     PrintSymbolHeader ();
1608
1609     for (I = 0; I < CollCount (Args); ++I) {
1610
1611         /* Parse the argument */
1612         unsigned Id;
1613         unsigned IdType = SymbolId;
1614         if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1615             /* Fetch list depending on type */
1616             switch (IdType) {
1617
1618                 case ScopeId:
1619                     S = cc65_symbol_byscope (Info, Id);
1620                     break;
1621
1622                 case SymbolId:
1623                     S = cc65_symbol_byid (Info, Id);
1624                     break;
1625
1626                 default:
1627                     S = 0;
1628                     PrintLine ("Invalid id type");
1629                     break;
1630             }
1631         } else {
1632             /* Ignore the invalid id */
1633             S = 0;
1634         }
1635
1636         /* Output the list */
1637         if (S) {
1638             PrintSymbols (S);
1639             cc65_free_symbolinfo (Info, S);
1640         }
1641     }
1642 }
1643
1644
1645
1646 static void CmdShowSymDef (Collection* Args)
1647 /* Show symbol definitions from the debug info file */
1648 {
1649     const cc65_lineinfo* L;
1650     unsigned I;
1651
1652     /* Be sure a file is loaded */
1653     if (!FileIsLoaded ()) {
1654         return;
1655     }
1656
1657     /* Output the header */
1658     PrintLineHeader ();
1659
1660     for (I = 0; I < CollCount (Args); ++I) {
1661
1662         /* Parse the argument */
1663         unsigned Id;
1664         unsigned IdType = SymbolId;
1665         if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1666             /* Fetch list depending on type */
1667             switch (IdType) {
1668
1669                 case SymbolId:
1670                     L = cc65_line_bysymdef (Info, Id);
1671                     break;
1672
1673                 default:
1674                     L = 0;
1675                     PrintLine ("Invalid id type");
1676                     break;
1677             }
1678         } else {
1679             /* Ignore the invalid id */
1680             L = 0;
1681         }
1682
1683         /* Output the list */
1684         if (L) {
1685             PrintLines (L);
1686             cc65_free_lineinfo (Info, L);
1687         }
1688     }
1689 }
1690
1691
1692
1693 static void CmdShowSymRef (Collection* Args)
1694 /* Show symbol references from the debug info file */
1695 {
1696     const cc65_lineinfo* L;
1697     unsigned I;
1698
1699     /* Be sure a file is loaded */
1700     if (!FileIsLoaded ()) {
1701         return;
1702     }
1703
1704     /* Output the header */
1705     PrintLineHeader ();
1706
1707     for (I = 0; I < CollCount (Args); ++I) {
1708
1709         /* Parse the argument */
1710         unsigned Id;
1711         unsigned IdType = SymbolId;
1712         if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1713             /* Fetch list depending on type */
1714             switch (IdType) {
1715
1716                 case SymbolId:
1717                     L = cc65_line_bysymref (Info, Id);
1718                     break;
1719
1720                 default:
1721                     L = 0;
1722                     PrintLine ("Invalid id type");
1723                     break;
1724             }
1725         } else {
1726             /* Ignore the invalid id */
1727             L = 0;
1728         }
1729
1730         /* Output the list */
1731         if (L) {
1732             PrintLines (L);
1733             cc65_free_lineinfo (Info, L);
1734         }
1735     }
1736 }
1737
1738
1739
1740 static void CmdShowType (Collection* Args)
1741 /* Show types from the debug info file */
1742 {
1743     const cc65_typedata* T;
1744     const cc65_spaninfo* S;
1745     unsigned I;
1746
1747     /* Be sure a file is loaded */
1748     if (!FileIsLoaded ()) {
1749         return;
1750     }
1751
1752     /* Output the header */
1753     PrintTypeHeader ();
1754
1755     for (I = 0; I < CollCount (Args); ++I) {
1756
1757         /* Parse the argument */
1758         unsigned Id;
1759         unsigned IdType = TypeId;
1760         if (GetId (CollConstAt (Args, I), &Id, &IdType)) {
1761             /* Fetch list depending on type */
1762             switch (IdType) {
1763
1764                 case SpanId:
1765                     S = cc65_span_byid (Info, Id);
1766                     if (S == 0 || S->count == 0) {
1767                         T = 0;
1768                         break;
1769                     }
1770                     Id = S->data[0].type_id;
1771                     /* FALLTHROUGH */
1772
1773                 case TypeId:
1774                     T = cc65_type_byid (Info, Id);
1775                     break;
1776
1777                 default:
1778                     T = 0;
1779                     PrintLine ("Invalid id type");
1780                     break;
1781             }
1782         } else {
1783             /* Ignore the invalid id */
1784             T = 0;
1785         }
1786
1787         /* Output the list */
1788         if (T) {
1789             PrintType (Id, T);
1790             cc65_free_typedata (Info, T);
1791         }
1792     }
1793 }
1794
1795
1796
1797 static void CmdUnload (Collection* Args attribute ((unused)))
1798 /* Unload a debug info file */
1799 {
1800     UnloadFile ();
1801 }
1802
1803
1804
1805 /*****************************************************************************/
1806 /*                                   Code                                    */
1807 /*****************************************************************************/
1808
1809
1810
1811 static int Parse (char* CmdLine, Collection* Args)
1812 /* Parse the command line and store the arguments in Args. Return true if ok,
1813 ** false on error.
1814 */
1815 {
1816     char* End;
1817
1818     /* Clear the collection */
1819     CollDeleteAll (Args);
1820
1821     /* Parse the command line */
1822     while (1) {
1823
1824         /* Break out on end of line */
1825         if (*CmdLine == '\0') {
1826             break;
1827         }
1828
1829         /* Search for start of next command */
1830         if (IsSpace (*CmdLine)) {
1831             ++CmdLine;
1832             continue;
1833         }
1834
1835         /* Allow double quotes to terminate a command */
1836         if (*CmdLine == '\"' || *CmdLine == '\'') {
1837             char Term = *CmdLine++;
1838             End = CmdLine;
1839             while (*End != Term) {
1840                 if (*End == '\0') {
1841                     PrintLine ("Unterminated argument");
1842                     return 0;
1843                 }
1844                 ++End;
1845             }
1846             *End++ = '\0';
1847         } else {
1848             End = CmdLine;
1849             while (!IsSpace (*End)) {
1850                 if (*End == '\0') {
1851                     PrintLine ("Unterminated argument");
1852                     return 0;
1853                 }
1854                 ++End;
1855             }
1856             *End++ = '\0';
1857         }
1858         CollAppend (Args, CmdLine);
1859         CmdLine = End;
1860     }
1861
1862     /* Ok */
1863     return 1;
1864 }
1865
1866
1867
1868 int main (int argc, char* argv[])
1869 /* Main program */
1870 {
1871     char Input[256];
1872     Collection Args = STATIC_COLLECTION_INITIALIZER;
1873
1874     /* Initialize the command line */
1875     InitCmdLine (&argc, &argv, "dbgsh");
1876
1877     /* If we have commands on the command line, execute them */
1878     if (ArgCount > 1) {
1879         unsigned I;
1880         for (I = 1; I < ArgCount; ++I) {
1881             CollAppend (&Args, ArgVec[I]);
1882         }
1883
1884         /* Search for the command, check number of args, then execute it */
1885         ExecCmd (&Args, MainCmds, sizeof (MainCmds) / sizeof (MainCmds[0]));
1886     }
1887
1888     /* Loop until program end */
1889     while (!Terminate) {
1890
1891         /* Output a prompt, then read the input */
1892         Print ("dbgsh> ");
1893         fflush (stdout);
1894         if (fgets (Input, sizeof (Input), stdin) == 0) {
1895             PrintLine ("(EOF)");
1896             break;
1897         }
1898
1899         /* Parse the command line */
1900         if (Parse (Input, &Args) == 0 || CollCount (&Args) == 0) {
1901             continue;
1902         }
1903
1904         /* Search for the command, check number of args, then execute it */
1905         ExecCmd (&Args, MainCmds, sizeof (MainCmds) / sizeof (MainCmds[0]));
1906     }
1907
1908     /* Free arguments */
1909     DoneCollection (&Args);
1910     return 0;
1911 }
1912
1913
1914