import of upstream version 1.17
[mw/micromonitor-lm32.git] / umon_main / host / src / utils / coff.c
1 /* coff.c:
2         Perform some dumps/conversions of a coff file.
3
4         General notice:
5         This code is part of a boot-monitor package developed as a generic base
6         platform for embedded system designs.  As such, it is likely to be
7         distributed to various projects beyond the control of the original
8         author.  Please notify the author of any enhancements made or bugs found
9         so that all may benefit from the changes.  In addition, notification back
10         to the author will allow the new user to pick up changes that may have
11         been made by other users after this version of the code was distributed.
12
13         Author: Ed Sutter
14         email:  esutter@lucent.com
15         phone:  908-582-2351
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <signal.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #ifdef BUILD_WITH_VCC
28 #include <io.h>
29 #else
30 #include <unistd.h>
31 #endif
32 #include "packdata.h"
33 #include "coff.h"
34 #include "../zlib/zlib.h"
35 #include "utils.h"
36 #include "version.h"
37
38 #ifndef O_BINARY
39 #define O_BINARY 0
40 #endif
41
42 int     coffFD = 0, noPad;
43 int             tiMode = 0;
44 char    *coffFname = (char *)0;
45
46 struct  filehdr CoffFhdr;
47 struct  aouthdr OptAhdr;
48 struct  scnhdr  *ScnTbl;
49
50 /* open verbosity: */
51 #define SHOWHDR                 0x0001
52 #define SHOWSECTIONS    0x0002
53 #define SHOWMAP                 0x0004
54 #define SHOWMAPOFFSET   0x0008
55 #define SHOWAPPEND              0x0010
56
57 struct  filehdr *GetCoffFileHdr();
58 int             Ecvt, verbose, debug;
59
60
61 void
62 ShowAppend(void)
63 {
64         int     i;
65         char    c;
66         long    maxsize, maxoff;
67
68         maxoff = 0;
69         for(i=0;i<CoffFhdr.f_nscns;i++) {
70                 if (ScnTbl[i].s_scnptr > maxoff) {
71                         maxoff = ScnTbl[i].s_scnptr;
72                         maxsize = ScnTbl[i].s_size;
73                 }
74         }
75         Lseek(coffFD,maxoff+maxsize,SEEK_SET);
76         while(1) {
77                 if (read(coffFD,&c,1) != 1)
78                         break;
79                 putchar(c);
80         }
81
82 }
83
84 void
85 ShowCoffSections(void)
86 {
87         int     i;
88
89         printf("\n\t\tCOFF FILE SECTION HEADERS\n");
90         for(i=0;i<CoffFhdr.f_nscns;i++) {
91                 printf("Section: %s...\n",ScnTbl[i].s_name);
92                 printf("  s_paddr:   0x%x\n",ScnTbl[i].s_paddr);
93                 printf("  s_vaddr:   0x%x\n",ScnTbl[i].s_vaddr);
94                 printf("  s_size:    %d\n",ScnTbl[i].s_size);
95                 printf("  s_scnptr:  0x%x\n",ScnTbl[i].s_scnptr);
96                 printf("  s_relptr:  0x%x\n",ScnTbl[i].s_relptr);
97                 printf("  s_lnnoptr: 0x%x\n",ScnTbl[i].s_lnnoptr);
98                 printf("  s_nreloc:  %d\n",ScnTbl[i].s_nreloc);
99                 printf("  s_nlnno:   %d\n",ScnTbl[i].s_nlnno);
100                 printf("  s_flags:   0x%x\n\n",ScnTbl[i].s_flags);
101                 if (ScnTbl[i].s_size < 0) {
102                         fprintf(stderr,"Warning: section size < 0\n");
103                         break;
104                 }
105         }
106 }
107
108 void
109 ShowCoffHdr(void)
110 {
111         printf("\n\t\tCOFF FILE HEADER\n");
112
113         printf("Magic:                          0x%x\n",CoffFhdr.f_magic);
114         if (CoffFhdr.f_opthdr) {
115                 printf("Opt magic:                      0x%x (%d)\n",
116                         OptAhdr.magic,OptAhdr.magic);
117                 printf("Text size:                      0x%x (%d)\n",
118                         OptAhdr.tsize,OptAhdr.tsize);
119                 printf("Data size:                      0x%x (%d)\n",
120                         OptAhdr.dsize,OptAhdr.dsize);
121                 printf("Bss size:                       0x%x (%d)\n",
122                         OptAhdr.bsize,OptAhdr.bsize);
123                 printf("Entrypoint:                     0x%x\n",OptAhdr.entry);
124         }
125         printf("Number of sections:             %d\n",CoffFhdr.f_nscns);
126         printf("Number of symbols:              %d\n",CoffFhdr.f_nsyms);
127 }
128
129 void
130 ShowCoffMap(void)
131 {
132         int     i, size;
133
134         printf("\n\t\tCOFF FILE MEMORY MAP\n\n");
135         for(i=0;i<CoffFhdr.f_nscns;i++) {
136                 char name[9];
137                 memcpy(name,ScnTbl[i].s_name,8);
138                 name[8] = 0;
139                 
140                 size = ScnTbl[i].s_size;
141                 printf("%8s: 0x%08x .. 0x%08x, 0x%x (%d) bytes.\n",
142                         name,ScnTbl[i].s_paddr,ScnTbl[i].s_paddr+size,size,size);
143         }
144 }
145
146 void
147 ShowCoffOffsets(void)
148 {
149         int     i, start;
150
151         start = sizeof(struct filehdr) + CoffFhdr.f_opthdr;
152         printf("\n\t\tCOFF FILE SECTION FILE OFFSETS\n");
153
154         for(i=0;i<CoffFhdr.f_nscns;i++) {
155                 printf("%8s: 0x%08x .. 0x%08x (%d bytes)\n",
156                         ScnTbl[i].s_name,ScnTbl[i].s_scnptr,
157                         ScnTbl[i].s_scnptr+ScnTbl[i].s_size,
158                         ScnTbl[i].s_size);
159                 start += ScnTbl[i].s_size;
160         }
161 }
162
163 /* GetCoffFileHdr():
164    Retrieve the header from the file and do a BE-to-LE conversion
165    on each of its members.
166 */
167 struct filehdr *
168 GetCoffFileHdr(void)
169 {
170         off_t here;
171
172         if (verbose)
173                 fprintf(stderr,"GetCoffFileHdr()\n");
174
175         /* Read in the coff file header. */
176         Lseek(coffFD,0,SEEK_SET);
177         Read(coffFD,(char *)&CoffFhdr,(unsigned)sizeof(struct filehdr));
178         CoffFhdr.f_magic = otherEnd16(Ecvt,CoffFhdr.f_magic);
179         CoffFhdr.f_nscns = otherEnd16(Ecvt,CoffFhdr.f_nscns);
180         CoffFhdr.f_timdat = otherEnd32(Ecvt,CoffFhdr.f_timdat);
181         CoffFhdr.f_symptr = otherEnd32(Ecvt,CoffFhdr.f_symptr);
182         CoffFhdr.f_nsyms = otherEnd32(Ecvt,CoffFhdr.f_nsyms);
183         CoffFhdr.f_opthdr = otherEnd16(Ecvt,CoffFhdr.f_opthdr);
184         CoffFhdr.f_flags = otherEnd16(Ecvt,CoffFhdr.f_flags);
185
186         if (CoffFhdr.f_opthdr) {
187                 here = Lseek(coffFD,0,SEEK_CUR);
188                 if (tiMode != 0)
189                         Lseek(coffFD,2,SEEK_CUR);
190                 Read(coffFD,(char *)&OptAhdr,(unsigned)sizeof(struct aouthdr));
191                 OptAhdr.magic = otherEnd16(Ecvt,OptAhdr.magic);
192                 OptAhdr.vstamp = otherEnd16(Ecvt,OptAhdr.vstamp);
193                 OptAhdr.tsize = otherEnd32(Ecvt,OptAhdr.tsize);
194                 OptAhdr.dsize = otherEnd32(Ecvt,OptAhdr.dsize);
195                 OptAhdr.bsize = otherEnd32(Ecvt,OptAhdr.bsize);
196                 OptAhdr.entry = otherEnd32(Ecvt,OptAhdr.entry);
197                 OptAhdr.text_start = otherEnd32(Ecvt,OptAhdr.text_start);
198                 OptAhdr.data_start = otherEnd32(Ecvt,OptAhdr.data_start);
199                 if (CoffFhdr.f_opthdr != sizeof(struct aouthdr)) {
200                         fprintf(stderr,"Warning: f_opthdr != size of aouthdr\n");
201                         Lseek(coffFD,here+CoffFhdr.f_opthdr,SEEK_SET);
202                 }
203         }
204         return(&CoffFhdr);
205 }
206
207 int
208 GetCoffSectionHdrs(void)
209 {
210         int     i;
211
212         ScnTbl = (struct scnhdr *)Malloc(CoffFhdr.f_nscns * sizeof(struct scnhdr));
213
214         /* Read in the coff section headers. */
215         if (tiMode == 0)
216                 Lseek(coffFD,sizeof(struct filehdr)+CoffFhdr.f_opthdr,SEEK_SET);
217         else
218                 Lseek(coffFD,0x782,SEEK_SET);
219
220
221         for(i=0;i<CoffFhdr.f_nscns;i++) {
222                 Read(coffFD,(char *)&ScnTbl[i],sizeof(struct scnhdr));
223
224                 ScnTbl[i].s_paddr = otherEnd32(Ecvt,ScnTbl[i].s_paddr);
225                 ScnTbl[i].s_vaddr = otherEnd32(Ecvt,ScnTbl[i].s_vaddr);
226                 ScnTbl[i].s_size = otherEnd32(Ecvt,ScnTbl[i].s_size);
227                 ScnTbl[i].s_scnptr = otherEnd32(Ecvt,ScnTbl[i].s_scnptr);
228                 ScnTbl[i].s_relptr = otherEnd32(Ecvt,ScnTbl[i].s_relptr);
229                 ScnTbl[i].s_lnnoptr = otherEnd32(Ecvt,ScnTbl[i].s_lnnoptr);
230                 ScnTbl[i].s_nreloc = otherEnd16(Ecvt,ScnTbl[i].s_nreloc);
231                 ScnTbl[i].s_nlnno = otherEnd16(Ecvt,ScnTbl[i].s_nlnno);
232                 ScnTbl[i].s_flags = otherEnd32(Ecvt,ScnTbl[i].s_flags);
233                 if (tiMode)
234                         Lseek(coffFD,8,SEEK_CUR);
235         }
236
237         return(CoffFhdr.f_nscns);
238 }
239
240 void
241 CoffToBinary(char *binto)
242 {
243         int     fd, sidx, firstone;
244         uchar   *cp;
245         struct  scnhdr  *sptr;
246
247         unlink(binto);
248         if ((fd = open(binto,O_WRONLY|O_BINARY|O_CREAT,0777))==-1)
249         {
250                 perror(binto);
251                 exit(1);
252         }
253         fprintf(stderr,"Converting %s into %s\n",
254                 coffFname,binto);
255         firstone = 1;
256         for(sptr=ScnTbl,sidx=0;sidx<CoffFhdr.f_nscns;sidx++,sptr++) {
257                 char    name[9], padbyte;
258                 int             padtot;
259                 long    nextpaddr;
260                 
261                 memcpy(name,sptr->s_name,8);
262                 name[8] = 0;
263
264                 if ((sptr->s_flags != STYP_BSS) &&
265                     (sptr->s_flags != STYP_INFO) &&
266                     (sptr->s_size)) {
267                         if (!firstone) {        /* Pad if necessary... */
268                                 if ((!noPad) && (nextpaddr != sptr->s_paddr)) {
269                                         if (sptr->s_paddr < nextpaddr) {
270                                                 fprintf(stderr,"Unexpected section address\n");
271                                                 exit(1);
272                                         }
273                                         padtot = sptr->s_paddr-nextpaddr;
274                                         printf("Pad 0x%x bytes\n",padtot);
275                                         padbyte = 0;
276                                         while(padtot) {
277                                                 write(fd,&padbyte,1);
278                                                 padtot--;
279                                         }
280                                 }
281                         }
282                         printf("Sec %-8s at 0x%-8x 0x%-6x bytes\n",
283                                 name,sptr->s_paddr,sptr->s_size);
284                         cp = (uchar *)Malloc(sptr->s_size);
285                         Lseek(coffFD,sptr->s_scnptr,SEEK_SET);
286                         read(coffFD,cp,sptr->s_size);
287                         write(fd,cp,sptr->s_size);
288                         free(cp);
289                         nextpaddr = sptr->s_paddr + sptr->s_size;
290                         firstone = 0;
291                 }
292         }
293         close(fd);
294 }       
295
296 void
297 PackCoffSections(char *packto)
298 {
299         char    *ibuf,*obuf, *sdata, *obase, *ibase;
300         int             i, pfd, sno, savings;
301         struct  stat finfo;
302         struct  filehdr *coffp;
303         struct  scnhdr *sp;
304
305         unlink(packto);
306         if ((pfd = open(packto,O_WRONLY|O_BINARY|O_CREAT,0777))==-1)
307         {
308                 perror(packto);
309                 exit(1);
310         }
311         fprintf(stderr,"Packing %s into %s...\n",
312                 coffFname,packto);
313
314         /* First copy the entire COFF file into the input buffer: */
315         fstat(coffFD,&finfo);
316         Lseek(coffFD,0,SEEK_SET);
317         ibuf = Malloc(finfo.st_size+32);
318         ibase = ibuf;
319         obuf = Malloc(finfo.st_size+32);
320         obase = obuf;
321         coffp = (struct filehdr *)obase;
322         Read(coffFD,ibuf,finfo.st_size);
323
324         /* Now copy the file header and optional header to the out buffer: */
325         for(i=0;i<sizeof(struct filehdr)+CoffFhdr.f_opthdr;i++)
326                 *obuf++ = *ibuf++;
327
328         /* Since the output file will be stripped, modify the new header: */
329         coffp->f_symptr = 0;
330         coffp->f_nsyms = 0;
331
332         /* At this point ibuf & obuf are at the base of the table of section */
333         /* headers.  The section headers must be adjusted because the size */
334         /* of the sections will be changing, so for each section, compress */
335         /* the data and adjust the header information... */
336         sp = (struct scnhdr *)obuf;
337
338         /* Set sdata to point into the new buffer at the point immediately */
339         /* after the headers. This pointer will be used to write the new */
340         /* compressed sections. */
341         sdata = obase + sizeof(struct filehdr) + CoffFhdr.f_opthdr +
342                 (CoffFhdr.f_nscns * sizeof(struct scnhdr));
343
344         /* For each section, if the section is loadable, the compress the */
345         /* data associated with that section... */
346         savings = 0;
347         for (sno=0;sno<CoffFhdr.f_nscns;sno++) {
348                 int     psize;
349
350                 /* If the section has data, compress it and adjust the */
351                 /* section header information. */
352                 if (ScnTbl[sno].s_scnptr) {
353                         /* Compress the section: */
354                         printf("Section %s: ",ScnTbl[sno].s_name);
355                         psize = packdata(ibase+ScnTbl[sno].s_scnptr,sdata,
356                                 ScnTbl[sno].s_size,1);
357
358                         /* Keep track of total space saved: */
359                         savings += (ScnTbl[sno].s_size - psize);
360
361                         /* Adjust the affected section header members: */
362                         ScnTbl[sno].s_size = psize;
363                         ScnTbl[sno].s_scnptr = (unsigned long)(sdata - obase);
364                         sdata += psize;
365                 }
366
367                 memcpy(sp->s_name,ScnTbl[sno].s_name,8);
368                 sp->s_paddr = otherEnd32(Ecvt,ScnTbl[sno].s_paddr);
369                 sp->s_vaddr = otherEnd32(Ecvt,ScnTbl[sno].s_vaddr);
370                 sp->s_size = otherEnd32(Ecvt,ScnTbl[sno].s_size);
371                 sp->s_scnptr = otherEnd32(Ecvt,ScnTbl[sno].s_scnptr);
372                 sp->s_relptr = otherEnd32(Ecvt,ScnTbl[sno].s_relptr);
373                 sp->s_lnnoptr = otherEnd32(Ecvt,ScnTbl[sno].s_lnnoptr);
374                 sp->s_nreloc = otherEnd16(Ecvt,ScnTbl[sno].s_nreloc);
375                 sp->s_nlnno = otherEnd16(Ecvt,ScnTbl[sno].s_nlnno);
376                 sp->s_flags = otherEnd32(Ecvt,ScnTbl[sno].s_flags);
377                 sp++;
378         }
379
380         if (write(pfd,(char *)obase,sdata-obase) != (sdata-obase)) {
381                 perror(packto);
382                 exit(1);
383         }
384         close(pfd);
385         free(ibase);
386         free(obase);
387         printf("Total savings of %d bytes\n",savings);
388 }
389
390 int
391 zipdata(src,dest,srcsize,mode,verbose)
392 char    *src, *dest, *mode;
393 int             srcsize, verbose;
394 {
395         int      zfd;
396         FILE *zout;
397         char *zoutfile;
398         struct stat zstat;
399
400         zoutfile = "zout";
401         unlink(zoutfile);
402
403         zout = gzopen(zoutfile, mode);
404     if (zout == NULL) {
405         fprintf(stderr, "can't gzopen %s\n", zoutfile);
406         exit(1);
407     }
408         if (gzwrite(zout, src, (unsigned)srcsize) != srcsize) {
409                 fprintf(stderr, "gzwrite failed\n");
410                 exit(1);
411         }
412     if (gzclose(zout) != Z_OK) {
413         fprintf(stderr, "gzclose failed\n");
414                 exit(1);
415         }
416         stat(zoutfile,&zstat);
417         if ((zfd = open(zoutfile,O_RDONLY|O_BINARY)) == -1) {
418         fprintf(stderr, "can't open %s\n",zoutfile);
419                 exit(1);
420         }
421         Read(zfd,dest,zstat.st_size);
422         close(zfd);
423         unlink(zoutfile);
424         if (verbose) {
425                 printf("%d%% compression (from %d to %d bytes)\n",
426                         (int)(((double)(zstat.st_size)/
427                          (double)srcsize)*100),srcsize,zstat.st_size);
428         }
429         return(zstat.st_size);
430 }
431
432 void
433 ZipCoffSections(int zlevel)
434 {
435         char    *ibuf,*obuf, *sdata, *obase, *ibase;
436         int             i, pfd, sno, savings;
437         char    zipto[128], mode[16];
438         struct  stat finfo;
439         struct  filehdr *coffp;
440         struct  scnhdr *sp;
441
442         sprintf(mode,"wb%d ",zlevel);
443         sprintf(zipto,"%s.czip",coffFname);
444         fprintf(stderr,"Compressing %s into %s \n",coffFname,zipto);
445
446         unlink(zipto);
447         if ((pfd = open(zipto,O_WRONLY|O_BINARY|O_CREAT,0777))==-1) {
448                 perror(zipto);
449                 exit(1);
450         }
451         fprintf(stderr,"Zipping %s into %s...\n",coffFname,zipto);
452
453         /* First copy the entire COFF file into the input buffer: */
454         fstat(coffFD,&finfo);
455         Lseek(coffFD,0,SEEK_SET);
456         ibuf = Malloc(finfo.st_size+32);
457         ibase = ibuf;
458         obuf = Malloc(finfo.st_size+32);
459         obase = obuf;
460         coffp = (struct filehdr *)obase;
461         Read(coffFD,ibuf,finfo.st_size);
462
463         /* Now copy the file header and optional header to the out buffer: */
464         for(i=0;i<sizeof(struct filehdr)+CoffFhdr.f_opthdr;i++)
465                 *obuf++ = *ibuf++;
466
467         /* Since the output file will be stripped, modify the new header: */
468         coffp->f_symptr = 0;
469         coffp->f_nsyms = 0;
470
471         /* At this point ibuf & obuf are at the base of the table of section */
472         /* headers.  The section headers must be adjusted because the size */
473         /* of the sections will be changing, so for each section, compress */
474         /* the data and adjust the header information... */
475         sp = (struct scnhdr *)obuf;
476
477         /* Set sdata to point into the new buffer at the point immediately */
478         /* after the headers. This pointer will be used to write the new */
479         /* compressed sections. */
480         sdata = obase + sizeof(struct filehdr) + CoffFhdr.f_opthdr +
481                 (CoffFhdr.f_nscns * sizeof(struct scnhdr));
482
483         /* For each section, if the section is loadable, the compress the */
484         /* data associated with that section... */
485         savings = 0;
486         for (sno=0;sno<CoffFhdr.f_nscns;sno++) {
487                 int     psize;
488
489                 /* If the section has data, compress it and adjust the */
490                 /* section header information. */
491                 if (ScnTbl[sno].s_scnptr) {
492                         /* Compress the section: */
493                         printf("Section %s: ",ScnTbl[sno].s_name);
494                         psize = zipdata(ibase+ScnTbl[sno].s_scnptr,sdata,
495                                 ScnTbl[sno].s_size,mode,1);
496
497                         /* Keep track of total space saved: */
498                         savings += (ScnTbl[sno].s_size - psize);
499
500                         /* Adjust the affected section header members: */
501                         ScnTbl[sno].s_size = psize;
502                         ScnTbl[sno].s_scnptr = (unsigned long)(sdata - obase);
503                         sdata += psize;
504                 }
505
506                 memcpy(sp->s_name,ScnTbl[sno].s_name,8);
507                 sp->s_paddr = otherEnd32(Ecvt,ScnTbl[sno].s_paddr);
508                 sp->s_vaddr = otherEnd32(Ecvt,ScnTbl[sno].s_vaddr);
509                 sp->s_size = otherEnd32(Ecvt,ScnTbl[sno].s_size);
510                 sp->s_scnptr = otherEnd32(Ecvt,ScnTbl[sno].s_scnptr);
511                 sp->s_relptr = otherEnd32(Ecvt,ScnTbl[sno].s_relptr);
512                 sp->s_lnnoptr = otherEnd32(Ecvt,ScnTbl[sno].s_lnnoptr);
513                 sp->s_nreloc = otherEnd16(Ecvt,ScnTbl[sno].s_nreloc);
514                 sp->s_nlnno = otherEnd16(Ecvt,ScnTbl[sno].s_nlnno);
515                 sp->s_flags = otherEnd32(Ecvt,ScnTbl[sno].s_flags);
516                 sp++;
517         }
518
519         if (write(pfd,(char *)obase,sdata-obase) != (sdata-obase)) {
520                 perror(zipto);
521                 exit(1);
522         }
523         close(pfd);
524         free(ibase);
525         free(obase);
526         printf("Total savings of %d bytes\n",savings);
527 }
528
529 void
530 StripCoffFile(char *stripto,char *append)
531 {
532         int     size, sfd, afd;
533         struct  filehdr *coffp;
534
535         unlink(stripto);
536         if ((sfd = open(stripto,O_WRONLY|O_BINARY|O_CREAT,0777))==-1)
537         {
538                 perror(stripto);
539                 exit(1);
540         }
541         fprintf(stderr,"Stripping %s into %s...\n",
542                 coffFname,stripto);
543         Lseek(coffFD,0,SEEK_SET);
544         size = CoffFhdr.f_symptr;
545         coffp = (struct filehdr *)Malloc(size+32);
546         Read(coffFD,(char *)coffp,size);
547         coffp->f_symptr = 0;
548         coffp->f_nsyms = 0;
549         if (write(sfd,(char *)coffp,size) != size) {
550                 perror(stripto);
551                 exit(1);
552         }
553         if (append) {
554                 struct  stat buf;
555                 char    *aspace;
556                 if ((afd = open(append,O_RDONLY|O_BINARY))==-1)
557                 {
558                         perror(append);
559                         exit(1);
560                 }
561                 stat(append,&buf);
562                 aspace = Malloc(buf.st_size+32);
563                 read(afd,aspace,buf.st_size);
564                 write(sfd,aspace,buf.st_size);
565                 free(aspace);
566                 close(afd);
567         }
568         close(sfd);
569 }
570
571 char *usage_txt[] = {
572         "Usage: coff [options] {filename}",
573         " Options:",
574         " -a{filename}  append file to end of -S file",
575         " -A            print what was appended by -a",
576         " -B{filename}  coff-2-bin to filename",
577         " -c            BE-to-LE convert",
578         " -f            show coff file header",
579         " -M            show coff map with file offsets",
580         " -m            show coff map without file offsets",
581         " -n            no padding with -B option",
582         " -p{filename}  pack to specified file (output file is also stripped)",
583         " -s            show coff section headers",
584         " -S{filename}  strip to specified file",
585         " -T{mode}      TI-COFF mode (experimental)",
586         " -V            display version of tool",
587         " -v            verbose mode",
588         " -z{zlvl}      compress sections of filename to 'filename.czip'",
589         "               zlvl can range from 1-9 (typically 6) where...",
590         "               1 is faster/lighter compression",
591         "               9 is slower/heavier compression",
592         0,
593 };
594
595 int
596 main(int argc,char *argv[])
597 {
598         extern  int optind;
599         extern  char *optarg;
600         char    fname[128], *append, *stripto, *binto, *packto;
601         int             tot, opt, showstuff, zlevel;
602
603         zlevel = verbose = 0;
604         showstuff = 0;
605         packto = (char *)0;
606         stripto = (char *)0;
607         append = (char *)0;
608         binto = (char *)0;
609         noPad = 0;
610         tiMode = 0;
611 #ifdef BUILD_WITH_VCC
612         Ecvt = 1;
613 #else
614         Ecvt = 0;
615 #endif
616         while ((opt=getopt(argc,argv,"Aa:cB:dfmMnp:sS:T:vVz:")) != EOF) {
617                 switch(opt) {
618                 case 'a':
619                         append = optarg;
620                         break;
621                 case 'A':
622                         showstuff |= SHOWAPPEND;
623                         break;
624                 case 'B':
625                         binto = optarg;
626                         break;
627                 case 'c':
628                         if (Ecvt)
629                                 Ecvt = 0;
630                         else
631                                 Ecvt = 1;
632                         break;
633                 case 'f':
634                         showstuff |= SHOWHDR;
635                         break;
636                 case 'M':
637                         showstuff |= SHOWMAPOFFSET;
638                         break;
639                 case 'm':
640                         showstuff |= SHOWMAP;
641                         break;
642                 case 'n':
643                         noPad = 1;
644                         break;
645                 case 'p':
646                         packto = optarg;
647                         break;
648                 case 'S':
649                         stripto = optarg;
650                         break;
651                 case 's':
652                         showstuff |= SHOWSECTIONS;
653                         break;
654                 case 'T':
655                         tiMode = atoi(optarg);
656                         break;
657                 case 'v':
658                         verbose = 1;
659                         break;
660                 case 'V':
661                         showVersion();
662                         break;
663                 case 'z':
664                         zlevel = atoi(optarg);
665                         if ((zlevel < 1) || (zlevel > 9))
666                                 usage("zlvl out of range\n");
667                         break;
668                 default:
669                         usage(0);
670                 }
671         }
672
673         if (argc != (optind+1))
674                 usage("Missing filename");
675
676         strcpy(fname,argv[optind]);
677
678         if (!fileexists(fname)) {
679                 fprintf(stderr,"No such file: %s\n",fname);
680                 exit(1);
681         }
682
683         if ((coffFD = open(fname,O_RDONLY|O_BINARY)) == -1)
684         {
685                 perror(fname);
686                 exit(1);
687         }
688
689         if (append && !stripto)
690                 usage("-a requires -S");
691
692         tot = 0;
693         if (binto) tot++;
694         if (packto) tot++;
695         if (stripto) tot++;
696         if (tot > 1)
697                 usage("-S, -B and -p options must be run individually");
698
699         coffFname = StrAllocAndCopy(fname);
700         GetCoffFileHdr();
701         GetCoffSectionHdrs();
702
703         if (binto) {
704                 CoffToBinary(binto);
705         }
706         else if (zlevel) {
707                 ZipCoffSections(zlevel);
708         }
709         else if (packto) {
710                 PackCoffSections(packto);
711         }
712         else if (stripto) {
713                 StripCoffFile(stripto,append);
714         }
715         else {
716                 if (showstuff & SHOWAPPEND)
717                         ShowAppend();
718                 if (showstuff & SHOWHDR)
719                         ShowCoffHdr();
720                 if (showstuff & SHOWMAP)
721                         ShowCoffMap();
722                 if (showstuff & SHOWMAPOFFSET)
723                         ShowCoffOffsets();
724                 if (showstuff & SHOWSECTIONS)
725                         ShowCoffSections();
726         }
727         return(0);
728 }