]> Shamusworld >> Repos - rmac/blob - rmac.c
Fixed .cargs problem, more code cleanup/fixup
[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 "risca.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 //
304 // Allocate memory; Panic and Quit if we Run Out
305 //
306 char * amem(LONG amount)
307 {
308         char * p;
309
310 //      if (amount & 1)                                                         // Keep word alignment
311 //              amount++;
312         amount = (amount + 1) & ~(0x01);                        // Keep word alignment
313
314         // Honor *small* request (< 64 bytes)
315         if (amount < A_THRESH)
316         {
317                 if (a_amount < amount)
318                 {
319                         a_ptr = amem(A_AMOUNT);                         // Allocate 4K bytes
320                         a_amount = A_AMOUNT;
321                 }
322
323                 p = a_ptr;
324                 a_ptr += amount;
325                 a_amount -= amount;
326         }
327         else
328         {
329                 amemtot += amount;                                              // Bump total alloc
330                 p = (char *)malloc(amount);                             // Get memory from malloc
331
332                 if (p == NULL)
333                         fatal("Memory exhausted!");
334
335                 memset(p, 0, amount);
336         }
337
338         return p;
339 }
340
341
342 //
343 // Copy stuff around, return pointer to dest+count+1 (doesn't handle overlap)
344 //
345 char * copy(char * dest, char * src, LONG count)
346 {
347         while (count--)
348                 *dest++ = *src++;
349
350         return dest;
351 }
352
353
354 //
355 // Clear a region of memory
356 //
357 void clear(char * dest, LONG count)
358 {
359         while(count--)
360                 *dest++ = 0;
361 }
362
363
364 //
365 // Check to see if the string is a keyword. Returns -1, or a value from the
366 // 'accept[]' table
367 //
368 int kmatch(char * p, int * base, int * check, int * tab, int * accept)
369 {
370         int state;
371         int j;
372
373         for(state=0; state>=0;)
374         {
375                 j = base[state] + (int)tolowertab[*p];
376
377                 if (check[j] != state)
378                 {                               // Reject, character doesn't match
379                         state = -1;                                        // No match 
380                         break;
381                 }
382
383                 if (!*++p)
384                 {                                           // Must accept or reject at EOS
385                         state = accept[j];                                 // (-1 on no terminal match) 
386                         break;
387                 }
388
389                 state = tab[j];
390         }
391
392         return state;
393 }
394
395
396 //
397 // Auto-even a section
398 //
399 void autoeven(int sect)
400 {
401         switchsect(sect);
402         d_even();
403         savsect();
404 }
405
406
407 //
408 // Manipulate file extension.
409 // `name' must be large enough to hold any possible filename.
410 // If `stripp' is nonzero, any old extension is removed.
411 // Then, if the file does not already have an extension,
412 // `extension' is appended to the filename.
413 //
414 char * fext(char * name, char * extension, int stripp)
415 {
416         char * s, * beg;                                           // String pointers
417
418         // Find beginning of "real" name
419         beg = name + strlen(name) - 1;
420
421         for(; beg>name; --beg)
422         {
423                 if (*beg == SLASHCHAR)
424                 {
425                         ++beg;
426                         break;
427                 }
428         }
429
430         if (stripp)
431         {                                             // Clobber any old extension
432                 for(s=beg; *s && *s!='.'; ++s) 
433                         ;
434
435                 *s = '\0';
436         }
437
438         for(s=beg; *s!='.'; ++s)
439         {
440                 if (!*s)
441                 {                                             // Append the new extension
442                         strcat(beg, extension);
443                         break;
444                 }
445         }
446
447         return name;
448 }
449
450
451 //
452 // Return `item'nth element of semicolon-seperated pathnames specified in the
453 // enviroment string `s'. Copy the pathname to `buf'.  Return 0 if the `item'
454 // nth path doesn't exist.
455 // 
456 // [`item' ranges from 0 to N-1, where N = #elements in search path]
457 //
458 int nthpath(char * env_var, int itemno, char * buf)
459 {
460         char * s = searchpath;
461
462         if (s == NULL)
463                 s = getenv(env_var);
464
465         if (s == NULL)
466                 return 0;
467
468         while (itemno--)
469                 while (*s != EOS && *s++ != ';')
470                         ;
471
472         if (*s == EOS)
473                 return 0;
474
475         while (*s != EOS && *s != ';')
476                 *buf++ = *s++;
477
478         *buf++ = EOS;
479
480         return 1;
481 }
482
483
484 //
485 // Display Command Line Help
486 //
487 void display_help(void)
488 {
489         printf("Usage:\n");
490         printf("    %s [options] srcfile\n", cmdlnexec);
491         printf("\n");
492         printf("Options:\n");
493         printf("   -? or -h              display usage information\n");
494         printf("   -dsymbol[=value]      define symbol\n");
495         printf("   -e[errorfile]         send error messages to file, not stdout\n");
496         printf("   -f[format]            output object file format\n");
497         printf("                         b: BSD (use this for Jaguar)\n");
498         printf("   -i[path]              directory to search for include files\n");
499         printf("   -l[filename]          create an output listing file\n");
500         printf("   -o file               output file name\n");
501         printf("   -r[size]              pad segments to boundary size specified\n");
502         printf("                         w: word (2 bytes, default alignment)\n");
503         printf("                         l: long (4 bytes)\n");
504         printf("                         p: phrase (8 bytes)\n");
505         printf("                         d: double phrase (16 bytes)\n");
506         printf("                         q: quad phrase (32 bytes)\n");
507         printf("   -s                    warn about possible short branches\n");
508         printf("   -u                    force referenced and undefined symbols global\n");
509         printf("   -v                    set verbose mode\n");
510         printf("   -y[pagelen]           set page line length (default: 61)\n");
511         printf("\n");
512 }
513
514
515 //
516 // Display Version Information
517 //
518 void display_version(void)
519 {
520         printf("\nReboot's Macro Assembler for Atari Jaguar\n"); 
521         printf("Copyright (C) 199x Landon Dyer, 2011 Reboot\n"); 
522         printf("V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
523 }
524
525
526 // 
527 // Process Command Line Arguments and do an Assembly
528 //
529 int process(int argc, char ** argv)
530 {
531         int argno;                                              // Argument number
532         SYM * sy;                                               // Pointer to a symbol record
533         char * s;                                               // String pointer
534         int fd;                                                 // File descriptor
535         char fnbuf[FNSIZ];                              // Filename buffer 
536         int i;                                                  // Iterator
537
538         errcnt = 0;                                             // Initialise error count
539         listing = 0;                                    // Initialise listing level
540         list_flag = 0;                                  // Initialise listing flag
541         verb_flag = perm_verb_flag;             // Initialise verbose flag
542         as68_flag = 0;                                  // Initialise as68 kludge mode
543         glob_flag = 0;                                  // Initialise .globl flag
544         sbra_flag = 0;                                  // Initialise short branch flag
545         debug = 0;                                              // Initialise debug flag
546         searchpath = NULL;                              // Initialise search path
547         objfname = NULL;                                // Initialise object filename
548         list_fname = NULL;                              // Initialise listing filename
549         err_fname = NULL;                               // Initialise error filename
550         obj_format = BSD;                               // Initialise object format
551         firstfname = NULL;                              // Initialise first filename
552         err_fd = ERROUT;                                // Initialise error file descriptor
553         err_flag = 0;                                   // Initialise error flag
554         rgpu = 0;                                               // Initialise GPU assembly flag
555         rdsp = 0;                                               // Initialise DSP assembly flag
556         lsym_flag = 1;                                  // Include local symbols in object file
557         regbank = BANK_N;                               // No RISC register bank specified
558         orgactive = 0;                                  // Not in RISC org section
559         orgwarning = 0;                                 // No ORG warning issued
560         a_amount = 0;
561         segpadsize = 2;                                 // Initialise segment padding size
562
563         // Initialise modules
564         InitSymbolTable();                              // Symbol table
565         init_token();                                   // Tokenizer
566         init_procln();                                  // Line processor
567         init_expr();                                    // Expression analyzer
568         init_sect();                                    // Section manager / code generator
569         init_mark();                                    // Mark tape-recorder
570         InitMacro();                                    // Macro processor
571         init_list();                                    // Listing generator
572
573         // Process command line arguments and assemble source files
574         for(argno=0; argno<argc; ++argno)
575         {
576                 if (*argv[argno] == '-')
577                 {
578                         switch (argv[argno][1])
579                         {
580                         case 'd':                                       // Define symbol
581                         case 'D':
582                                 for(s=argv[argno]+2; *s!=EOS;)
583                                 {
584                                         if (*s++ == '=')
585                                         {
586                                                 s[-1] = EOS;
587                                                 break;
588                                         }
589                                 }
590
591                                 if (argv[argno][2] == EOS)
592                                 {
593                                         printf("-d: empty symbol\n");
594                                         ++errcnt;
595                                         return errcnt;
596                                 }
597
598                                 sy = lookup(argv[argno] + 2, 0, 0);
599
600                                 if (sy == NULL)
601                                 {
602                                         sy = NewSymbol(argv[argno] + 2, LABEL, 0);
603                                         sy->svalue = 0;
604                                 }
605
606                                 sy->sattr = DEFINED | EQUATED | ABS;
607
608                                 if (*s)
609                                         sy->svalue = (VALUE)atoi(s);
610                                 else
611                                         sy->svalue = 0;
612
613                                 break;
614                         case 'e':                                       // Redirect error message output
615                         case 'E':
616                                 err_fname = argv[argno] + 2;
617                                 break;
618                         case 'f':                                       // -f<format>
619                         case 'F':
620                                 switch (argv[argno][2])
621                                 {
622                                 case EOS:
623                                 case 'b':                                 // -fb = BSD (Jaguar Recommended)
624                                 case 'B':
625                                         obj_format = BSD;
626                                         break;
627                                 default:
628                                         printf("-f: unknown object format specified\n");
629                                         errcnt++;
630                                         return errcnt;
631                                 }
632                                 break;
633                         case 'g':                                       // Debugging flag
634                         case 'G':
635                                 printf("Debugging flag (-g) not yet implemented\n");
636                                 break;
637                         case 'i':                                       // Set directory search path
638                         case 'I':
639                                 searchpath = argv[argno] + 2;
640                                 break;
641                         case 'l':                                       // Produce listing file
642                         case 'L':
643                                 list_fname = argv[argno] + 2;
644                                 listing = 1;
645                                 list_flag = 1;
646                                 lnsave++;
647                                 break;
648                         case 'o':                                       // Direct object file output
649                         case 'O':
650                                 if (argv[argno][2] != EOS)
651                                         objfname = argv[argno] + 2;
652                                 else
653                                 {
654                                         if (++argno >= argc)
655                                         {
656                                                 printf("Missing argument to -o");
657                                                 errcnt++;
658                                                 return errcnt;
659                                         }
660                                         objfname = argv[argno];
661                                 }
662
663                                 break;
664                         case 'r':                                       // Pad seg to requested boundary size
665                         case 'R':
666                                 switch(argv[argno][2])
667                                 {
668                                 case 'w': case 'W': segpadsize = 2;  break;  
669                                 case 'l': case 'L': segpadsize = 4;  break;
670                                 case 'p': case 'P': segpadsize = 8;  break;
671                                 case 'd': case 'D': segpadsize = 16; break;
672                                 case 'q': case 'Q': segpadsize = 32; break;
673                                 default: segpadsize = 2; break;           // Effective autoeven();
674                                 }
675                                 break;
676                         case 's':                                       // Warn about possible short branches
677                         case 'S':
678                                 sbra_flag = 1;
679                                 break;
680                         case 'u':                                       // Make undefined symbols .globl
681                         case 'U':
682                                 glob_flag = 1;
683                                 break;
684                         case 'v':                                       // Verbose flag
685                         case 'V':
686                                 verb_flag++;
687
688                                 if (verb_flag > 1)
689                                         display_version();
690
691                                 break;
692                         case 'x':                                       // Turn on debugging
693                         case 'X':
694                                 debug = 1;
695                                 printf("~ Debugging ON\n");
696                                 break;
697                         case 'y':                                       // -y<pagelen>
698                         case 'Y':
699                                 pagelen = atoi(argv[argno] + 2);
700
701                                 if (pagelen < 10)
702                                 {
703                                         printf("-y: bad page length\n");
704                                         ++errcnt;
705                                         return errcnt;
706                                 }
707
708                                 break;
709                         case EOS:                                       // Input is stdin
710                                 if (firstfname == NULL)                       // Kludge first filename
711                                         firstfname = defname;
712
713                                 include(0, "(stdin)");
714                                 Assemble();
715                                 break;
716                         case 'h':                                       // Display command line usage
717                         case 'H':
718                         case '?':
719                                 display_version();
720                                 display_help();
721                                 errcnt++;
722                                 break;
723                         default:
724                                 display_version();
725                                 printf("Unknown switch: %s\n\n", argv[argno]);
726                                 display_help();
727                                 errcnt++;
728                                 break;
729                         }
730                 }
731                 else
732                 {
733                         // Record first filename.
734                         if (firstfname == NULL)
735                                 firstfname = argv[argno];
736
737                         strcpy(fnbuf, argv[argno]);
738                         fext(fnbuf, ".s", 0);
739                         fd = open(fnbuf, 0);
740
741                         if (fd < 0)
742                         {
743                                 printf("Cannot open: %s\n", fnbuf);
744                                 errcnt++;
745                                 continue;
746                         }
747
748                         include(fd, fnbuf);
749                         Assemble();
750                 }
751         }
752
753         // Wind-up processing;
754         // o  save current section (no more code generation)
755         // o  do auto-even of all sections (or boundary alignment as requested through '-r')
756         // o  determine name of object file:
757         //    -  "foo.o" for linkable output;
758         //    -  "foo.prg" for GEMDOS executable (-p flag).
759         savsect();
760
761         for(i=TEXT; i<=BSS; i<<=1)
762         {
763                 switchsect(i);
764
765                 switch(segpadsize)
766                 {
767                 case 2:  d_even();    break;
768                 case 4:  d_long();    break;
769                 case 8:  d_phrase();  break;
770                 case 16: d_dphrase(); break;
771                 case 32: d_qphrase(); break;
772                 }
773
774                 savsect();
775         }
776
777         if (objfname == NULL)
778         {
779                 if (firstfname == NULL)
780                         firstfname = defname;
781
782                 strcpy(fnbuf, firstfname);
783                 //fext(fnbuf, prg_flag ? ".prg" : ".o", 1);
784                 fext(fnbuf, ".o", 1);
785                 objfname = fnbuf;
786         }
787
788         // With one pass finished, go back and:
789         // (1)   run through all the fixups and resolve forward references;
790         // (1.5) ensure that remaining fixups can be handled by the linker
791         //       (`lo68' format, extended (postfix) format....)
792         // (2)   generate the output file image and symbol table;
793         // (3)   generate relocation information from left-over fixups.
794         ResolveAllFixups();                                             // Do all fixups
795         stopmark();                                                             // Stop mark tape-recorder
796
797         if (errcnt == 0)
798         {
799                 if ((fd = open(objfname, _OPEN_FLAGS, _PERM_MODE)) < 0)
800                         cantcreat(objfname);
801
802                 if (verb_flag)
803                 {
804                         s = "object";
805                         printf("[Writing %s file: %s]\n", s, objfname);
806                 }
807
808                 object((WORD)fd);
809                 close(fd);
810
811                 if (errcnt != 0)
812                         unlink(objfname);
813         }
814
815         if (list_flag)
816         {
817                 if (verb_flag)
818                         printf("[Wrapping-up listing file]\n");
819
820                 listing = 1;
821                 symtable();
822                 close(list_fd);
823         }
824
825         if (err_flag)
826                 close(err_fd);
827
828         DEBUG dump_everything();
829
830         return errcnt;
831 }
832
833
834 //
835 // Determine Processor Endianess
836 //
837 int get_endianess(void)
838 {
839         int i = 1;
840         char * p = (char *)&i;
841
842         if (p[0] == 1)
843                 return 0;
844
845         return 1;
846 }
847
848
849 //
850 // Application Entry Point; Handle the Command Line
851 //
852 int main(int argc, char ** argv)
853 {
854         int status;
855         int i;
856
857         perm_verb_flag = 0;                             // Clobber "permanent" verbose flag
858         cmdlnexec = argv[0];                    // Obtain executable name
859
860         endian = get_endianess();               // Get processor endianess
861
862         for(i=0; i<MAXFWDJUMPS; i++)
863                 fwdjump[i] = 0;
864
865         // Full command line passed
866         if (argc > 1)
867         {
868                 status = process(argc - 1, argv + 1);              
869         }
870         else
871         {
872                 display_version();
873                 display_help();
874         }
875
876         return status;
877 }