home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip21.zip / zipsplit.c < prev    next >
C/C++ Source or Header  |  1996-04-14  |  22KB  |  804 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1996 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel, Onno van der Linden and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included,
  7.  that it is not sold for profit, and that this copyright notice is retained.
  8.  
  9. */
  10.  
  11. /*
  12.  *  zipsplit.c by Mark Adler.
  13.  */
  14.  
  15. #define UTIL
  16. #include "zip.h"
  17. #include "revision.h"
  18. #include <signal.h>
  19.  
  20. #define DEFSIZ 36000L   /* Default split size (change in help() too) */
  21. #if defined(MSDOS) || defined(__human68k__)
  22. #  define NL 2          /* Number of bytes written for a \n */
  23. #else /* !MSDOS */
  24. #  define NL 1          /* Number of bytes written for a \n */
  25. #endif /* ?MSDOS */
  26. #ifdef RISCOS
  27. #  define INDEX "zipspl/idx"      /* Name of index file */
  28. #  define TEMPL_FMT "%%0%dld"
  29. #  define TEMPL_SIZ 13
  30. #else
  31. #  define INDEX "zipsplit.idx"    /* Name of index file */
  32. #  define TEMPL_FMT "%%0%dld.zip"
  33. #  define TEMPL_SIZ 17
  34. #endif
  35.  
  36. /* Local functions */
  37. local zvoid *talloc OF((extent));
  38. local void tfree OF((zvoid *));
  39. local void tfreeall OF((void));
  40. local void handler OF((int));
  41. local void license OF((void));
  42. local void help OF((void));
  43. local void version_info OF((void));
  44. local extent simple OF((ulg *, extent, ulg, ulg));
  45. local int descmp OF((const zvoid *, const zvoid *));
  46. local extent greedy OF((ulg *, extent, ulg, ulg));
  47. local int retry OF((void));
  48. int main OF((int, char **));
  49.  
  50.  
  51. /* Output zip files */
  52. local char template[TEMPL_SIZ]; /* name template for output files */
  53. local int zipsmade = 0;         /* number of zip files made */
  54. local int indexmade = 0;        /* true if index file made */
  55. local char *path = NULL;        /* space for full name */
  56. local char *name;               /* where name goes in path[] */
  57.  
  58.  
  59. /* The talloc() and tree() routines extend malloc() and free() to keep
  60.    track of all allocated memory.  Then the tfreeall() routine uses this
  61.    information to free all allocated memory before exiting. */
  62.  
  63. #define TMAX 6          /* set intelligently by examining the code */
  64. zvoid *talls[TMAX];     /* malloc'ed pointers to track */
  65. int talln = 0;          /* number of entries in talls[] */
  66.  
  67.  
  68. local zvoid *talloc(s)
  69. extent s;
  70. /* does a malloc() and saves the pointer to free later (does not check
  71.    for an overflow of the talls[] list) */
  72. {
  73.   zvoid *p;
  74.  
  75.   if ((p = (zvoid *)malloc(s)) != NULL)
  76.     talls[talln++] = p;
  77.   return p;
  78. }
  79.  
  80.  
  81. local void tfree(p)
  82. zvoid *p;
  83. /* does a free() and also removes the pointer from the talloc() list */
  84. {
  85.   int i;
  86.  
  87.   free(p);
  88.   i = talln;
  89.   while (i--)
  90.     if (talls[i] == p)
  91.       break;
  92.   if (i >= 0)
  93.   {
  94.     while (++i < talln)
  95.       talls[i - 1] = talls[i];
  96.     talln--;
  97.   }
  98. }
  99.  
  100.  
  101. local void tfreeall()
  102. /* free everything talloc'ed and not tfree'd */
  103. {
  104.   while (talln)
  105.     free(talls[--talln]);
  106. }
  107.  
  108.  
  109. void ziperr(c, h)
  110. int c;                  /* error code from the ZE_ class */
  111. char *h;                /* message about how it happened */
  112. /* Issue a message for the error, clean up files and memory, and exit. */
  113. {
  114.   if (PERR(c))
  115.     perror("zipsplit error");
  116.   fprintf(stderr, "zipsplit error: %s (%s)\n", errors[c-1], h);
  117.   if (indexmade)
  118.   {
  119.     strcpy(name, INDEX);
  120.     destroy(path);
  121.   }
  122.   for (; zipsmade; zipsmade--)
  123.   {
  124.     sprintf(name, template, zipsmade);
  125.     destroy(path);
  126.   }
  127.   tfreeall();
  128.   if (zipfile != NULL)
  129.     free((zvoid *)zipfile);
  130.   EXIT(c);
  131. }
  132.  
  133.  
  134. local void handler(s)
  135. int s;                  /* signal number (ignored) */
  136. /* Upon getting a user interrupt, abort cleanly using ziperr(). */
  137. {
  138. #ifndef MSDOS
  139.   putc('\n', stderr);
  140. #endif /* !MSDOS */
  141.   ziperr(ZE_ABORT, "aborting");
  142.   s++;                                  /* keep some compilers happy */
  143. }
  144.  
  145.  
  146. void zipwarn(a, b)
  147. char *a, *b;            /* message strings juxtaposed in output */
  148. /* Print a warning message to stderr and return. */
  149. {
  150.   fprintf(stderr, "zipsplit warning: %s%s\n", a, b);
  151. }
  152.  
  153.  
  154. local void license()
  155. /* Print license information to stdout. */
  156. {
  157.   extent i;             /* counter for copyright array */
  158.  
  159.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
  160.     printf(copyright[i], "zipsplit");
  161.     putchar('\n');
  162.   }
  163.   for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
  164.     puts(disclaimer[i]);
  165. }
  166.  
  167.  
  168. local void help()
  169. /* Print help (along with license info) to stdout. */
  170. {
  171.   extent i;             /* counter for help array */
  172.  
  173.   /* help array */
  174.   static const char *text[] = {
  175. "",
  176. "ZipSplit %s (%s)",
  177. "Usage:  zipsplit [-tips] [-n size] [-r room] [-b path] zipfile",
  178. "  -t   report how many files it will take, but don't make them",
  179. #ifdef RISCOS
  180. "  -i   make index (" INDEX ") and count its size against first zip file",
  181. #else
  182. "  -i   make index (zipsplit.idx) and count its size against first zip file",
  183. #endif
  184. "  -n   make zip files no larger than \"size\" (default = 36000)",
  185. "  -r   leave room for \"room\" bytes on the first disk (default = 0)",
  186. "  -b   use \"path\" for the output zip files",
  187. "  -p   pause between output zip files",
  188. "  -s   do a sequential split even if it takes more zip files",
  189. "  -h   show this help    -v   show version info    -L   show software license"
  190.   };
  191.  
  192.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
  193.     printf(copyright[i], "zipsplit");
  194.     putchar('\n');
  195.   }
  196.   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
  197.   {
  198.     printf(text[i], VERSION, REVDATE);
  199.     putchar('\n');
  200.   }
  201. }
  202.  
  203.  
  204. local void version_info()
  205. /* Print verbose info about program version and compile time options
  206.    to stdout. */
  207. {
  208.   extent i;             /* counter in text arrays */
  209.  
  210.   static const char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n";
  211.  
  212.   /* Options info array */
  213.   static const char *comp_opts[] = {
  214. #ifdef DEBUG
  215.     "DEBUG",
  216. #endif
  217.     NULL
  218.   };
  219.  
  220.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  221.   {
  222.     printf(copyright[i], "zip");
  223.     putchar('\n');
  224.   }
  225.  
  226.   for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
  227.   {
  228.     printf(versinfolines[i], "ZipSplit", VERSION, REVDATE);
  229.     putchar('\n');
  230.   }
  231.  
  232.   printf(CompiledWith,
  233.  
  234. #ifdef __GNUC__
  235.       "gcc ", __VERSION__,
  236. #else
  237.       "(OS specific) cc ", "",
  238. #endif
  239.  
  240. #ifdef RISCOS
  241.       "RISC OS (Acorn Computers Ltd)",
  242. #else
  243. #ifdef AMIGA
  244.       "AmigaDOS"
  245. #else
  246. #ifdef ATARI
  247. #  ifdef __MINT__
  248.       "Atari TOS/MiNT",
  249. #  else
  250.       "Atari TOS",
  251. #  endif
  252. #else
  253. #ifdef CMS_MVS
  254. #  ifdef VM_CMS
  255.       "VM/CMS",
  256. #  else
  257.       "MVS",
  258. #  endif
  259. #else
  260. #ifdef __human68k__
  261.       "Human68k (X68000)",
  262. #else
  263. #ifdef DOS
  264.       "MS-DOS",
  265. #else
  266. #ifdef OS2
  267.       "OS/2",
  268. #else
  269. #ifdef TOPS20
  270.       "TOPS-20",
  271. #else
  272. #ifdef UNIX
  273.       "Unix",
  274. #else
  275. #ifdef VMS
  276.       "VMS",
  277. #else
  278. #ifdef WIN32
  279.       "\n\tWindows 95 / Windows NT (32-bit)",
  280. #else
  281.       "[unrecognized OS]",
  282. #endif /* WIN32 */
  283. #endif /* VMS */
  284. #endif /* UNIX */
  285. #endif /* TOPS20 */
  286. #endif /* OS2 */
  287. #endif /* DOS */
  288. #endif /* __human68k__ */
  289. #endif /* CMS_MVS */
  290. #endif /* ATARI */
  291. #endif /* AMIGA */
  292. #endif /* RISCOS */
  293.  
  294. #ifdef __DATE__
  295.       " on ", __DATE__
  296. #else
  297.       "", ""
  298. #endif
  299.     );
  300.  
  301.   puts("ZipSplit special compilation options:");
  302.   for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
  303.   {
  304.     printf("\t%s\n",comp_opts[i]);
  305.   }
  306.   if (i == 0)
  307.       puts("\t[none]");
  308. }
  309.  
  310.  
  311. local extent simple(a, n, c, d)
  312. ulg *a;         /* items to put in bins, return value: destination bins */
  313. extent n;       /* number of items */
  314. ulg c;          /* capacity of each bin */
  315. ulg d;          /* amount to deduct from first bin */
  316. /* Return the number of bins of capacity c that are needed to contain the
  317.    integers in a[0..n-1] placed sequentially into the bins.  The value d
  318.    is deducted initially from the first bin (space for index).  The entries
  319.    in a[] are replaced by the destination bins. */
  320. {
  321.   extent k;     /* current bin number */
  322.   ulg t;        /* space used in current bin */
  323.  
  324.   t = k = 0;
  325.   while (n--)
  326.   {
  327.     if (*a + t > c - (k == 0 ? d : 0))
  328.     {
  329.       k++;
  330.       t = 0;
  331.     }
  332.     t += *a;
  333.     *(ulg huge *)a++ = k;
  334.   }
  335.   return k + 1;
  336. }
  337.  
  338.  
  339. local int descmp(a, b)
  340. const zvoid *a, *b;           /* pointers to pointers to ulg's to compare */
  341. /* Used by qsort() in greedy() to do a descending sort. */
  342. {
  343.   return **(ulg **)a < **(ulg **)b ? 1 : (**(ulg **)a > **(ulg **)b ? -1 : 0);
  344. }
  345.  
  346.  
  347. local extent greedy(a, n, c, d)
  348. ulg *a;         /* items to put in bins, return value: destination bins */
  349. extent n;       /* number of items */
  350. ulg c;          /* capacity of each bin */
  351. ulg d;          /* amount to deduct from first bin */
  352. /* Return the number of bins of capacity c that are needed to contain the
  353.    items with sizes a[0..n-1] placed non-sequentially into the bins.  The
  354.    value d is deducted initially from the first bin (space for index).
  355.    The entries in a[] are replaced by the destination bins. */
  356. {
  357.   ulg *b;       /* space left in each bin (malloc'ed for each m) */
  358.   ulg *e;       /* copy of argument a[] (malloc'ed) */
  359.   extent i;     /* steps through items */
  360.   extent j;     /* steps through bins */
  361.   extent k;     /* best bin to put current item in */
  362.   extent m;     /* current number of bins */
  363.   ulg **s;      /* pointers to e[], sorted descending (malloc'ed) */
  364.   ulg t;        /* space left in best bin (index k) */
  365.  
  366.   /* Algorithm:
  367.      1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
  368.         descending order.
  369.      2. Compute total of s[] and set m to the smallest number of bins of
  370.         capacity c that can hold the total.
  371.      3. Allocate m bins.
  372.      4. For each item in s[], starting with the largest, put it in the
  373.         bin with the smallest current capacity greater than or equal to the
  374.         item's size.  If no bin has enough room, increment m and go to step 4.
  375.      5. Else, all items ended up in a bin--return m.
  376.   */
  377.  
  378.   /* Copy a[] to e[], put pointers to e[] in s[], and sort s[].  Also compute
  379.      the initial number of bins (minus 1). */
  380.   if ((e = (ulg *)malloc(n * sizeof(ulg))) == NULL ||
  381.       (s = (ulg **)malloc(n * sizeof(ulg *))) == NULL)
  382.   {
  383.     if (e != NULL)
  384.       free((zvoid *)e);
  385.     ziperr(ZE_MEM, "was trying a smart split");
  386.     return 0;                           /* only to make compiler happy */
  387.   }
  388.   memcpy((char *)e, (char *)a, n * sizeof(ulg));
  389.   for (t = i = 0; i < n; i++)
  390.     t += *(s[i] = e + i);
  391.   m = (extent)((t + c - 1) / c) - 1;    /* pre-decrement for loop */
  392.   qsort((char *)s, n, sizeof(ulg *), descmp);
  393.  
  394.   /* Stuff bins until successful */
  395.   do {
  396.     /* Increment the number of bins, allocate and initialize bins */
  397.     if ((b = (ulg *)malloc(++m * sizeof(ulg))) == NULL)
  398.     {
  399.       free((zvoid *)s);
  400.       free((zvoid *)e);
  401.       ziperr(ZE_MEM, "was trying a smart split");
  402.     }
  403.     b[0] = c - d;                       /* leave space in first bin */
  404.     for (j = 1; j < m; j++)
  405.       b[j] = c;
  406.  
  407.     /* Fill the bins greedily */
  408.     for (i = 0; i < n; i++)
  409.     {
  410.       /* Find smallest bin that will hold item i (size s[i]) */
  411.       t = c + 1;
  412.       for (k = j = 0; j < m; j++)
  413.         if (*s[i] <= b[j] && b[j] < t)
  414.           t = b[k = j];
  415.  
  416.       /* If no bins big enough for *s[i], try next m */
  417.       if (t == c + 1)
  418.         break;
  419.  
  420.       /* Diminish that bin and save where it goes */
  421.       b[k] -= *s[i];
  422.       a[(int)((ulg huge *)(s[i]) - (ulg huge *)e)] = k;
  423.     }
  424.  
  425.     /* Clean up */
  426.     free((zvoid *)b);
  427.  
  428.     /* Do until all items put in a bin */
  429.   } while (i < n);
  430.  
  431.   /* Done--clean up and return the number of bins needed */
  432.   free((zvoid *)s);
  433.   free((zvoid *)e);
  434.   return m;
  435. }
  436.  
  437.  
  438. local int retry()
  439. {
  440.   char m[10];
  441.   fputs("Error writing to disk--redo entire disk? ", stderr);
  442.   fgets(m, 10, stdin);
  443.   return *m == 'y' || *m == 'Y';
  444. }
  445.  
  446.  
  447. int main(argc, argv)
  448. int argc;               /* number of tokens in command line */
  449. char **argv;            /* command line tokens */
  450. /* Split a zip file into several zip files less than a specified size.  See
  451.    the command help in help() above. */
  452. {
  453.   ulg *a;               /* malloc'ed list of sizes, dest bins */
  454.   extent *b;            /* heads of bin linked lists (malloc'ed) */
  455.   ulg c;                /* bin capacity, start of central directory */
  456.   int d;                /* if true, just report the number of disks */
  457.   FILE *e;              /* input zip file */
  458.   FILE *f;              /* output index and zip files */
  459.   extent g;             /* number of bins from greedy(), entry to write */
  460.   int h;                /* how to split--true means simple split, counter */
  461.   ulg i = 0;            /* size of index file plus room to leave */
  462.   extent j;             /* steps through zip entries, bins */
  463.   int k;                /* next argument type */
  464.   extent *n = NULL;     /* next item in bin list (heads in b) */
  465.   ulg *p;               /* malloc'ed list of sizes, dest bins for greedy() */
  466.   char *q;              /* steps through option characters */
  467.   int r;                /* temporary variable, counter */
  468.   extent s;             /* number of bins needed */
  469.   ulg t;                /* total of sizes, end of central directory */
  470.   int u;                /* flag to wait for user on output files */
  471.   struct zlist far **w; /* malloc'ed table for zfiles linked list */
  472.   int x;                /* if true, make an index file */
  473.   struct zlist far *z;  /* steps through zfiles linked list */
  474. #ifdef AMIGA
  475.   char tailchar;         /* temporary variable used in name generation below */
  476. #endif
  477.  
  478.   /* If no args, show help */
  479.   if (argc == 1)
  480.   {
  481.     help();
  482.     EXIT(0);
  483.   }
  484.  
  485.   init_upper();           /* build case map table */
  486.  
  487.   /* Go through args */
  488.   signal(SIGINT, handler);
  489. #ifdef SIGTERM                 /* Amiga has no SIGTERM */
  490.   signal(SIGTERM, handler);
  491. #endif
  492.   k = h = x = d = u = 0;
  493.   c = DEFSIZ;
  494.   for (r = 1; r < argc; r++)
  495.     if (*argv[r] == '-')
  496.       if (argv[r][1])
  497.         for (q = argv[r]+1; *q; q++)
  498.           switch(*q)
  499.           {
  500.             case 'b':   /* Specify path for output files */
  501.               if (k)
  502.                 ziperr(ZE_PARMS, "options are separate and precede zip file");
  503.               else
  504.                 k = 1;          /* Next non-option is path */
  505.               break;
  506.             case 'h':   /* Show help */
  507.               help();  EXIT(0);
  508.             case 'i':   /* Make an index file */
  509.               x = 1;
  510.               break;
  511.             case 'l': case 'L':  /* Show copyright and disclaimer */
  512.               license();  EXIT(0);
  513.             case 'n':   /* Specify maximum size of resulting zip files */
  514.               if (k)
  515.                 ziperr(ZE_PARMS, "options are separate and precede zip file");
  516.               else
  517.                 k = 2;          /* Next non-option is size */
  518.               break;
  519.             case 'p':
  520.               u = 1;
  521.               break;
  522.             case 'r':
  523.               if (k)
  524.                 ziperr(ZE_PARMS, "options are separate and precede zip file");
  525.               else
  526.                 k = 3;          /* Next non-option is room to leave */
  527.               break;
  528.             case 's':
  529.               h = 1;    /* Only try simple */
  530.               break;
  531.             case 't':   /* Just report number of disks */
  532.               d = 1;
  533.               break;
  534.             case 'v':   /* Show version info */
  535.               version_info();  EXIT(0);
  536.             default:
  537.               ziperr(ZE_PARMS, "Use option -h for help.");
  538.           }
  539.       else
  540.         ziperr(ZE_PARMS, "zip file cannot be stdin");
  541.     else
  542.       if (k == 0)
  543.         if (zipfile == NULL)
  544.         {
  545.           if ((zipfile = ziptyp(argv[r])) == NULL)
  546.             ziperr(ZE_MEM, "was processing arguments");
  547.         }
  548.         else
  549.           ziperr(ZE_PARMS, "can only specify one zip file");
  550.       else if (k == 1)
  551.       {
  552.         tempath = argv[r];
  553.         k = 0;
  554.       }
  555.       else if (k == 2)
  556.       {
  557.         if ((c = (ulg)atol(argv[r])) < 100)     /* 100 is smallest zip file */
  558.           ziperr(ZE_PARMS, "invalid size given. Use option -h for help.");
  559.         k = 0;
  560.       }
  561.       else              /* k must be 3 */
  562.       {
  563.         i = (ulg)atol(argv[r]);
  564.         k = 0;
  565.       }
  566.   if (zipfile == NULL)
  567.     ziperr(ZE_PARMS, "need to specify zip file");
  568.  
  569.  
  570.   /* Read zip file */
  571.   if ((r = readzipfile()) != ZE_OK)
  572.     ziperr(r, zipfile);
  573.   if (zfiles == NULL)
  574.     ziperr(ZE_NAME, zipfile);
  575.  
  576.   /* Make a list of sizes and check against capacity.  Also compute the
  577.      size of the index file. */
  578.   c -= ENDHEAD + 4;                     /* subtract overhead/zipfile */
  579.   if ((a = (ulg *)talloc(zcount * sizeof(ulg))) == NULL ||
  580.       (w = (struct zlist far **)talloc(zcount * sizeof(struct zlist far *))) ==
  581.        NULL)
  582.   {
  583.     ziperr(ZE_MEM, "was computing split");
  584.     return 1;
  585.   }
  586.   t = 0;
  587.   for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
  588.   {
  589.     w[j] = z;
  590.     if (x)
  591.       i += z->nam + 6 + NL;
  592.     t += a[j] = 8 + LOCHEAD + CENHEAD +
  593.            2 * (ulg)z->nam + 2 * (ulg)z->ext + z->com + z->siz;
  594.     if (a[j] > c)
  595.       ziperr(ZE_BIG, z->zname);
  596.   }
  597.  
  598.   /* Decide on split to use, report number of files */
  599.   if (h)
  600.     s = simple(a, zcount, c, i);
  601.   else
  602.   {
  603.     if ((p = (ulg *)talloc(zcount * sizeof(ulg))) == NULL)
  604.       ziperr(ZE_MEM, "was computing split");
  605.     memcpy((char *)p, (char *)a, zcount * sizeof(ulg));
  606.     s = simple(a, zcount, c, i);
  607.     g = greedy(p, zcount, c, i);
  608.     if (s <= g)
  609.       tfree((zvoid *)p);
  610.     else
  611.     {
  612.       tfree((zvoid *)a);
  613.       a = p;
  614.       s = g;
  615.     }
  616.   }
  617.   printf("%ld zip files w%s be made (%ld%% efficiency)\n",
  618.          (ulg)s, d ? "ould" : "ill", ((200 * ((t + c - 1)/c)) / s + 1) >> 1);
  619.   if (d)
  620.   {
  621.     tfreeall();
  622.     free((zvoid *)zipfile);
  623.     zipfile = NULL;
  624.     EXIT(0);
  625.   }
  626.  
  627.   /* Set up path for output files */
  628.   if ((path = (char *)talloc(tempath == NULL ? 13 : strlen(tempath) + 14)) ==
  629.       NULL)
  630.     ziperr(ZE_MEM, "was making output file names");
  631.   if (tempath == NULL)
  632.      name = path;
  633.   else
  634.   {
  635.     strcpy(path, tempath);
  636. #ifdef AMIGA
  637.     tailchar = path[strlen(path) - 1];  /* last character */
  638.     if (path[0] && (tailchar != '/') && (tailchar != ':'))
  639.       strcat(path, "/");
  640.     name = path + strlen(path);
  641. #else
  642. #  ifdef RISCOS
  643.     if (path[0] && path[strlen(path) - 1] != '.')
  644.       strcat(path, ".");
  645.     name = path + strlen(path);
  646. #  else /* !RISCOS */
  647.     if (path[0] && path[strlen(path) - 1] != '/')
  648.       strcat(path, "/");
  649.     name = path + strlen(path);
  650. #  endif
  651. #endif /* ?AMIGA */
  652.   }
  653.  
  654.   /* Make linked lists of results */
  655.   if ((b = (extent *)talloc(s * sizeof(extent))) == NULL ||
  656.       (n = (extent *)talloc(zcount * sizeof(extent))) == NULL)
  657.     ziperr(ZE_MEM, "was computing split");
  658.   for (j = 0; j < s; j++)
  659.     b[j] = (extent)-1;
  660.   j = zcount;
  661.   while (j--)
  662.   {
  663.     g = (extent)a[j];
  664.     n[j] = b[g];
  665.     b[g] = j;
  666.   }
  667.  
  668.   /* Make a name template for the zip files that is eight or less characters
  669.      before the .zip, and that will not overwrite the original zip file. */
  670.   for (k = 1, j = s; j >= 10; j /= 10)
  671.     k++;
  672.   if (k > 7)
  673.     ziperr(ZE_PARMS, "way too many zip files must be made");
  674. #ifdef VMS
  675.   if ((q = strrchr(zipfile, ']')) != NULL)
  676. #else /* !VMS */
  677. #  ifdef AMIGA
  678.   if (((q = strrchr(zipfile, '/')) != NULL)
  679.                        || ((q = strrchr(zipfile, ':'))) != NULL)
  680. #  else /* !AMIGA */
  681. #    ifdef RISCOS
  682.   if ((q = strrchr(zipfile, '.')) != NULL)
  683. #    else /* !RISCOS */
  684.   if ((q = strrchr(zipfile, '/')) != NULL)
  685. #    endif /* ?RISCOS */
  686. #  endif /* ?AMIGA */
  687. #endif /* ?VMS */
  688.     q++;
  689.   else
  690.     q = zipfile;
  691.   r = 0;
  692.   while ((g = *q++) != '\0' && g != '.' && r < 8 - k)
  693.     template[r++] = (char)g;
  694.   if (r == 0)
  695.     template[r++] = '_';
  696.   else if (g >= '0' && g <= '9')
  697.     template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
  698.   sprintf(template + r, TEMPL_FMT, k);
  699.  
  700.   /* Make the zip files from the linked lists of entry numbers */
  701.   if ((e = fopen(zipfile, FOPR)) == NULL)
  702.     ziperr(ZE_NAME, zipfile);
  703.   free((zvoid *)zipfile);
  704.   zipfile = NULL;
  705.   for (j = 0; j < s; j++)
  706.   {
  707.     /* jump here on a disk retry */
  708.    redobin:
  709.  
  710.     /* prompt if requested */
  711.     if (u)
  712.     {
  713.       char m[10];
  714.       fprintf(stderr, "Insert disk #%ld of %ld and hit return: ",
  715.               (ulg)j + 1, (ulg)s);
  716.       fgets(m, 10, stdin);
  717.     }
  718.  
  719.     /* write index file on first disk if requested */
  720.     if (j == 0 && x)
  721.     {
  722.       strcpy(name, INDEX);
  723.       printf("creating: %s\n", path);
  724.       indexmade = 1;
  725.       if ((f = fopen(path, "w")) == NULL)
  726.       {
  727.         if (u && retry()) goto redobin;
  728.         ziperr(ZE_CREAT, path);
  729.       }
  730.       for (j = 0; j < zcount; j++)
  731.         fprintf(f, "%5ld %s\n", a[j] + 1, w[j]->zname);
  732.       if ((j = ferror(f)) != 0 || fclose(f))
  733.       {
  734.         if (j)
  735.           fclose(f);
  736.         if (u && retry()) goto redobin;
  737.         ziperr(ZE_WRITE, path);
  738.       }
  739.     }
  740.  
  741.     /* create output zip file j */
  742.     sprintf(name, template, j + 1L);
  743.     printf("creating: %s\n", path);
  744.     zipsmade = j + 1;
  745.     if ((f = fopen(path, FOPW)) == NULL)
  746.     {
  747.       if (u && retry()) goto redobin;
  748.       ziperr(ZE_CREAT, path);
  749.     }
  750.     tempzn = 0;
  751.  
  752.     /* write local headers and copy compressed data */
  753.     for (g = b[j]; g != (extent)-1; g = (extent)n[g])
  754.     {
  755.       if (fseek(e, w[g]->off, SEEK_SET))
  756.         ziperr(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
  757.       if ((r = zipcopy(w[g], e, f)) != ZE_OK)
  758.       {
  759.         if (r == ZE_TEMP)
  760.         {
  761.           if (u && retry()) goto redobin;
  762.           ziperr(ZE_WRITE, path);
  763.         }
  764.         else
  765.           ziperr(r, zipfile);
  766.       }
  767.     }
  768.  
  769.     /* write central headers */
  770.     if ((c = ftell(f)) == (ulg)(-1L))
  771.     {
  772.       if (u && retry()) goto redobin;
  773.       ziperr(ZE_WRITE, path);
  774.     }
  775.     for (g = b[j], k = 0; g != (extent)-1; g = n[g], k++)
  776.       if ((r = putcentral(w[g], f)) != ZE_OK)
  777.       {
  778.         if (u && retry()) goto redobin;
  779.         ziperr(ZE_WRITE, path);
  780.       }
  781.  
  782.     /* write end-of-central header */
  783.     if ((t = ftell(f)) == -1L ||
  784.         (r = putend(k, t - c, c, (extent)0, (char *)NULL, f)) != ZE_OK ||
  785.         ferror(f) || fclose(f))
  786.     {
  787.       if (u && retry()) goto redobin;
  788.       ziperr(ZE_WRITE, path);
  789.     }
  790. #ifdef RISCOS
  791.     /* Set the filetype to &DDC */
  792.     setfiletype(path,0xDDC);
  793. #endif
  794.   }
  795.   fclose(e);
  796.  
  797.   /* Done! */
  798.   if (u)
  799.     fputs("Done.\n", stderr);
  800.   tfreeall();
  801.  
  802.   RETURN(0);
  803. }
  804.