]> Shamusworld >> Repos - rmac/blob - rmac.c
More readability cleanups.
[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 in_main;                                            // In main memory flag for GPUMAIN
41 int endian;                                                     // Host processor endianess
42 char * objfname;                                        // Object filename pointer
43 char * firstfname;                                      // First source filename
44 char * cmdlnexec;                                       // Executable name, pointer to ARGV[0]
45 char * searchpath;                                      // Search path for include files 
46 char defname[] = "noname.o";            // Default output filename
47
48 // Under Windows and UNIX malloc() is an expensive call, so for small amounts
49 // of memory we allocate from a previously allocated buffer.
50
51 #define A_AMOUNT        4096                                // Amount to malloc() at a time
52 #define A_THRESH        64                                  // Use malloc() for amounts >= A_THRESH
53
54 static LONG a_amount;                                       // Amount left at a_ptr 
55 static char * a_ptr;                                        // Next free chunk
56 LONG amemtot;                                               // amem() total of requests
57
58 // Qsort; The THRESHold below is the insertion sort threshold, and has been adjusted
59 // for records of size 48 bytes.The MTHREShold is where we stop finding a better median.
60  
61 #define THRESH          4                                   // Threshold for insertion
62 #define MTHRESH         6                                   // Threshold for median
63
64 static int (*qcmp)();                                       // The comparison routine
65 static int qsz;                                             // Size of each record
66 static int thresh;                                          // THRESHold in chars 
67 static int mthresh;                                         // MTHRESHold in chars
68
69
70 //
71 // qst: Do a quicksort. First, find the median element, and put that one in the
72 // first place as the discriminator. (This "median" is just the median of the
73 // first, last and middle elements). (Using this median instead of the first
74 // element is a big win). Then, the usual partitioning/swapping, followed by
75 // moving the discriminator into the right place. Then, figure out the sizes of
76 // the two partions, do the smaller one recursively and the larger one via a
77 // repeat of this code.  Stopping when there are less than THRESH elements in a
78 // partition and cleaning up with an insertion sort (in our caller) is a huge
79 // win. All data swaps are done in-line, which is space-losing but time-saving.
80 // (And there are only three places where this is done).
81 //
82 static int qst(char * base, char * max)
83 {
84    char c, * i, * j, * jj;
85    int ii;
86    char * mid, * tmp;
87    long lo, hi;
88
89    /*
90          * At the top here, lo is the number of characters of elements in the
91          * current partition. (Which should be max - base).
92          * Find the median of the first, last, and middle element and make
93          * that the middle element. Set j to largest of first and middle.
94          * If max is larger than that guy, then it's that guy, else compare
95          * max with loser of first and take larger. Things are set up to
96          * prefer the middle, then the first in case of ties.
97          */
98         lo = max - base;                /* number of elements as chars */
99
100         do
101         {
102                 mid = i = base + qsz * ((lo / qsz) >> 1);
103
104                 if (lo >= mthresh)
105                 {
106                         j = (qcmp((jj = base), i) > 0 ? jj : i);
107
108                         if (qcmp(j, (tmp = max - qsz)) > 0)
109                         {
110                                 /* switch to first loser */
111                                 j = (j == jj ? i : jj);
112
113                                 if (qcmp(j, tmp) < 0)
114                                         j = tmp;
115                         }
116
117                         if (j != i)
118                         {
119                                 ii = qsz;
120
121                                 do
122                                 {
123                                         c = *i;
124                                         *i++ = *j;
125                                         *j++ = c;
126                                 }
127                                 while (--ii);
128                         }
129                 }
130
131                 /*
132                  * Semi-standard quicksort partitioning/swapping
133                  */
134                 for(i=base, j=max-qsz; ;)
135                 {
136                         while (i < mid && qcmp(i, mid) <= 0)
137                                 i += qsz;
138
139                         while (j > mid)
140                         {
141                                 if (qcmp(mid, j) <= 0)
142                                 {
143                                         j -= qsz;
144                                         continue;
145                                 }
146
147                                 tmp = i + qsz;  /* value of i after swap */
148
149                                 if (i == mid)
150                                 {
151                                         /* j <-> mid, new mid is j */
152                                         mid = jj = j;
153                                 }
154                                 else
155                                 {
156                                         /* i <-> j */
157                                         jj = j;
158                                         j -= qsz;
159                                 }
160
161                                 goto swap;
162                         }
163
164                         if (i == mid)
165                         {
166                                 break;
167                         }
168                         else
169                         {
170                                 /* i <-> mid, new mid is i */
171                                 jj = mid;
172                                 tmp = mid = i;  /* value of i after swap */
173                                 j -= qsz;
174                         }
175 swap:
176                         ii = qsz;
177
178                         do
179                         {
180                                 c = *i;
181                                 *i++ = *jj;
182                                 *jj++ = c;
183                         }
184                         while (--ii);
185
186                         i = tmp;
187                 }
188
189                 /*
190                  * Look at sizes of the two partitions, do the smaller
191                  * one first by recursion, then do the larger one by
192                  * making sure lo is its size, base and max are update
193                  * correctly, and branching back.  But only repeat
194                  * (recursively or by branching) if the partition is
195                  * of at least size THRESH.
196                  */
197                 i = (j = mid) + qsz;
198
199                 if ((lo = j - base) <= (hi = max - i))
200                 {
201                         if (lo >= thresh)
202                                 qst(base, j);
203
204                         base = i;
205                         lo = hi;
206                 }
207                 else
208                 {
209                         if (hi >= thresh)
210                                 qst(i, max);
211
212                         max = j;
213                 }
214         }
215         while (lo >= thresh);
216
217         return 0;
218 }
219
220
221 /*
222  * qsort:
223  * First, set up some global parameters for qst to share.  Then, quicksort
224  * with qst(), and then a cleanup insertion sort ourselves.  Sound simple?
225  * It's not...
226  */
227 int rmac_qsort(char * base, int n, int size, int (*compar)())
228 {
229         register char c, * i, * j, * lo, * hi;
230         char * min, * max;
231
232         if (n <= 1)
233                 return 0;
234
235         qsz = size;
236         qcmp = compar;
237         thresh = qsz * THRESH;
238         mthresh = qsz * MTHRESH;
239         max = base + n * qsz;
240
241         if (n >= THRESH)
242         {
243                 qst(base, max);
244                 hi = base + thresh;
245         }
246         else
247         {
248                 hi = max;
249         }
250
251         /*
252          * First put smallest element, which must be in the first THRESH, in
253          * the first position as a sentinel.  This is done just by searching
254          * the first THRESH elements (or the first n if n < THRESH), finding
255          * the min, and swapping it into the first position.
256          */
257         for(j=lo=base; (lo+=qsz)<hi;)
258         {
259                 if (qcmp(j, lo) > 0)
260                         j = lo;
261         }
262
263         if (j != base)
264         {
265                 /* swap j into place */
266                 for(i=base, hi=base+qsz; i<hi;)
267                 {
268                         c = *j;
269                         *j++ = *i;
270                         *i++ = c;
271                 }
272         }
273
274         /*
275          * With our sentinel in place, we now run the following hyper-fast
276          * insertion sort.  For each remaining element, min, from [1] to [n-1],
277          * set hi to the index of the element AFTER which this one goes.
278          * Then, do the standard insertion sort shift on a character at a time
279          * basis for each element in the frob.
280          */
281         for(min=base; (hi=min+=qsz)<max;)
282         {
283                 while (qcmp(hi -= qsz, min) > 0)
284                         /* void */;
285
286                 if ((hi += qsz) != min)
287                 {
288                         for(lo=min+qsz; --lo>=min;)
289                         {
290                                 c = *lo;
291
292                                 for(i=j=lo; (j-=qsz)>=hi; i=j)
293                                         *i = *j;
294
295                                 *i = c;
296                         }
297                 }
298         }
299
300         return 0;
301 }
302
303
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
314         if (amount < A_THRESH)
315         {                                  // Honor *small* request
316                 if (a_amount < amount)
317                 {
318                         a_ptr = amem(A_AMOUNT);
319                         a_amount = A_AMOUNT;
320                 }
321
322                 p = a_ptr;
323                 a_ptr += amount;
324                 a_amount -= amount;
325         }
326         else
327         {
328                 amemtot += amount;                                    // Bump total alloc
329                 p = (char *)malloc(amount);                           // Get memory from malloc
330
331                 if ((LONG)p == (LONG)NULL)
332                         fatal("memory exhausted");
333
334                 memset(p, 0, amount);
335         }
336
337         return p;
338 }
339
340
341 //
342 // Copy stuff around, return pointer to dest+count+1 (doesn't handle overlap)
343 //
344 char * copy(char * dest, char * src, LONG count)
345 {
346         while (count--)
347                 *dest++ = *src++;
348
349         return dest;
350 }
351
352
353 //
354 // Clear a region of memory
355 //
356 void clear(char * dest, LONG count)
357 {
358         while(count--)
359                 *dest++ = 0;
360 }
361
362
363 //
364 // Check to see if the string is a keyword. Returns -1, or a value from the
365 // 'accept[]' table
366 //
367 int kmatch(char * p, int * base, int * check, int * tab, int * accept)
368 {
369         int state;
370         int j;
371
372         for(state=0; state>=0;)
373         {
374                 j = base[state] + (int)tolowertab[*p];
375
376                 if (check[j] != state)
377                 {                               // Reject, character doesn't match
378                         state = -1;                                        // No match 
379                         break;
380                 }
381
382                 if (!*++p)
383                 {                                           // Must accept or reject at EOS
384                         state = accept[j];                                 // (-1 on no terminal match) 
385                         break;
386                 }
387
388                 state = tab[j];
389         }
390
391         return state;
392 }
393
394
395 //
396 // Auto-even a section
397 //
398 void autoeven(int sect)
399 {
400         switchsect(sect);
401         d_even();
402         savsect();
403 }
404
405
406 //
407 // Manipulate file extension.
408 // `name' must be large enough to hold any possible filename.
409 // If `stripp' is nonzero, any old extension is removed.
410 // Then, if the file does not already have an extension,
411 // `extension' is appended to the filename.
412 //
413 char * fext(char * name, char * extension, int stripp)
414 {
415         char * s, * beg;                                           // String pointers
416
417         // Find beginning of "real" name
418         beg = name + strlen(name) - 1;
419
420         for(; beg>name; --beg)
421         {
422                 if (*beg == SLASHCHAR)
423                 {
424                         ++beg;
425                         break;
426                 }
427         }
428
429         if (stripp)
430         {                                             // Clobber any old extension
431                 for(s=beg; *s && *s!='.'; ++s) 
432                         ;
433
434                 *s = '\0';
435         }
436
437         for(s=beg; *s!='.'; ++s)
438         {
439                 if (!*s)
440                 {                                             // Append the new extension
441                         strcat(beg, extension);
442                         break;
443                 }
444         }
445
446         return name;
447 }
448
449
450 //
451 // Return `item'nth element of semicolon-seperated pathnames specified in the
452 // enviroment string `s'. Copy the pathname to `buf'.  Return 0 if the `item'
453 // nth path doesn't exist.
454 // 
455 // [`item' ranges from 0 to N-1, where N = #elements in search path]
456 //
457 int nthpath(char * env_var, int itemno, char * buf)
458 {
459         char * s = searchpath;
460
461         if (s == NULL)
462                 s = getenv(env_var);
463
464         if (s == NULL)
465                 return 0;
466
467         while (itemno--)
468                 while (*s != EOS && *s++ != ';')
469                         ;
470
471         if (*s == EOS)
472                 return 0;
473
474         while (*s != EOS && *s != ';')
475                 *buf++ = *s++;
476
477         *buf++ = EOS;
478
479         return 1;
480 }
481
482
483 //
484 // Display Command Line Help
485 //
486 void display_help(void)
487 {
488         printf("Usage:\n");
489         printf("    %s [options] srcfile\n", cmdlnexec);
490         printf("\n");
491         printf("Options:\n");
492         printf("   -? or -h              display usage information\n");
493         printf("   -dsymbol[=value]      define symbol\n");
494         printf("   -e[errorfile]         send error messages to file, not stdout\n");
495         printf("   -f[format]            output object file format\n");
496         printf("                         b: BSD (use this for Jaguar)\n");
497         printf("   -i[path]              directory to search for include files\n");
498         printf("   -l[filename]          create an output listing file\n");
499         printf("   -o file               output file name\n");
500         printf("   -r[size]              pad segments to boundary size specified\n");
501         printf("                         w: word (2 bytes, default alignment)\n");
502         printf("                         l: long (4 bytes)\n");
503         printf("                         p: phrase (8 bytes)\n");
504         printf("                         d: double phrase (16 bytes)\n");
505         printf("                         q: quad phrase (32 bytes)\n");
506         printf("   -s                    warn about possible short branches\n");
507         printf("   -u                    force referenced and undefined symbols global\n");
508         printf("   -v                    set verbose mode\n");
509         printf("   -y[pagelen]           set page line length (default: 61)\n");
510         printf("\n");
511 }
512
513
514 //
515 // Display Version Information
516 //
517 void display_version(void)
518 {
519         printf("\nReboot's Macro Assembler for Atari Jaguar\n"); 
520         printf("Copyright (C) 199x Landon Dyer, 2011 Reboot\n"); 
521         printf("V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
522 }
523
524
525 // 
526 // Process Command Line Arguments and do an Assembly
527 //
528 int process(int argc, char ** argv)
529 {
530         int argno;                                              // Argument number
531         SYM * sy;                                               // Pointer to a symbol record
532         char * s;                                               // String pointer
533         int fd;                                                 // File descriptor
534         char fnbuf[FNSIZ];                              // Filename buffer 
535         int i;                                                  // Iterator
536
537         errcnt = 0;                                             // Initialise error count
538         listing = 0;                                    // Initialise listing level
539         list_flag = 0;                                  // Initialise listing flag
540         verb_flag = perm_verb_flag;             // Initialise verbose flag
541         as68_flag = 0;                                  // Initialise as68 kludge mode
542         glob_flag = 0;                                  // Initialise .globl flag
543         sbra_flag = 0;                                  // Initialise short branch flag
544         debug = 0;                                              // Initialise debug flag
545         searchpath = NULL;                              // Initialise search path
546         objfname = NULL;                                // Initialise object filename
547         list_fname = NULL;                              // Initialise listing filename
548         err_fname = NULL;                               // Initialise error filename
549         obj_format = BSD;                               // Initialise object format
550         firstfname = NULL;                              // Initialise first filename
551         err_fd = ERROUT;                                // Initialise error file descriptor
552         err_flag = 0;                                   // Initialise error flag
553         rgpu = 0;                                               // Initialise GPU assembly flag
554         rdsp = 0;                                               // Initialise DSP assembly flag
555         lsym_flag = 1;                                  // Include local symbols in object file
556         regbank = BANK_N;                               // No RISC register bank specified
557         orgactive = 0;                                  // Not in RISC org section
558         orgwarning = 0;                                 // No ORG warning issued
559         a_amount = 0;
560         segpadsize = 2;                                 // Initialise segment padding size
561         in_main = 0;
562
563         // Initialise modules
564         init_sym();                                             // 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         init_macro();                                   // 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 = newsym(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         fixups();                                                // 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 }