Article View: comp.os.os2
Article #1376(Part 3) compress (fast!) for OS/2
From: Kai-Uwe Rommel
Date: Mon, 12 Mar 1990 04:39
Date: Mon, 12 Mar 1990 04:39
271 lines
10741 bytes
10741 bytes
*** Split Message, part #3, MsgSplit Version 2 (11-Mar-90) ***
X * or stdout (if stdin used as input)
X *
X * Assumptions:
X * When filenames are given, replaces with the compressed version
X * (.Z suffix) only if the file decreases in size.
X * Algorithm:
X * Modified Lempel-Ziv method (LZW). Basically finds common
X * substrings and replaces them with a variable size code. This is
X * deterministic, and can be done on the fly. Thus, the decompression
X * procedure needs no input table, but tracks the way the table was built.
X */
X
X#ifdef __ZTC__
X#include <int.h>
Xint silly_nonsense(struct INT_DATA *foo) {raise(SIGINT); return 1;}
X#endif
X
X#define ARGVAL() (*++(*argv) || (--argc && *++argv))
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
X char tempname[100], *cp;
X
X if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
X signal(SIGINT, onintr);
X#ifdef __ZTC__
X /*
X * The "signal" call above isn't good enough for Zortech
X */
X int_intercept(0x23, silly_nonsense, 256);
X#endif
X#ifdef SIGSEGV
X signal(SIGSEGV, oops);
X#endif
X if (isatty(2))
X foreground = 1;
X }
X
X#ifndef MSDOS
X if ((cp = strrchr(argv[0], '/')) != 0)
X cp++;
X else
X cp = argv[0];
X#else
X for (cp = argv[0]; *cp; cp++)
X if (*cp == '/' || *cp == '\\')
X argv[0] = cp + 1;
X cp = strlwr(argv[0]);
X#endif
X /* Limited to 8 char filenames under DOS */
X if (strncmp(cp, "uncompress", 8) == 0)
X do_decomp = 1;
X else if (strncmp(cp, "zcat", 4) == 0) {
X do_decomp = 1;
X zcat_flg = 1;
X }
X
X#ifdef BSD4_2
X /* 4.2BSD dependent - take it out if not */
X setlinebuf(stderr);
X#endif /* BSD4_2 */
X
X for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
X while (*++(*argv)) { /* Process all flags in this arg */
X switch (**argv) {
X case 'V':
X version();
X break;
X case 'v':
X verbose = 1;
X break;
X case 'd':
X do_decomp = 1;
X break;
X case 'f':
X case 'F':
X force = 1;
X break;
X case 'n':
X magic = 0;
X break;
X case 'C':
X block_compress = 0;
X break;
X case 'b':
X if (!ARGVAL()) {
X fprintf(stderr, "Missing maxbits\n");
X Usage();
X exit(1);
X }
X maxbits = atoi(*argv);
X goto nextarg;
X case 'c':
X zcat_flg = 1;
X break;
X case 'q':
X verbose = 0;
X break;
X case 'k':
X keep = 1;
X break;
X case 'h':
X Usage();
X exit(1);
X default:
X fprintf(stderr, "Unknown flag: '%c'; ", **argv);
X Usage();
X exit(1);
X }
X }
Xnextarg:;
X }
X
X#ifdef i8088
X if (! taballoc()) {
X fprintf(stderr, "compress: out of memory\n");
X exit(1);
X }
X#endif
X /*
X * If no filename args, do standard input.
X */
X if (argc <= 0) {
X if ( isatty(fileno(stdin)) )
X {
X version();
X Usage();
X exit(1);
X }
X
X if (! ifopen((char *)0) || ! ofopen((char *)0))
X exit(1);
X
X ifname = "stdin";
X
X if (do_decomp) {
X if (!check_magic())
X exit(1);
X decompress();
X }
X else {
X compress();
X if (verbose)
X putc('\n', stderr);
X }
X exit(exit_stat);
X }
X
X while (--argc >= 0) {
X char *suf;
X
X ifname = *argv++;
X suf = strrchr(ifname, '.');
X
X exit_stat = 0;
X okunlink = 0;
X
X if (do_decomp) { /* DECOMPRESSION */
X if (!suf || (strcmp(suf, ".Z") && strcmp(suf, ".z"))) {
X strcpy(tempname, ifname);
X#ifdef MSDOS
X if ( suf = strrchr(tempname, '.') )
X if ( suf > strrchr(tempname, '\\') )
X *suf = 0;
X#endif
X strcat(tempname, ".Z");
X ifname = tempname;
X }
X if (! ifopen(ifname) || !check_magic())
X continue;
X if (zcat_flg)
X ofname[0] = '\0';
X else {
X strcpy(ofname, ifname);
X ofname[strlen(ifname) - 2] = '\0';
X }
X if (!ofopen(ofname))
X continue;
X if (!zcat_flg && verbose)
X fprintf(stderr, "%s: ", ifname);
X decompress();
X }
X else { /* COMPRESSION */
X if (suf && (!strcmp(suf, ".Z") || !strcmp(suf, ".z"))) {
X fprintf(stderr, "%s: already has .Z suffix -- no change\n",
X ifname);
X continue;
X }
X if (! ifopen(ifname))
X continue;
X if (zcat_flg)
X ofname[0] = 0;
X else {
X strcpy(ofname, ifname);
X#ifdef MSDOS
X if ( suf = strrchr(ofname, '.') )
X if ( suf > strrchr(ofname, '\\') )
X *suf = 0;
X#endif
X#ifndef MSDOS /* We'll let ofopen do the complaining */
X#ifndef BSD4_2
X if ((cp = strrchr(ofname, '/')) != NULL)
X cp++;
X else
X cp = ofname;
X if (strlen(cp) > 12) {
X fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
X continue;
X }
X#endif
X#endif
X strcat(ofname, ".Z");
X }
X if (! ofopen(ofname))
X continue;
X if (! zcat_flg && verbose)
X fprintf(stderr, "%s: ", ifname);
X compress();
X }
X
X if (! zcat_flg) {
X copystat();
X if ((exit_stat == 1) || verbose)
X putc('\n', stderr);
X }
X }
X exit(exit_stat);
X}
X
X/*
X * compress stdin to stdout
X *
X * Algorithm: use open addressing double hashing (no chaining) on the
X * prefix code / next character combination. We do a variant of Knuth's
X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
X * secondary probe. Here, the modular division first probe is gives way
X * to a faster exclusive-or manipulation. Also do block compression with
X * an adaptive reset, whereby the code table is cleared when the compression
X * ratio decreases, but after the table fills. The variable-length output
X * codes are re-sized at this point, and a special CLEAR code is generated
X * for the decompressor. Late addition: construct the table according to
X * file size for noticeable speed improvement on small files. Please direct
X * questions about this implementation to ames!jaw.
X *
X * Secondary hash function changed slightly for DOS. Hash table used to be
X * > 64K. This is slow on a 16 bit machine because it means long arithmetic,
X * and more complicated addressing of tables in the far address space.
X * We now restrict the table size to 64K, and, so that the table does
X * not overfill, restrict the codes that we will generate to MAXMAXCODE.
X * This causes slightly poorer compression in some cases, but, interestingly
X * enough, also causes better compression ratios in certain other cases.
X * Yes, this is all compatible with other compresses.
X */
Xstatic long in_count; /* length of input */
Xstatic long out_count; /* length of compressed output */
*** Original message split, continued in next message ***
t
--
Kai-Uwe Rommel at The Black Cat's Shack (Fidonet 1:109/401)
Internet: Kai-Uwe.Rommel@p0.f40.n109.z1.fidonet.org
UUCP: ...!uunet!blkcat!40.0!Kai-Uwe.Rommel
Technical Details
Message-ID:
<721.25FAE6FC@blkcat.fidonet.org>Path:
arc1-ca.pugleaf.net!utzoo!attcan!uunet!blkcat!p0.f40.n109.z1.fidonet.org!Kai-Uwe.RommelShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!blkcat!p0.f40.n109.z1.fidonet.org!Kai-Uwe.Rommel From: Kai-Uwe.Rommel@p0.f40.n109.z1.fidonet.org (Kai-Uwe Rommel) Newsgroups: comp.os.os2 Subject: (Part 3) compress (fast!) for OS/2 Message-ID: <721.25FAE6FC@blkcat.fidonet.org> Date: 12 Mar 90 04:39:48 GMT Sender: ufgate@blkcat.fidonet.org (newsout1.26) Organization: FidoNet node 1:109/40.0 - Crewe 400 Nat'l Hub, Joe Keenan Lines: 271