home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / ARCHIVE / ZIPOFF.ZIP / ZIPOFF.C next >
Encoding:
C/C++ Source or Header  |  1991-07-04  |  20.5 KB  |  603 lines

  1. #include <stdio.h>
  2. #include <io.h>
  3. #include <conio.h>
  4. #include <fcntl.h>
  5. #include <dos.h>
  6. #include <stdlib.h>
  7. #include <alloc.h>
  8. #include <math.h>
  9. #include <mem.h>
  10. #include <ctype.h>
  11. #include <errno.h>
  12. #include <sys/stat.h>
  13.  
  14. /*
  15.  *  Written and Copyright (c) 1990-1991 by Morgan R. Schweers  (mrs@netcom.com)
  16.  *
  17.  *
  18.  *  History:  V1.0
  19.  *            Cleaned up the code, and the output, so it looked a little
  20.  *            less like the homemade hack that it is.  Also wrote the docs.
  21.  *            First public release
  22.  *
  23.  *                One of the reasons I commented it so heavily is so others
  24.  *            can use the code to write their own handlers of .ZIP files.
  25.  *            (No, I *DON'T* normally code like this.)  For all up-and-coming
  26.  *            ZIPhandler writers, *READ AND LEARN APPNOTE.TXT!*  <grin>
  27.  *
  28.  *                If you have any questions on the code, feel free to drop
  29.  *            me a line at mrs@netcom.com or ms@gnu.ai.mit.edu.  If you have
  30.  *            a feature you think would be good to add, feel free to write it
  31.  *            up and send it to me.
  32.  *
  33.  *                The source is all here.  It was compiled with Turbo C++ 1.0,
  34.  *            with the command line:
  35.  *            tcc -ml -G -C zipoff.c
  36.  *
  37.  */
  38.  
  39. #define TRUE 1
  40. #define FALSE !TRUE
  41. #define WORD *(unsigned int*)&buffer
  42. #define LONG *(unsigned long*)&buffer
  43. #define c_size sizeof(struct central_dir)
  44. #define BLOCKSIZE 8192
  45. #define INTRO "Zipoff V1.0 Copyright 1990-91 by Morgan Schweers.  (408) 727-2736\n"
  46.  
  47. struct central_dir {
  48.                      unsigned long central_sig;
  49.                      unsigned vmade, vneed, bflag, method, ftime, fdate;
  50.                      unsigned long crc,csize,usize;
  51.                      unsigned fnlen,eflen, comlen, dnum_st, iatt;
  52.                      unsigned long xatt,local_offset;
  53.                      char far *fname, far *efield, far *comment;
  54.                    };
  55.  
  56. struct llist {
  57.                  struct central_dir far *data;
  58.              };
  59.  
  60. /*
  61.  *  parse_args(int, char **) ->
  62.  *          Order things properly, so the data can be easily
  63.  *      retrieved.  I decided to do it myself, rather than
  64.  *      incorporating someone else's getopt() function.
  65.  *
  66.  *          It packs parameters against the beginning, preserving
  67.  *      the order.  Directly following that are the options.
  68.  *      Both '-' and '/' work as qualifiers.
  69.  */
  70.  
  71. int parse_args(int args, char **arglist)
  72. {
  73.   char *swap;
  74.   int i,j,total_normal=0;  /*  total keeps track of # of the non-option
  75.                                parameters specified.  */
  76.  
  77.   while(i!=3 && j<=args) {
  78.     for(i=1; i<=args && !(arglist[i][0]=='-' || arglist[i][0]=='/'); i++);
  79.     if(i!=3) {
  80.        for(j=i; j<=args && (arglist[j][0]=='-' || arglist[j][0]=='/'); j++);
  81.        if(j<=args) {
  82.          swap = arglist[i];
  83.          arglist[i] = arglist[j];
  84.          arglist[j] = swap;
  85.        }
  86.     }
  87.   }
  88.  
  89.   for(i=1; i<=args; i++)
  90.     if(arglist[i][0]=='-' || arglist[i][0]=='/')
  91.        arglist[i]++;
  92.     else
  93.       ++total_normal;
  94.  
  95.   return(total_normal);
  96. }
  97.  
  98. /*
  99.  *  main() ->
  100.  *              Nope, none of this is broken down into subroutines.
  101.  *           It probably could be, and the code would be much much
  102.  *           prettier afterwards.  Someday I may just do that.
  103.  *
  104.  *              The basic idea is:  Find out the number of records.
  105.  *           Load all the records in.  Sort them all in order of
  106.  *           largest files (after compression) first.  Scan
  107.  *           through them, copying the files that will fit in the
  108.  *           remaining space on the disk.  (Or that will fit within
  109.  *           the limit given.)
  110.  *               After the limit has been reached, add the central
  111.  *           directory header on, and we're finished w/ that .ZIP.
  112.  *           Prompt the user, and go around again.
  113.  *
  114.  *               After we're all done, beep and tell the user.
  115.  *
  116.  *   Variables used:
  117.  *      cur_loc is the current location in the file.
  118.  *      limit is the number of bytes left available on the drive.
  119.  *      bmove is the number of bytes to move to the destination ZIP.
  120.  *      moved keeps track of the number of bytes moved for each file.
  121.  *      nzsize points to the directory area of the ZIP.
  122.  *      nzsize_2 points to the "end of central dir record"
  123.  *      real_limit is the maximum limit either specified or on the destination
  124.  *
  125.  *      fname has the destination file name.
  126.  *      buffer stores the data read in.
  127.  *
  128.  *      zipnum is 'xx' in NEWZIPxx.ZIP
  129.  *      rval holds return values
  130.  *      gave_limit, interactive, and bad_command_line are booleans based on
  131.  *          the options selected on the command line.
  132.  *
  133.  *      Block is used to display the "I'm alive" pulsar
  134.  *
  135.  *      cur_rec is the total number of records.
  136.  *      total_files is a count of the total number of files
  137.  *          that have been copied so far.
  138.  *      local_files is a count of the number of local files
  139.  *          that have been copied so far.
  140.  *
  141.  *      entry, temp, and first are all part of the array used to store
  142.  *          pointers to the directory data.
  143.  *      swap is used in the bubble sort.
  144.  *      dt is used in the diskfree routine, to determine the amount of
  145.  *          free space left.
  146.  */
  147.  
  148. main(int argc, char **argv)
  149. {
  150.   unsigned long cur_loc=0L, limit=0L, bmove=0L, count=1L, moved=0L, nzsize=0L, nzsize_2=0L, real_limit=0L;
  151.   unsigned char fname[128], ch, input_fname[128];
  152.   unsigned char *buffer;
  153.   int r_handle, w_handle, rw_handle, zipnum=0, rval=0;
  154.   int i=1, j=0, gave_limit=FALSE, interactive=TRUE, bad_command_line=FALSE;
  155.  
  156.   char block[5]="|/-\\";
  157.   unsigned char *zipbase=NULL, *maxspace=NULL;
  158.   unsigned cur_rec=0, total_files=0, local_files=0, pulse=0;
  159.  
  160.   struct llist far *entry, far *temp, far *first;
  161.   struct central_dir far *swap;
  162.   struct dfree dt;
  163.  
  164.   printf(INTRO);  /*  Say hello to the nice users  */
  165.  
  166.   argc--;
  167.   if(argc>=2 && argc<=5) {
  168.      /*  Check what they put in for arguments...  */
  169.      rval = parse_args(argc, argv);
  170.      if(rval!=2) bad_command_line = TRUE;
  171.   } else bad_command_line = TRUE;
  172.  
  173.   /*  If they've not typed a proper command line, tell them so */
  174.   if(bad_command_line == TRUE) {
  175.      printf("\ausage: zipoff {zipfile} {destination path} [options]\n");
  176.  
  177.      printf("\n[options] =\n\t-b{basename}\t--  Sets the base filename for the output .ZIP's\n");
  178.      printf("\t\t\t(maximum of 6 characters, defaults to NEWZIP)\n\t");
  179.  
  180.      printf("-mXXXX\t\t--  Sets the maximum output file size for the .ZIP's\n");
  181.      printf("\t\t\t(defaults to the space remaining on the default drive)\n");
  182.  
  183.      printf("\t-n\t\t--  Non-interactive mode.  Does not prompt between ZIPs\n");
  184.      printf("\t\t\t(requires the -mXXXX option. Defaults to interactive)\n");
  185.  
  186.      printf("\n\nNote:  The destination path *MUST* start with a drive letter, unless\n");
  187.      printf("\tyou are specifying a maximum output size.\n");
  188.      printf("\n\nExamples:\tzipoff cdrive.zip b:\\ -bcdrive\n");
  189.      printf("\t\tzipoff -n c:\\realbig.zip /bbigfil .\\ -m1048576\n");
  190.      printf("    (note that both the forward slash and the dash are acceptable delimiters,\n");
  191.      printf("     and that options can be sprinkled among the required parameters.)\n");
  192.      printf("\t\tzipoff test.zip b:\n");
  193.      return(1);
  194.   }
  195.  
  196.   /*  Check if any of the arguments were specified */
  197.   for(i=3; i<=argc; i++) {
  198.     if(argv[i][0]=='b') { zipbase = argv[i]; zipbase++; }
  199.     if(argv[i][0]=='m') { maxspace= argv[i]; maxspace++; gave_limit=TRUE; }
  200.     if(argv[i][0]=='n') { interactive = FALSE; }
  201.   }
  202.  
  203.   /*  If they didn't give the '-m' option, but gave the '-n' option, yell.  */
  204.   if(!gave_limit && !interactive) {
  205.       interactive=TRUE;
  206.       printf("\awarning:  non-interactive mode requires the -m option\n");
  207.       return(1);
  208.   }
  209.  
  210.   /*  No zipbase?  Default to NEWZIP  */
  211.   if(zipbase == NULL) {
  212.      zipbase = malloc(7);
  213.      strcpy(zipbase,"NEWZIP");
  214.   }
  215.  
  216.   /*  If they gave a maximum, check it.  */
  217.   if(gave_limit) {
  218.      real_limit = atol(maxspace);
  219.      if(real_limit == 0) {
  220.        gave_limit = FALSE;
  221.        printf("A maximum file space of %s is not valid.\n",maxspace);
  222.        return(1);
  223.      }
  224.   }
  225.  
  226.   /*  Check the length of 'zipbase' and warn the user if truncating  */
  227.   if(strlen(zipbase)>6) {
  228.      printf("Truncating %s to ",zipbase);
  229.      zipbase[6]=0;
  230.      printf("%s.\n",zipbase);
  231.   }
  232.  
  233.   buffer = farmalloc(BLOCKSIZE);
  234.  
  235.   if(buffer==NULL) {
  236.     printf("Memory allocation error, core dumped. {Just kidding about the core!}\n");
  237.     printf("Not enough memory to run.\n");
  238.     return(1);
  239.   }
  240.  
  241.   /*  Add on .ZIP if they haven't an extension  */
  242.   strcpy(input_fname, argv[1]);
  243.   if(strchr(input_fname,'.')==NULL)
  244.      strcat(input_fname,".ZIP");
  245.  
  246.   r_handle = open(input_fname,O_BINARY | O_RDONLY);
  247.   if(r_handle == -1) {
  248.      printf("File %s not found.\n",input_fname);
  249.      return(1);
  250.   }
  251.  
  252.   /*  Read in the header of the first file...  */
  253.   rval = read(r_handle, buffer, 30);
  254.   if(rval!=30) {
  255.      printf("Difficulty reading file %s.\n",input_fname);
  256.      return(1);
  257.   }
  258.  
  259.   /*  Count the records in the file  */
  260.   while(WORD[2] == 0x0403)
  261.   {
  262.     cur_loc = lseek(r_handle, LONG[18] + WORD[26] + WORD[28], SEEK_CUR);
  263.     printf("%5.5d\r",cur_rec);
  264.     cur_rec++;
  265.     read(r_handle, buffer,30);
  266.   }
  267.  
  268.   printf("Total number of files in ZIPfile = %d.\n",cur_rec);
  269.   if(gave_limit) printf("The maximum file size for output files is %lu.\n",(unsigned long) real_limit);
  270.  
  271.   /*  If nothing was found, then there's clearly a problem, neh?  */
  272.   if(cur_rec==0) {
  273.      printf("No records found.  Is %s a .ZIP file?\n",input_fname);
  274.      return(1);
  275.   }
  276.  
  277.   /*
  278.    *  Yes, this *WILL* fail on more than 65528/(sizeof (struct llist))
  279.    *  entries.  If anyone gets to that level, contact me.
  280.    */
  281.   entry = farcalloc(cur_rec, sizeof(struct llist));
  282.  
  283.   if(entry==NULL) {
  284.      printf("Too many records.  (WOW!  That's over 16,380 files!)\n");
  285.      printf("If it's less, please contact the author.\n");
  286.      free(buffer);
  287.      return(1);
  288.   }
  289.  
  290.   first = entry;
  291.   lseek(r_handle, cur_loc, SEEK_SET);
  292.   read(r_handle, buffer, 46);
  293.  
  294.   entry->data = farmalloc((size_t) c_size);
  295.  
  296.   if(entry->data == NULL) {
  297.      printf("Problems allocating memory.\n");
  298.      free(buffer);
  299.      return(1);
  300.   }
  301.  
  302.   i=1;  /*  Initialize I again  */
  303.  
  304.   while(WORD[2] == 0x0201 && entry->data != NULL)
  305.   {
  306.     printf("Loading: %5.5d, Memory left: %8.8ld\r",i++,farcoreleft());
  307.     memcpy(entry->data,buffer,46);
  308.  
  309.     /*  Allocate exactly enough bytes for the filename  */
  310.     entry->data->fname = farmalloc(entry->data->fnlen);
  311.  
  312.     /* If there's an extented field, then allocate space for the extended field */
  313.     if(entry->data->eflen != 0) entry->data->efield= farmalloc(entry->data->eflen);
  314.  
  315.     /*  Allocate space for the comment, if there is one.  */
  316.     if(entry->data->comlen!= 0) entry->data->comment = farmalloc(entry->data->comlen);
  317.  
  318.     /*  Load up the filename  */
  319.     read(r_handle, entry->data->fname, entry->data->fnlen);
  320.  
  321.     /*  Load up the extended data  */
  322.     if(entry->data->eflen != 0) read(r_handle, entry->data->efield, entry->data->eflen);
  323.  
  324.     /*  Load up the comment  */
  325.     if(entry->data->comlen!= 0) read(r_handle, entry->data->comment,entry->data->comlen);
  326.     entry++;
  327.     entry->data = farmalloc((size_t) c_size);
  328.     if(entry->data==NULL) {
  329.        printf("Out of memory at record %d.\n",i);
  330.        printf("This ZIP needs around %ld bytes of free space.\n",(unsigned long) cur_rec*(c_size+40));
  331.        entry=first;
  332.        for(j=0; j<i; j++) {
  333.           free(entry->data);
  334.           entry++;
  335.        }
  336.        free(first);
  337.        free(buffer);
  338.        return(1);
  339.     }
  340.     read(r_handle, buffer, 46);  /*  Read in the next header */
  341.   }
  342.  
  343.   printf("\nSorting entry ");
  344.   entry = first;
  345.  
  346.   /*  Create a single header-sized swap area for the upcoming sort  */
  347.   swap = farmalloc(sizeof(struct llist));
  348.  
  349.   if(swap == NULL) {
  350.      printf("Out of memory while attempting to allocate %d bytes of memory.\n");
  351.      printf("Don't you HATE when that happens?\n");
  352.      entry=first;
  353.      for(j=0; j<cur_rec; j++) {
  354.         free(entry->data);
  355.         entry++;
  356.      }
  357.      free(first);
  358.      free(buffer);
  359.      return(1);
  360.   }
  361.  
  362.   /*  Yes, this *IS* a bubble sort.  So what?  It works!  */
  363.   while(entry->data->central_sig==0x02014b50)
  364.   {
  365.     printf("%5.5d.\b\b\b\b\b\b",count);
  366.     count++;
  367.     temp = entry;
  368.     temp++;
  369.     while(temp->data->central_sig==0x02014b50)
  370.     {
  371.       if(entry->data->csize < temp->data->csize)
  372.       {
  373.         swap = entry->data;
  374.         entry->data = temp->data;
  375.         temp->data = swap;
  376.       }
  377.       temp++;
  378.     }
  379.     entry++;
  380.   }
  381.  
  382.   /*  Do they want to see what's going on?  */
  383.   if(interactive) printf("\nPress 'Y' to display list of filenames, or any other key to continue:");
  384.   if(interactive) {
  385.     while(!kbhit());
  386.     ch=getch();
  387.     printf("\n");
  388.     if(ch=='Y' || ch=='y')
  389.     {
  390.       entry = first;
  391.       while(entry->data->central_sig==0x02014b50)
  392.       {
  393.         printf("Compressed size: %10.10lu, CRC: %8.8lx  Name: ", entry->data->csize, entry->data->crc);
  394.         /*  *entry->data->fname is *NON*-zero terminated, so this displays it.  */
  395.         for(i=0; (i<entry->data->fnlen); i++) printf("%c",entry->data->fname[i]);
  396.         printf("\n");
  397.         entry++;
  398.       }
  399.     }
  400.   }
  401.   local_files=1;
  402.   if(!gave_limit)
  403.       printf("Enter disk in drive %c:, and press ANY KEY when ready: ",toupper(argv[2][0]));
  404.   else
  405.       if(interactive) printf("Hit ANY KEY to begin: ");
  406.   if(interactive) {
  407.     while(!kbhit);
  408.     getch();
  409.   }
  410.   printf("\n");
  411.   while(local_files!=0 && total_files != cur_rec)
  412.   {
  413.     /*  Point to the beginning of the data  */
  414.     entry = first;
  415.     local_files=0;
  416.     sprintf(fname,"%s%s%2.2d.ZIP",argv[2],zipbase,zipnum++);
  417.     w_handle=open(fname, O_CREAT | O_WRONLY | O_BINARY, S_IWRITE | S_IREAD);
  418.  
  419.     if(w_handle==-1) {
  420.        printf("Unable to open %s for output.\n",fname);
  421.        perror("error");
  422.        return(1);
  423.     }
  424.  
  425.     rw_handle=open("C_DIR.CDR", O_CREAT | O_RDWR | O_BINARY, S_IWRITE | S_IREAD);
  426.     if(rw_handle==-1) {
  427.        printf("Unable to open output C_DIR.CDR (central directory data file).\n");
  428.        perror("error");
  429.        return(2);
  430.     }
  431.  
  432.     if(!gave_limit) {
  433.         /*  What's the free space on the drive?  */
  434.         getdfree(toupper(argv[2][0])-64, &dt);
  435.  
  436.         if(dt.df_sclus==65535) {
  437.            printf("Error reading drive information for drive %c.\n",argv[2][0]);
  438.            return(1);
  439.         }
  440.     }
  441.  
  442.     /*  Limit is how much space we have to put the .ZIP in */
  443.     if(!gave_limit) {
  444.         limit = (unsigned long) dt.df_avail*dt.df_sclus*dt.df_bsec;
  445.         limit -= 1024;  /*  Fudge factor (max floppy clustersize)  */
  446.         real_limit = limit;
  447.     } else
  448.         limit = real_limit;
  449.  
  450.     /*
  451.      *  This is the main loop.  Herein we gauge how much space is available,
  452.      *  and determine the files that will be moved.  The compressed code is
  453.      *  moved entirely as is, requiring no decompression.  I use 8K chunks
  454.      *  to move it, since that's about the fastest.  (Anything smaller takes
  455.      *  longer, anything larger tends to over-shoot.)
  456.      */
  457.     while(((unsigned int) entry->data->central_sig)==0x4b50)
  458.     {
  459.       /*
  460.        *  Ick.  Not pretty, eh?  It initializes the bmove variable to be
  461.        *  the size of the current entry's compressed size, plus twice the
  462.        *  filename length, plus twice the extended info length, plus
  463.        *  the comment length, plus 76 (header information).  The two pieces
  464.        *  of data (extra field and filename) are doubled because they have
  465.        *  to be stored in the .ZIP file later.  The number 76 includes the
  466.        *  header that will be written at the end.
  467.        */
  468.       bmove = entry->data->csize + entry->data->fnlen*2 + entry->data->eflen*2 + entry->data->comlen + 76;
  469.  
  470.       if((unsigned long) bmove > (unsigned long) real_limit && entry->data->central_sig==0x02014b50) {
  471.          printf("Skipping file ");
  472.  
  473.          /*  There *HAS* to be a way to print a non-zero-terminated string */
  474.      for(i=0; i<entry->data->fnlen; i++) printf("%c",entry->data->fname[i]);
  475.  
  476.          printf("\n\tbecause it is larger than the maximum size of %ld.\n",real_limit);
  477.  
  478.          if(gave_limit) {
  479.             printf("\a\t(because the limit is not based on disk size,\n");
  480.             printf("\tthe file will be removed from the list.\n");
  481.             entry->data->central_sig=0x4b50L;
  482.             total_files++;
  483.          }
  484.       }
  485.  
  486.       if(bmove <= limit && entry->data->central_sig == 0x02014b50)
  487.       {
  488.         local_files++;
  489.  
  490.         /*  There *HAS* to be a way to print a non-zero-terminated string */
  491.     for(i=0; i<entry->data->fnlen; i++) printf("%c",entry->data->fname[i]);
  492.  
  493.         /*  Seek to the beginning of this file  */
  494.         lseek(r_handle, entry->data->local_offset, SEEK_SET);
  495.  
  496.         /* Adjust bytes to move appropriately.  */
  497.         bmove -= (entry->data->fnlen + entry->data->eflen + entry->data->comlen + 46);
  498.         nzsize = lseek(w_handle,0L,SEEK_CUR);
  499.         count = BLOCKSIZE;
  500.         pulse = 0;
  501.     while (count==BLOCKSIZE)
  502.         {
  503.       printf("%c\b",block[pulse++]);
  504.           pulse %= 4;
  505.       count = read(r_handle, buffer, BLOCKSIZE);
  506.  
  507.           /*  Yupyup.  Another piece of weird code.  Effectively, if we read
  508.            *  more code than we needed to, then adjust the count.  Since we
  509.            *  seek each compressed file, it's no problem to overread a bit.
  510.            */
  511.           if((count+moved) > bmove) count=bmove-moved;
  512.           moved+=count;
  513.       rval = write(w_handle,buffer,count);
  514.           if(rval!=count) {
  515.              printf(" \nwrite error: probably out of disk space\n\tThis .ZIP is now corrupted (%s)\n",fname);
  516.              if(gave_limit) printf("The output ZIPs were too large for the one drive.\n");
  517.              printf("unrecoverable error\a\a\n");
  518.              entry=first;
  519.              for(j=0; j<cur_rec; j++) {
  520.                free(entry->data);
  521.               entry++;
  522.              }
  523.              free(first);
  524.              free(buffer);
  525.              free(swap);
  526.              return(1);
  527.            }
  528.         }
  529.         printf(" \n");
  530.         moved = 0L;
  531.         entry->data->local_offset = nzsize;
  532.         write(rw_handle, entry->data, 46L);
  533.         write(rw_handle, entry->data->fname, entry->data->fnlen);
  534.         write(rw_handle, entry->data->efield, entry->data->eflen);
  535.         write(rw_handle, entry->data->comment, entry->data->comlen);
  536.         entry->data->central_sig=0x4b50;
  537.  
  538.         /*  Re-adjust bmove, so that the 'limit' will be correct,
  539.          *  in terms of the final size including the header data
  540.          *  that has to go along w/ each file.
  541.          */
  542.         bmove += (entry->data->fnlen + entry->data->eflen + entry->data->comlen + 46);
  543.         limit -= bmove;
  544.       }
  545.       entry++;
  546.     }
  547.     /*  Keep ourselves a count of the files that have been copied.  */
  548.     total_files += local_files;
  549.  
  550.     /*  What's our current location in the file.  */
  551.     nzsize = lseek(w_handle,0L,SEEK_CUR);
  552.  
  553.     /*  Now we write out a directory at the end of the .ZIP file.  */
  554.     lseek(rw_handle, 0L, SEEK_SET);
  555.     count = BLOCKSIZE;
  556.     while(count==BLOCKSIZE)
  557.     {
  558.       count = read(rw_handle, buffer, BLOCKSIZE);
  559.       write(w_handle, buffer, count);
  560.     }
  561.     /*  nzsize_2 is the location at which the central directory pointer is.
  562.      *  That's how it's written in the appnote.txt.  Then we build the final
  563.      *  'central directory entry', which closes off the .ZIP file.
  564.      */
  565.     nzsize_2 = filelength(rw_handle);
  566.     close(rw_handle);
  567.     unlink("C_DIR.CDR");
  568.     LONG[0] = 0x06054b50;   /*  Magic Marker  */
  569.     WORD[4] = 0;
  570.     WORD[6] = 0;
  571.     WORD[8] = local_files;  /*  Number of files in this .ZIP  */
  572.     WORD[10]= local_files;
  573.     LONG[12]=nzsize_2;
  574.     LONG[16]=nzsize;
  575.     WORD[20]=0;
  576.     write(w_handle, buffer, 22);
  577.     close(w_handle);
  578.     if(total_files!=cur_rec)
  579.     {
  580.         if(!gave_limit)
  581.         printf("\aEnter disk in drive %c:, and press ANY KEY when ready: ",toupper(argv[2][0]));
  582.         else
  583.             if(interactive) printf("\aPress ANY KEY to make next file: ");
  584.         if(interactive) {
  585.           while(!kbhit);
  586.           getch();
  587.         }
  588.         printf("\n");
  589.     }
  590.   }
  591.   close(r_handle);
  592.   printf("Filling of these .ZIP files done successfully.\n\a");
  593.   entry=first;
  594.   for(j=0; j<cur_rec; j++) {
  595.      free(entry->data);
  596.      entry++;
  597.   }
  598.   free(first);
  599.   free(buffer);
  600.   free(swap);
  601.   return(0);
  602. }
  603.