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