Annotation of coherent/b/bin/zip/zipsplit.c, revision 1.1.1.1

1.1       root        1: /*
                      2: 
                      3:  Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
                      4:  Kai Uwe Rommel 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:  unmodified, that it is not sold for profit, and that this copyright notice
                      8:  is retained.
                      9: 
                     10: */
                     11: 
                     12: /*
                     13:  *  zipsplit.c by Mark Adler.
                     14:  */
                     15: 
                     16: #define UTIL
                     17: #include "revision.h"
                     18: #include "zip.h"
                     19: #include <signal.h>
                     20: 
                     21: #define DEFSIZ 36000L   /* Default split size (change in help() too) */
                     22: #ifdef MSDOS
                     23: #  define NL 2          /* Number of bytes written for a \n */
                     24: #else /* !MSDOS */
                     25: #  define NL 1          /* Number of bytes written for a \n */
                     26: #endif /* ?MSDOS */
                     27: #define INDEX "zipsplit.idx"    /* Name of index file */
                     28: 
                     29: 
                     30: /* Local functions */
                     31: #ifdef PROTO
                     32:    local void handler(int);
                     33:    local void license(void);
                     34:    local void help(void);
                     35:    local extent simple(ulg *, extent, ulg, ulg);
                     36:    local int descmp(voidp *, voidp *);
                     37:    local extent greedy(ulg *, extent, ulg, ulg);
                     38:    void main(int, char **);
                     39: #endif /* PROTO */
                     40: 
                     41: 
                     42: /* Output zip files */
                     43: local char template[16];        /* name template for output files */
                     44: local int zipsmade = 0;         /* number of zip files made */
                     45: local int indexmade = 0;        /* true if index file made */
                     46: local char *path = NULL;        /* space for full name */
                     47: local char *name;               /* where name goes in path[] */
                     48: 
                     49: 
                     50: void err(c, h)
                     51: int c;                  /* error code from the ZE_ class */
                     52: char *h;                /* message about how it happened */
                     53: /* Issue a message for the error, clean up files and memory, and exit. */
                     54: {
                     55:   if (PERR(c))
                     56:     perror("zipsplit error");
                     57:   fprintf(stderr, "zipsplit error: %s (%s)\n", errors[c-1], h);
                     58:   if (indexmade)
                     59:   {
                     60:     strcpy(name, INDEX);
                     61:     destroy(path);
                     62:   }
                     63:   for (; zipsmade; zipsmade--)
                     64:   {
                     65:     sprintf(name, template, zipsmade);
                     66:     destroy(path);
                     67:   }
                     68:   if (path != NULL)
                     69:     free((voidp *)path);
                     70:   if (zipfile != NULL)
                     71:     free((voidp *)zipfile);
                     72: #ifdef VMS
                     73:   exit(0);
                     74: #else /* !VMS */
                     75:   exit(c);
                     76: #endif /* ?VMS */
                     77: }
                     78: 
                     79: 
                     80: 
                     81: local void handler(s)
                     82: int s;                  /* signal number (ignored) */
                     83: /* Upon getting a user interrupt, abort cleanly using err(). */
                     84: {
                     85: #ifndef MSDOS
                     86:   putc('\n', stderr);
                     87: #endif /* !MSDOS */
                     88:   err(ZE_ABORT, "aborting");
                     89:   s++;                                  /* keep some compilers happy */
                     90: }
                     91: 
                     92: 
                     93: void warn(a, b)
                     94: char *a, *b;            /* message strings juxtaposed in output */
                     95: /* Print a warning message to stderr and return. */
                     96: {
                     97:   fprintf(stderr, "zipsplit warning: %s%s\n", a, b);
                     98: }
                     99: 
                    100: 
                    101: local void license()
                    102: /* Print license information to stdout. */
                    103: {
                    104:   extent i;             /* counter for copyright array */
                    105: 
                    106:   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
                    107:     printf(copyright[i], "zipsplit");
                    108:     putchar('\n');
                    109:   }
                    110:   for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
                    111:     puts(disclaimer[i]);
                    112: }
                    113: 
                    114: 
                    115: local void help()
                    116: /* Print help (along with license info) to stdout. */
                    117: {
                    118:   extent i;             /* counter for help array */
                    119: 
                    120:   /* help array */
                    121:   static char *text[] = {
                    122: "",
                    123: "ZipSplit %d.%d (%s)",
                    124: "Usage:  zipsplit [-ti] [-n size] [-b path] zipfile",
                    125: "  -t   report how many files it will take, but don't make them",
                    126: "  -i   make index (zipsplit.idx) and count its size against first zip file",
                    127: "  -n   make zip files no larger than \"size\" (default = 36000)",
                    128: "  -b   use \"path\" for the output zip files",
                    129: "  -s   do a sequential split even if it takes more zip files",
                    130: "  -h   show this help               -L   show software license"
                    131:   };
                    132: 
                    133:   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
                    134:     printf(copyright[i], "zipsplit");
                    135:     putchar('\n');
                    136:   }
                    137:   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
                    138:   {
                    139:     printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
                    140:     putchar('\n');
                    141:   }
                    142: }
                    143: 
                    144: 
                    145: local extent simple(a, n, c, d)
                    146: ulg *a;         /* items to put in bins, return value: destination bins */
                    147: extent n;       /* number of items */
                    148: ulg c;          /* capacity of each bin */
                    149: ulg d;          /* amount to deduct from first bin */
                    150: /* Return the number of bins of capacity c that are needed to contain the
                    151:    integers in a[0..n-1] placed sequentially into the bins.  The value d
                    152:    is deducted initially from the first bin (space for index).  The entries
                    153:    in a[] are replaced by the destination bins. */
                    154: {
                    155:   extent k;     /* current bin number */
                    156:   ulg t;        /* space used in current bin */
                    157: 
                    158:   t = k = 0;
                    159:   while (n--)
                    160:   {
                    161:     if (*a + t > c - (k == 0 ? d : 0))
                    162:     {
                    163:       k++;
                    164:       t = 0;
                    165:     }
                    166:     t += *a;
                    167:     *(ulg huge *)a++ = k;
                    168:   }
                    169:   return k + 1;
                    170: }
                    171: 
                    172: 
                    173: local int descmp(a, b)
                    174: voidp *a, *b;           /* pointers to pointers to ulg's to compare */
                    175: /* Used by qsort() in greedy() to do a descending sort. */
                    176: {
                    177:   return **(ulg **)a < **(ulg **)b ? 1 : (**(ulg **)a > **(ulg **)b ? -1 : 0);
                    178: }
                    179: 
                    180: 
                    181: local extent greedy(a, n, c, d)
                    182: ulg *a;         /* items to put in bins, return value: destination bins */
                    183: extent n;       /* number of items */
                    184: ulg c;          /* capacity of each bin */
                    185: ulg d;          /* amount to deduct from first bin */
                    186: /* Return the number of bins of capacity c that are needed to contain the
                    187:    items with sizes a[0..n-1] placed non-sequentially into the bins.  The
                    188:    value d is deducted initially from the first bin (space for index).
                    189:    The entries in a[] are replaced by the destination bins. */
                    190: {
                    191:   ulg *b;       /* space left in each bin (malloc'ed for each m) */
                    192:   ulg *e;       /* copy of argument a[] (malloc'ed) */
                    193:   extent i;     /* steps through items */
                    194:   extent j;     /* steps through bins */
                    195:   extent k;     /* best bin to put current item in */
                    196:   extent m;     /* current number of bins */
                    197:   ulg **s;      /* pointers to e[], sorted descending (malloc'ed) */
                    198:   ulg t;        /* space left in best bin (index k) */
                    199: 
                    200:   /* Algorithm:
                    201:      1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
                    202:         descending order.
                    203:      2. Compute total of s[] and set m to the smallest number of bins of
                    204:         capacity c that can hold the total.
                    205:      3. Allocate m bins.
                    206:      4. For each item in s[], starting with the largest, put it in the
                    207:         bin with the smallest current capacity greater than or equal to the
                    208:         item's size.  If no bin has enough room, increment m and go to step 4.
                    209:      5. Else, all items ended up in a bin--return m.
                    210:   */
                    211: 
                    212:   /* Copy a[] to e[], put pointers to e[] in s[], and sort s[].  Also compute
                    213:      the initial number of bins (minus 1). */
                    214:   if ((e = (ulg *)malloc(n * sizeof(ulg))) == NULL ||
                    215:       (s = (ulg **)malloc(n * sizeof(ulg *))) == NULL)
                    216:   {
                    217:     if (e != NULL)
                    218:       free((voidp *)e);
                    219:     err(ZE_MEM, "was trying a smart split");
                    220:     return 0;                           /* only to make compiler happy */
                    221:   }
                    222:   memcpy((char *)e, (char *)a, n * sizeof(ulg));
                    223:   for (t = i = 0; i < n; i++)
                    224:     t += *(s[i] = e + i);
                    225:   m = (extent)((t + c - 1) / c) - 1;    /* pre-decrement for loop */
                    226:   qsort((char *)s, n, sizeof(ulg *), descmp);
                    227: 
                    228:   /* Stuff bins until successful */
                    229:   do {
                    230:     /* Increment the number of bins, allocate and initialize bins */
                    231:     if ((b = (ulg *)malloc(++m * sizeof(ulg))) == NULL)
                    232:     {
                    233:       free((voidp *)s);
                    234:       free((voidp *)e);
                    235:       err(ZE_MEM, "was trying a smart split");
                    236:     }
                    237:     b[0] = c - d;                       /* leave space in first bin */
                    238:     for (j = 1; j < m; j++)
                    239:       b[j] = c;
                    240: 
                    241:     /* Fill the bins greedily */
                    242:     for (i = 0; i < n; i++)
                    243:     {
                    244:       /* Find smallest bin that will hold item i (size s[i]) */
                    245:       t = c + 1;
                    246:       for (k = j = 0; j < m; j++)
                    247:         if (*s[i] <= b[j] && b[j] < t)
                    248:           t = b[k = j];
                    249: 
                    250:       /* If no bins big enough for *s[i], try next m */
                    251:       if (t == c + 1)
                    252:         break;
                    253: 
                    254:       /* Diminish that bin and save where it goes */
                    255:       b[k] -= *s[i];
                    256:       a[(int)((ulg huge *)(s[i]) - (ulg huge *)e)] = k;
                    257:     }
                    258: 
                    259:     /* Clean up */
                    260:     free((voidp *)b);
                    261: 
                    262:     /* Do until all items put in a bin */
                    263:   } while (i < n);
                    264: 
                    265:   /* Done--clean up and return the number of bins needed */
                    266:   free((voidp *)s);
                    267:   free((voidp *)e);
                    268:   return m;
                    269: }
                    270: 
                    271: 
                    272: void main(argc, argv)
                    273: int argc;               /* number of tokens in command line */
                    274: char **argv;            /* command line tokens */
                    275: /* Split a zip file into several zip files less than a specified size.  See
                    276:    the command help in help() above. */
                    277: {
                    278:   ulg *a;               /* malloc'ed list of sizes, dest bins */
                    279:   extent *b;            /* heads of bin linked lists (malloc'ed) */
                    280:   ulg c;                /* bin capacity, start of central directory */
                    281:   int d;                /* if true, just report the number of disks */
                    282:   FILE *e;              /* input zip file */
                    283:   FILE *f;              /* output index and zip files */
                    284:   extent g;             /* number of bins from greedy(), entry to write */
                    285:   int h;                /* how to split--true means simple split, counter */
                    286:   ulg i;                /* size of index file or zero if none */
                    287:   extent j;             /* steps through zip entries, bins */
                    288:   int k;                /* next argument type */
                    289:   ulg *p;               /* malloc'ed list of sizes, dest bins for greedy() */
                    290:   char *q;              /* steps through option characters */
                    291:   int r;                /* temporary variable, counter */
                    292:   extent s;             /* number of bins needed */
                    293:   ulg t;                /* total of sizes, end of central directory */
                    294:   struct zlist far **w; /* malloc'ed table for zfiles linked list */
                    295:   int x;                /* if true, make an index file */
                    296:   struct zlist far *z;  /* steps through zfiles linked list */
                    297: 
                    298: 
                    299:   /* If no args, show help */
                    300:   if (argc == 1)
                    301:   {
                    302:     help();
                    303:     exit(0);
                    304:   }
                    305: 
                    306:   init_upper();           /* build case map table */
                    307: 
                    308:   /* Go through args */
                    309:   signal(SIGINT, handler);
                    310:   signal(SIGTERM, handler);
                    311:   k = h = x = d = 0;
                    312:   c = DEFSIZ;
                    313:   for (r = 1; r < argc; r++)
                    314:     if (*argv[r] == '-')
                    315:       if (argv[r][1])
                    316:         for (q = argv[r]+1; *q; q++)
                    317:           switch(*q)
                    318:           {
                    319:             case 'b':   /* Specify path for output files */
                    320:               if (k)
                    321:                 err(ZE_PARMS, "options are separate and precede zip file");
                    322:               else
                    323:                 k = 1;          /* Next non-option is path */
                    324:               break;
                    325:             case 'h':   /* Show help */
                    326:               help();  exit(0);
                    327:             case 'i':   /* Make an index file */
                    328:               x = 1;
                    329:               break;
                    330:             case 'l': case 'L':  /* Show copyright and disclaimer */
                    331:               license();  exit(0);
                    332:             case 'n':   /* Specify maximum size of resulting zip files */
                    333:               if (k)
                    334:                 err(ZE_PARMS, "options are separate and precede zip file");
                    335:               else
                    336:                 k = 2;          /* Next non-option is size */
                    337:               break;
                    338:             case 's':
                    339:               h = 1;    /* Only try simple */
                    340:               break;
                    341:             case 't':   /* Just report number of disks */
                    342:               d = 1;
                    343:               break;
                    344:             default:
                    345:               err(ZE_PARMS, "unknown option");
                    346:           }
                    347:       else
                    348:         err(ZE_PARMS, "zip file cannot be stdin");
                    349:     else
                    350:       if (k == 0)
                    351:         if (zipfile == NULL)
                    352:         {
                    353:           if ((zipfile = ziptyp(argv[r])) == NULL)
                    354:             err(ZE_MEM, "was processing arguments");
                    355:         }
                    356:         else
                    357:           err(ZE_PARMS, "can only specify one zip file");
                    358:       else if (k == 1)
                    359:       {
                    360:         tempath = argv[r];
                    361:         k = 0;
                    362:       }
                    363:       else              /* k must be 2 */
                    364:       {
                    365:         if ((c = (ulg)atol(argv[r])) < 100)     /* 100 is smallest zip file */
                    366:           err(ZE_PARMS, "invalid size given");
                    367:         k = 0;
                    368:       }
                    369:   if (zipfile == NULL)
                    370:     err(ZE_PARMS, "need to specify zip file");
                    371: 
                    372: 
                    373:   /* Read zip file */
                    374:   if ((r = readzipfile()) != ZE_OK)
                    375:     err(r, zipfile);
                    376:   if (zfiles == NULL)
                    377:     err(ZE_NAME, zipfile);
                    378: 
                    379:   /* Make a list of sizes and check against capacity.  Also compute the
                    380:      size of the index file. */
                    381:   c -= ENDHEAD + 4;                     /* subtract overhead/zipfile */
                    382:   if ((a = (ulg *)malloc(zcount * sizeof(ulg))) == NULL ||
                    383:       (w = (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) ==
                    384:        NULL)
                    385:   {
                    386:     if (a != NULL)
                    387:       free((voidp *)a);
                    388:     err(ZE_MEM, "was computing split");
                    389:     return;
                    390:   }
                    391:   i = t = 0;
                    392:   for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
                    393:   {
                    394:     w[j] = z;
                    395:     if (x)
                    396:       i += z->nam + 6 + NL;
                    397:     t += a[j] = 8 + LOCHEAD + CENHEAD +
                    398:            2 * (ulg)z->nam + 2 * (ulg)z->ext + z->com + z->siz;
                    399:     if (a[j] > c)
                    400:     {
                    401:       free((voidp *)w);  free((voidp *)a);
                    402:       err(ZE_BIG, z->zname);
                    403:     }
                    404:   }
                    405: 
                    406:   /* Decide on split to use, report number of files */
                    407:   if (h)
                    408:     s = simple(a, zcount, c, i);
                    409:   else
                    410:   {
                    411:     if ((p = (ulg *)malloc(zcount * sizeof(ulg))) == NULL)
                    412:     {
                    413:       free((voidp *)w);  free((voidp *)a);
                    414:       err(ZE_MEM, "was computing split");
                    415:     }
                    416:     memcpy((char *)p, (char *)a, zcount * sizeof(ulg));
                    417:     s = simple(a, zcount, c, i);
                    418:     g = greedy(p, zcount, c, i);
                    419:     if (s <= g)
                    420:       free((voidp *)p);
                    421:     else
                    422:     {
                    423:       free((voidp *)a);
                    424:       a = p;
                    425:       s = g;
                    426:     }
                    427:   }
                    428:   printf("%d zip files w%s be made (%d%% efficiency)\n",
                    429:          s, d ? "ould" : "ill", ((200 * ((t + c - 1)/c)) / s + 1) >> 1);
                    430:   if (d)
                    431:   {
                    432:     free((voidp *)w);  free((voidp *)a);
                    433:     free((voidp *)zipfile);
                    434:     zipfile = NULL;
                    435:     return;
                    436:   }
                    437: 
                    438:   /* Set up path for output files */
                    439:   if ((path = malloc(tempath == NULL ? 13 : strlen(tempath) + 14)) == NULL)
                    440:     err(ZE_MEM, "was making output file names");
                    441:   if (tempath == NULL)
                    442:      name = path;
                    443:   else
                    444:   {
                    445:     strcpy(path, tempath);
                    446:     if (path[0] && path[strlen(path) - 1] != '/')
                    447:       strcat(path, "/");
                    448:     name = path + strlen(path);
                    449:   }
                    450: 
                    451:   /* Write the index file */
                    452:   if (x)
                    453:   {
                    454:     strcpy(name, INDEX);
                    455:     printf("creating %s\n", path);
                    456:     indexmade = 1;
                    457:     if ((f = fopen(path, "w")) == NULL)
                    458:     {
                    459:       free((voidp *)w);  free((voidp *)a);
                    460:       err(ZE_CREAT, path);
                    461:     }
                    462:     for (j = 0; j < zcount; j++)
                    463:       fprintf(f, "%5ld %s\n", a[j] + 1, w[j]->zname);
                    464:     if ((j = ferror(f)) != 0 || fclose(f))
                    465:     {
                    466:       if (j)
                    467:         fclose(f);
                    468:       free((voidp *)w);  free((voidp *)a);
                    469:       err(ZE_WRITE, path);
                    470:     }
                    471:   }
                    472: 
                    473:   /* Make linked lists of results */
                    474:   if ((b = (extent *)malloc(s * sizeof(extent))) == NULL)
                    475:   {
                    476:     free((voidp *)w);  free((voidp *)a);
                    477:     err(ZE_MEM, "was computing split");
                    478:   }
                    479:   for (j = 0; j < s; j++)
                    480:     b[j] = (extent)-1;
                    481:   j = zcount;
                    482:   while (j--)
                    483:   {
                    484:     g = (extent)a[j];
                    485:     a[j] = b[g];
                    486:     b[g] = j;
                    487:   }
                    488: 
                    489:   /* Make a name template for the zip files that is eight or less characters
                    490:      before the .zip, and that will not overwrite the original zip file. */
                    491:   for (k = 1, j = s; j >= 10; j /= 10)
                    492:     k++;
                    493:   if (k > 7)
                    494:   {
                    495:     free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    496:     err(ZE_PARMS, "way too many zip files must be made");
                    497:   }
                    498: #ifdef VMS
                    499:   if ((q = strrchr(zipfile, ']')) != NULL)
                    500: #else /* !VMS */
                    501:   if ((q = strrchr(zipfile, '/')) != NULL)
                    502: #endif /* ?VMS */
                    503:     q++;
                    504:   else
                    505:     q = zipfile;
                    506:   r = 0;
                    507:   while ((g = *q++) != 0 && g != '.' && r < 8 - k)
                    508:     template[r++] = (char)g;
                    509:   if (r == 0)
                    510:     template[r++] = '_';
                    511:   else if (g >= '0' && g <= '9')
                    512:     template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
                    513:   sprintf(template + r, "%%0%dd.zip", k);
                    514: 
                    515:   /* Make the zip files from the linked lists of entry numbers */
                    516:   if ((e = fopen(zipfile, FOPR)) == NULL)
                    517:   {
                    518:     free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    519:     err(ZE_NAME, zipfile);
                    520:   }
                    521:   free((voidp *)zipfile);
                    522:   zipfile = NULL;
                    523:   for (j = 0; j < s; j++)
                    524:   {
                    525:     sprintf(name, template, j + 1);
                    526:     printf("creating %s\n", path);
                    527:     zipsmade = j + 1;
                    528:     if ((f = fopen(path, FOPW)) == NULL)
                    529:     {
                    530:       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    531:       err(ZE_CREAT, path);
                    532:     }
                    533:     tempzn = 0;
                    534:     for (g = b[j]; g != (extent)-1; g = (extent)a[g])
                    535:     {
                    536:       if (fseek(e, w[g]->off, SEEK_SET))
                    537:       {
                    538:         free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    539:         err(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
                    540:       }
                    541:       if ((r = zipcopy(w[g], e, f)) != ZE_OK)
                    542:       {
                    543:         free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    544:         if (r == ZE_TEMP)
                    545:           err(ZE_WRITE, path);
                    546:         else
                    547:           err(r, zipfile);
                    548:       }
                    549:     }
                    550:     if ((c = ftell(f)) == -1L)
                    551:     {
                    552:       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    553:       err(ZE_WRITE, path);
                    554:     }
                    555:     for (g = b[j], k = 0; g != (extent)-1; g = (extent)a[g], k++)
                    556:       if ((r = putcentral(w[g], f)) != ZE_OK)
                    557:       {
                    558:         free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    559:         err(ZE_WRITE, path);
                    560:       }
                    561:     if ((t = ftell(f)) == -1L)
                    562:     {
                    563:       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    564:       err(ZE_WRITE, path);
                    565:     }
                    566:     if ((r = putend(k, t - c, c, (extent)0, (char *)NULL, f)) != ZE_OK)
                    567:     {
                    568:       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    569:       err(ZE_WRITE, path);
                    570:     }
                    571:     if (ferror(f) || fclose(f))
                    572:     {
                    573:       free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    574:       err(ZE_WRITE, path);
                    575:     }
                    576:   }
                    577:   free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
                    578:   fclose(e);
                    579: 
                    580:   /* Done! */
                    581:   exit(0);
                    582: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.