🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.os.os2
Article #1376

(Part 3) compress (fast!) for OS/2

#1376
From: Kai-Uwe Rommel
Date: Mon, 12 Mar 1990 04:39
271 lines
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.Rommel

Show 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