]> Shamusworld >> Repos - rmac/blob - rmac.c
02bdcfd6e90c9ef6b52b73dd45073e611759ec44
[rmac] / rmac.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // RMAC.C - Main Application Code
4 // Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
7 //
8
9 #include "rmac.h"
10 #include "error.h"
11 #include "listing.h"
12 #include "procln.h"
13 #include "token.h"
14 #include "expr.h"
15 #include "sect.h"
16 #include "mark.h"
17 #include "macro.h"
18 #include "riscasm.h"
19 #include "direct.h"
20 #include "version.h"
21 #include "debug.h"
22 #include "symbol.h"
23 #include "object.h"
24
25 int perm_verb_flag;                                     // Permanently verbose, interactive mode
26 int list_flag;                                          // "-l" Listing flag on command line
27 int verb_flag;                                          // Be verbose about what's going on
28 int as68_flag;                                          // as68 kludge mode
29 int glob_flag;                                          // Assume undefined symbols are global
30 int lsym_flag;                                          // Include local symbols in object file
31 int sbra_flag;                                          // Warn about possible short branches
32 int obj_format;                                         // Object format flag
33 int debug;                                                      // [1..9] Enable debugging levels
34 int err_flag;                                           // '-e' specified
35 int err_fd;                                                     // File to write error messages to 
36 int rgpu, rdsp;                                         // Assembling Jaguar GPU or DSP code
37 int list_fd;                                            // File to write listing to
38 int regbank;                                            // RISC register bank
39 int segpadsize;                                         // Segment padding size
40 int endian;                                                     // Host processor endianess
41 char * objfname;                                        // Object filename pointer
42 char * firstfname;                                      // First source filename
43 char * cmdlnexec;                                       // Executable name, pointer to ARGV[0]
44 char * searchpath;                                      // Search path for include files 
45 char defname[] = "noname.o";            // Default output filename
46
47 // Under Windows and UNIX malloc() is an expensive call, so for small amounts
48 // of memory we allocate from a previously allocated buffer.
49
50 #define A_AMOUNT        4096                                // Amount to malloc() at a time
51 #define A_THRESH        64                                  // Use malloc() for amounts >= A_THRESH
52
53 static LONG a_amount;                                       // Amount left at a_ptr 
54 static char * a_ptr;                                        // Next free chunk
55 LONG amemtot;                                               // amem() total of requests
56
57 // Qsort; The THRESHold below is the insertion sort threshold, and has been adjusted
58 // for records of size 48 bytes.The MTHREShold is where we stop finding a better median.
59  
60 #define THRESH          4                                   // Threshold for insertion
61 #define MTHRESH         6                                   // Threshold for median
62
63 static int (*qcmp)();                                       // The comparison routine
64 static int qsz;                                             // Size of each record
65 static int thresh;                                          // THRESHold in chars 
66 static int mthresh;                                         // MTHRESHold in chars
67
68
69 //
70 // qst: Do a quicksort. First, find the median element, and put that one in the
71 // first place as the discriminator. (This "median" is just the median of the
72 // first, last and middle elements). (Using this median instead of the first
73 // element is a big win). Then, the usual partitioning/swapping, followed by
74 // moving the discriminator into the right place. Then, figure out the sizes of
75 // the two partions, do the smaller one recursively and the larger one via a
76 // repeat of this code.  Stopping when there are less than THRESH elements in a
77 // partition and cleaning up with an insertion sort (in our caller) is a huge
78 // win. All data swaps are done in-line, which is space-losing but time-saving.
79 // (And there are only three places where this is done).
80 //
81 static int qst(char * base, char * max)
82 {
83    char c, * i, * j, * jj;
84    int ii;
85    char * mid, * tmp;
86    long lo, hi;
87
88    /*
89          * At the top here, lo is the number of characters of elements in the
90          * current partition. (Which should be max - base).
91          * Find the median of the first, last, and middle element and make
92          * that the middle element. Set j to largest of first and middle.
93          * If max is larger than that guy, then it's that guy, else compare
94          * max with loser of first and take larger. Things are set up to
95          * prefer the middle, then the first in case of ties.
96          */
97         lo = max - base;                /* number of elements as chars */
98
99         do
100         {
101                 mid = i = base + qsz * ((lo / qsz) >> 1);
102
103                 if (lo >= mthresh)
104                 {
105                         j = (qcmp((jj = base), i) > 0 ? jj : i);
106
107                         if (qcmp(j, (tmp = max - qsz)) > 0)
108                         {
109                                 /* switch to first loser */
110                                 j = (j == jj ? i : jj);
111
112                                 if (qcmp(j, tmp) < 0)
113                                         j = tmp;
114                         }
115
116                         if (j != i)
117                         {
118                                 ii = qsz;
119
120                                 do
121                                 {
122                                         c = *i;
123                                         *i++ = *j;
124                                         *j++ = c;
125                                 }
126                                 while (--ii);
127                         }
128                 }
129
130                 /*
131                  * Semi-standard quicksort partitioning/swapping
132                  */
133                 for(i=base, j=max-qsz; ;)
134                 {
135                         while (i < mid && qcmp(i, mid) <= 0)
136                                 i += qsz;
137
138                         while (j > mid)
139                         {
140                                 if (qcmp(mid, j) <= 0)
141                                 {
142                                         j -= qsz;
143                                         continue;
144                                 }
145
146                                 tmp = i + qsz;  /* value of i after swap */
147
148                                 if (i == mid)
149                                 {
150                                         /* j <-> mid, new mid is j */
151                                         mid = jj = j;
152                                 }
153                                 else
154                                 {
155                                         /* i <-> j */
156                                         jj = j;
157                                         j -= qsz;
158                                 }
159
160                                 goto swap;
161                         }
162
163                         if (i == mid)
164                         {
165                                 break;
166                         }
167                         else
168                         {
169                                 /* i <-> mid, new mid is i */
170                                 jj = mid;
171                                 tmp = mid = i;  /* value of i after swap */
172                                 j -= qsz;
173                         }
174 swap:
175                         ii = qsz;
176
177                         do
178                         {
179                                 c = *i;
180                                 *i++ = *jj;
181                                 *jj++ = c;
182                         }
183                         while (--ii);
184
185                         i = tmp;
186                 }
187
188                 /*
189                  * Look at sizes of the two partitions, do the smaller
190                  * one first by recursion, then do the larger one by
191                  * making sure lo is its size, base and max are update
192                  * correctly, and branching back.  But only repeat
193                  * (recursively or by branching) if the partition is
194                  * of at least size THRESH.
195                  */
196                 i = (j = mid) + qsz;
197
198                 if ((lo = j - base) <= (hi = max - i))
199                 {
200                         if (lo >= thresh)
201                                 qst(base, j);
202
203                         base = i;
204                         lo = hi;
205                 }
206                 else
207                 {
208                         if (hi >= thresh)
209                                 qst(i, max);
210
211                         max = j;
212                 }
213         }
214         while (lo >= thresh);
215
216         return 0;
217 }
218
219
220 /*
221  * qsort:
222  * First, set up some global parameters for qst to share.  Then, quicksort
223  * with qst(), and then a cleanup insertion sort ourselves.  Sound simple?
224  * It's not...
225  */
226 int rmac_qsort(char * base, int n, int size, int (*compar)())
227 {
228         register char c, * i, * j, * lo, * hi;
229         char * min, * max;
230
231         if (n <= 1)
232                 return 0;
233
234         qsz = size;
235         qcmp = compar;
236         thresh = qsz * THRESH;
237         mthresh = qsz * MTHRESH;
238         max = base + n * qsz;
239
240         if (n >= THRESH)
241         {
242                 qst(base, max);
243                 hi = base + thresh;
244         }
245         else
246         {
247                 hi = max;
248         }
249
250         /*
251          * First put smallest element, which must be in the first THRESH, in
252          * the first position as a sentinel.  This is done just by searching
253          * the first THRESH elements (or the first n if n < THRESH), finding
254          * the min, and swapping it into the first position.
255          */
256         for(j=lo=base; (lo+=qsz)<hi;)
257         {
258                 if (qcmp(j, lo) > 0)
259                         j = lo;
260         }
261
262         if (j != base)
263         {
264                 /* swap j into place */
265                 for(i=base, hi=base+qsz; i<hi;)
266                 {
267                         c = *j;
268                         *j++ = *i;
269                         *i++ = c;
270                 }
271         }
272
273         /*
274          * With our sentinel in place, we now run the following hyper-fast
275          * insertion sort.  For each remaining element, min, from [1] to [n-1],
276          * set hi to the index of the element AFTER which this one goes.
277          * Then, do the standard insertion sort shift on a character at a time
278          * basis for each element in the frob.
279          */
280         for(min=base; (hi=min+=qsz)<max;)
281         {
282                 while (qcmp(hi -= qsz, min) > 0)
283                         /* void */;
284
285                 if ((hi += qsz) != min)
286                 {
287                         for(lo=min+qsz; --lo>=min;)
288                         {
289                                 c = *lo;
290
291                                 for(i=j=lo; (j-=qsz)>=hi; i=j)
292                                         *i = *j;
293
294                                 *i = c;
295                         }
296                 }
297         }
298
299         return 0;
300 }
301
302
303 #if 0
304 //
305 // Allocate memory; Panic and Quit if we Run Out
306 //
307 char * amem(LONG amount)
308 {
309         char * p;
310
311 //      if (amount & 1)                                                         // Keep word alignment
312 //              amount++;
313         amount = (amount + 1) & ~(0x01);                        // Keep word alignment
314
315         // Honor *small* request (< 64 bytes)
316         if (amount < A_THRESH)
317         {
318                 if (a_amount < amount)
319                 {
320                         a_ptr = amem(A_AMOUNT);                         // Allocate 4K bytes
321                         a_amount = A_AMOUNT;
322                 }
323
324                 p = a_ptr;
325                 a_ptr += amount;
326                 a_amount -= amount;
327         }
328         else
329         {
330                 amemtot += amount;                                              // Bump total alloc
331                 p = (char *)malloc(amount);                             // Get memory from malloc
332
333                 if (p == NULL)
334                         fatal("Memory exhausted!");
335
336                 memset(p, 0, amount);
337         }
338
339         return p;
340 }
341 #endif
342
343
344 //
345 // Copy stuff around, return pointer to dest+count+1 (doesn't handle overlap)
346 //
347 char * copy(char * dest, char * src, LONG count)
348 {
349         while (count--)
350                 *dest++ = *src++;
351
352         return dest;
353 }
354
355
356 //
357 // Clear a region of memory
358 //
359 void clear(char * dest, LONG count)
360 {
361         while(count--)
362                 *dest++ = 0;
363 }
364
365
366 //
367 // Check to see if the string is a keyword. Returns -1, or a value from the
368 // 'accept[]' table
369 //
370 int kmatch(char * p, int * base, int * check, int * tab, int * accept)
371 {
372         int state;
373         int j;
374
375         for(state=0; state>=0;)
376         {
377                 j = base[state] + (int)tolowertab[*p];
378
379                 if (check[j] != state)
380                 {                               // Reject, character doesn't match
381                         state = -1;                                        // No match 
382                         break;
383                 }
384
385                 if (!*++p)
386                 {                                           // Must accept or reject at EOS
387                         state = accept[j];                                 // (-1 on no terminal match) 
388                         break;
389                 }
390
391                 state = tab[j];
392         }
393
394         return state;
395 }
396
397
398 //
399 // Auto-even a section
400 //
401 void autoeven(int sect)
402 {
403         switchsect(sect);
404         d_even();
405         savsect();
406 }
407
408
409 //
410 // Manipulate file extension.
411 // `name' must be large enough to hold any possible filename.
412 // If `stripp' is nonzero, any old extension is removed.
413 // Then, if the file does not already have an extension,
414 // `extension' is appended to the filename.
415 //
416 char * fext(char * name, char * extension, int stripp)
417 {
418         char * s, * beg;                                           // String pointers
419
420         // Find beginning of "real" name
421         beg = name + strlen(name) - 1;
422
423         for(; beg>name; --beg)
424         {
425                 if (*beg == SLASHCHAR)
426                 {
427                         ++beg;
428                         break;
429                 }
430         }
431
432         if (stripp)
433         {                                             // Clobber any old extension
434                 for(s=beg; *s && *s!='.'; ++s) 
435                         ;
436
437                 *s = '\0';
438         }
439
440         for(s=beg; *s!='.'; ++s)
441         {
442                 if (!*s)
443                 {                                             // Append the new extension
444                         strcat(beg, extension);
445                         break;
446                 }
447         }
448
449         return name;
450 }
451
452
453 //
454 // Return `item'nth element of semicolon-seperated pathnames specified in the
455 // enviroment string `s'. Copy the pathname to `buf'.  Return 0 if the `item'
456 // nth path doesn't exist.
457 // 
458 // [`item' ranges from 0 to N-1, where N = #elements in search path]
459 //
460 int nthpath(char * env_var, int itemno, char * buf)
461 {
462         char * s = searchpath;
463
464         if (s == NULL)
465                 s = getenv(env_var);
466
467         if (s == NULL)
468                 return 0;
469
470         while (itemno--)
471                 while (*s != EOS && *s++ != ';')
472                         ;
473
474         if (*s == EOS)
475                 return 0;
476
477         while (*s != EOS && *s != ';')
478                 *buf++ = *s++;
479
480         *buf++ = EOS;
481
482         return 1;
483 }
484
485
486 //
487 // Display Command Line Help
488 //
489 void display_help(void)
490 {
491         printf("Usage:\n");
492         printf("    %s [options] srcfile\n", cmdlnexec);
493         printf("\n");
494         printf("Options:\n");
495         printf("   -? or -h              display usage information\n");
496         printf("   -dsymbol[=value]      define symbol\n");
497         printf("   -e[errorfile]         send error messages to file, not stdout\n");
498         printf("   -f[format]            output object file format\n");
499         printf("                         b: BSD (use this for Jaguar)\n");
500         printf("   -i[path]              directory to search for include files\n");
501         printf("   -l[filename]          create an output listing file\n");
502         printf("   -o file               output file name\n");
503         printf("   -r[size]              pad segments to boundary size specified\n");
504         printf("                         w: word (2 bytes, default alignment)\n");
505         printf("                         l: long (4 bytes)\n");
506         printf("                         p: phrase (8 bytes)\n");
507         printf("                         d: double phrase (16 bytes)\n");
508         printf("                         q: quad phrase (32 bytes)\n");
509         printf("   -s                    warn about possible short branches\n");
510         printf("   -u                    force referenced and undefined symbols global\n");
511         printf("   -v                    set verbose mode\n");
512         printf("   -y[pagelen]           set page line length (default: 61)\n");
513         printf("\n");
514 }
515
516
517 //
518 // Display Version Information
519 //
520 void display_version(void)
521 {
522         printf("\nReboot's Macro Assembler for Atari Jaguar\n"); 
523         printf("Copyright (C) 199x Landon Dyer, 2011 Reboot\n"); 
524         printf("V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
525 }
526
527
528 // 
529 // Process Command Line Arguments and do an Assembly
530 //
531 int process(int argc, char ** argv)
532 {
533         int argno;                                              // Argument number
534         SYM * sy;                                               // Pointer to a symbol record
535         char * s;                                               // String pointer
536         int fd;                                                 // File descriptor
537         char fnbuf[FNSIZ];                              // Filename buffer 
538         int i;                                                  // Iterator
539
540         errcnt = 0;                                             // Initialise error count
541         listing = 0;                                    // Initialise listing level
542         list_flag = 0;                                  // Initialise listing flag
543         verb_flag = perm_verb_flag;             // Initialise verbose flag
544         as68_flag = 0;                                  // Initialise as68 kludge mode
545         glob_flag = 0;                                  // Initialise .globl flag
546         sbra_flag = 0;                                  // Initialise short branch flag
547         debug = 0;                                              // Initialise debug flag
548         searchpath = NULL;                              // Initialise search path
549         objfname = NULL;                                // Initialise object filename
550         list_fname = NULL;                              // Initialise listing filename
551         err_fname = NULL;                               // Initialise error filename
552         obj_format = BSD;                               // Initialise object format
553         firstfname = NULL;                              // Initialise first filename
554         err_fd = ERROUT;                                // Initialise error file descriptor
555         err_flag = 0;                                   // Initialise error flag
556         rgpu = 0;                                               // Initialise GPU assembly flag
557         rdsp = 0;                                               // Initialise DSP assembly flag
558         lsym_flag = 1;                                  // Include local symbols in object file
559         regbank = BANK_N;                               // No RISC register bank specified
560         orgactive = 0;                                  // Not in RISC org section
561         orgwarning = 0;                                 // No ORG warning issued
562         a_amount = 0;
563         segpadsize = 2;                                 // Initialise segment padding size
564
565         // Initialise modules
566         InitSymbolTable();                              // Symbol table
567         init_token();                                   // Tokenizer
568         init_procln();                                  // Line processor
569         init_expr();                                    // Expression analyzer
570         init_sect();                                    // Section manager / code generator
571         init_mark();                                    // Mark tape-recorder
572         InitMacro();                                    // Macro processor
573         init_list();                                    // Listing generator
574
575         // Process command line arguments and assemble source files
576         for(argno=0; argno<argc; ++argno)
577         {
578                 if (*argv[argno] == '-')
579                 {
580                         switch (argv[argno][1])
581                         {
582                         case 'd':                                       // Define symbol
583                         case 'D':
584                                 for(s=argv[argno]+2; *s!=EOS;)
585                                 {
586                                         if (*s++ == '=')
587                                         {
588                                                 s[-1] = EOS;
589                                                 break;
590                                         }
591                                 }
592
593                                 if (argv[argno][2] == EOS)
594                                 {
595                                         printf("-d: empty symbol\n");
596                                         ++errcnt;
597                                         return errcnt;
598                                 }
599
600                                 sy = lookup(argv[argno] + 2, 0, 0);
601
602                                 if (sy == NULL)
603                                 {
604                                         sy = NewSymbol(argv[argno] + 2, LABEL, 0);
605                                         sy->svalue = 0;
606                                 }
607
608                                 sy->sattr = DEFINED | EQUATED | ABS;
609
610                                 if (*s)
611                                         sy->svalue = (VALUE)atoi(s);
612                                 else
613                                         sy->svalue = 0;
614
615                                 break;
616                         case 'e':                                       // Redirect error message output
617                         case 'E':
618                                 err_fname = argv[argno] + 2;
619                                 break;
620                         case 'f':                                       // -f<format>
621                         case 'F':
622                                 switch (argv[argno][2])
623                                 {
624                                 case EOS:
625                                 case 'b':                                 // -fb = BSD (Jaguar Recommended)
626                                 case 'B':
627                                         obj_format = BSD;
628                                         break;
629                                 default:
630                                         printf("-f: unknown object format specified\n");
631                                         errcnt++;
632                                         return errcnt;
633                                 }
634                                 break;
635                         case 'g':                                       // Debugging flag
636                         case 'G':
637                                 printf("Debugging flag (-g) not yet implemented\n");
638                                 break;
639                         case 'i':                                       // Set directory search path
640                         case 'I':
641                                 searchpath = argv[argno] + 2;
642                                 break;
643                         case 'l':                                       // Produce listing file
644                         case 'L':
645                                 list_fname = argv[argno] + 2;
646                                 listing = 1;
647                                 list_flag = 1;
648                                 lnsave++;
649                                 break;
650                         case 'o':                                       // Direct object file output
651                         case 'O':
652                                 if (argv[argno][2] != EOS)
653                                         objfname = argv[argno] + 2;
654                                 else
655                                 {
656                                         if (++argno >= argc)
657                                         {
658                                                 printf("Missing argument to -o");
659                                                 errcnt++;
660                                                 return errcnt;
661                                         }
662                                         objfname = argv[argno];
663                                 }
664
665                                 break;
666                         case 'r':                                       // Pad seg to requested boundary size
667                         case 'R':
668                                 switch(argv[argno][2])
669                                 {
670                                 case 'w': case 'W': segpadsize = 2;  break;  
671                                 case 'l': case 'L': segpadsize = 4;  break;
672                                 case 'p': case 'P': segpadsize = 8;  break;
673                                 case 'd': case 'D': segpadsize = 16; break;
674                                 case 'q': case 'Q': segpadsize = 32; break;
675                                 default: segpadsize = 2; break;           // Effective autoeven();
676                                 }
677                                 break;
678                         case 's':                                       // Warn about possible short branches
679                         case 'S':
680                                 sbra_flag = 1;
681                                 break;
682                         case 'u':                                       // Make undefined symbols .globl
683                         case 'U':
684                                 glob_flag = 1;
685                                 break;
686                         case 'v':                                       // Verbose flag
687                         case 'V':
688                                 verb_flag++;
689
690                                 if (verb_flag > 1)
691                                         display_version();
692
693                                 break;
694                         case 'x':                                       // Turn on debugging
695                         case 'X':
696                                 debug = 1;
697                                 printf("~ Debugging ON\n");
698                                 break;
699                         case 'y':                                       // -y<pagelen>
700                         case 'Y':
701                                 pagelen = atoi(argv[argno] + 2);
702
703                                 if (pagelen < 10)
704                                 {
705                                         printf("-y: bad page length\n");
706                                         ++errcnt;
707                                         return errcnt;
708                                 }
709
710                                 break;
711                         case EOS:                                       // Input is stdin
712                                 if (firstfname == NULL)                       // Kludge first filename
713                                         firstfname = defname;
714
715                                 include(0, "(stdin)");
716                                 Assemble();
717                                 break;
718                         case 'h':                                       // Display command line usage
719                         case 'H':
720                         case '?':
721                                 display_version();
722                                 display_help();
723                                 errcnt++;
724                                 break;
725                         default:
726                                 display_version();
727                                 printf("Unknown switch: %s\n\n", argv[argno]);
728                                 display_help();
729                                 errcnt++;
730                                 break;
731                         }
732                 }
733                 else
734                 {
735                         // Record first filename.
736                         if (firstfname == NULL)
737                                 firstfname = argv[argno];
738
739                         strcpy(fnbuf, argv[argno]);
740                         fext(fnbuf, ".s", 0);
741                         fd = open(fnbuf, 0);
742
743                         if (fd < 0)
744                         {
745                                 printf("Cannot open: %s\n", fnbuf);
746                                 errcnt++;
747                                 continue;
748                         }
749
750                         include(fd, fnbuf);
751                         Assemble();
752                 }
753         }
754
755         // Wind-up processing;
756         // o  save current section (no more code generation)
757         // o  do auto-even of all sections (or boundary alignment as requested through '-r')
758         // o  determine name of object file:
759         //    -  "foo.o" for linkable output;
760         //    -  "foo.prg" for GEMDOS executable (-p flag).
761         savsect();
762
763         for(i=TEXT; i<=BSS; i<<=1)
764         {
765                 switchsect(i);
766
767                 switch(segpadsize)
768                 {
769                 case 2:  d_even();    break;
770                 case 4:  d_long();    break;
771                 case 8:  d_phrase();  break;
772                 case 16: d_dphrase(); break;
773                 case 32: d_qphrase(); break;
774                 }
775
776                 savsect();
777         }
778
779         if (objfname == NULL)
780         {
781                 if (firstfname == NULL)
782                         firstfname = defname;
783
784                 strcpy(fnbuf, firstfname);
785                 //fext(fnbuf, prg_flag ? ".prg" : ".o", 1);
786                 fext(fnbuf, ".o", 1);
787                 objfname = fnbuf;
788         }
789
790         // With one pass finished, go back and:
791         // (1)   run through all the fixups and resolve forward references;
792         // (1.5) ensure that remaining fixups can be handled by the linker
793         //       (`lo68' format, extended (postfix) format....)
794         // (2)   generate the output file image and symbol table;
795         // (3)   generate relocation information from left-over fixups.
796         ResolveAllFixups();                                             // Do all fixups
797         stopmark();                                                             // Stop mark tape-recorder
798
799         if (errcnt == 0)
800         {
801                 if ((fd = open(objfname, _OPEN_FLAGS, _PERM_MODE)) < 0)
802                         cantcreat(objfname);
803
804                 if (verb_flag)
805                 {
806                         s = "object";
807                         printf("[Writing %s file: %s]\n", s, objfname);
808                 }
809
810                 object((WORD)fd);
811                 close(fd);
812
813                 if (errcnt != 0)
814                         unlink(objfname);
815         }
816
817         if (list_flag)
818         {
819                 if (verb_flag)
820                         printf("[Wrapping-up listing file]\n");
821
822                 listing = 1;
823                 symtable();
824                 close(list_fd);
825         }
826
827         if (err_flag)
828                 close(err_fd);
829
830         DEBUG dump_everything();
831
832         return errcnt;
833 }
834
835
836 //
837 // Determine Processor Endianess
838 //
839 int get_endianess(void)
840 {
841         int i = 1;
842         char * p = (char *)&i;
843
844         if (p[0] == 1)
845                 return 0;
846
847         return 1;
848 }
849
850
851 //
852 // Application Entry Point; Handle the Command Line
853 //
854 int main(int argc, char ** argv)
855 {
856         perm_verb_flag = 0;                             // Clobber "permanent" verbose flag
857         cmdlnexec = argv[0];                    // Obtain executable name
858
859         endian = get_endianess();               // Get processor endianess
860
861         // If commands were passed in, process them
862         if (argc > 1)
863         {
864                 return process(argc - 1, argv + 1);              
865         }
866
867         display_version();
868         display_help();
869
870         return 0;
871 }