Retire decomp16(1)

Change-Id: I455aac47b3efa4ffa5cc8305c6760f92e1e8642a
This commit is contained in:
David van Moolenbroek 2015-09-20 15:35:48 +00:00
parent c0d9ad695c
commit fd962fdd93
5 changed files with 3 additions and 499 deletions

View File

@ -299,7 +299,7 @@
./usr/bin/cut minix-sys
./usr/bin/datasizes minix-sys obsolete
./usr/bin/dd minix-sys obsolete
./usr/bin/decomp16 minix-sys
./usr/bin/decomp16 minix-sys obsolete
./usr/bin/del_route minix-sys
./usr/bin/deroff minix-sys
./usr/bin/DESCRIBE minix-sys
@ -2373,7 +2373,7 @@
./usr/man/man1/cut.1 minix-sys
./usr/man/man1/date.1 minix-sys
./usr/man/man1/dd.1 minix-sys
./usr/man/man1/decomp16.1 minix-sys
./usr/man/man1/decomp16.1 minix-sys obsolete
./usr/man/man1/deroff.1 minix-sys
./usr/man/man1/df.1 minix-sys
./usr/man/man1/dhrystone.1 minix-sys

View File

@ -6,7 +6,7 @@ SUBDIR= add_route arp at backup \
cawf cdprobe \
cleantmp \
compress crc cron crontab \
decomp16 DESCRIBE devmand devsize dhcpd \
DESCRIBE devmand devsize dhcpd \
dhrystone \
eject \
fix format fsck.mfs \

View File

@ -1,3 +0,0 @@
PROG= decomp16
.include <bsd.prog.mk>

View File

@ -1,55 +0,0 @@
.TH man 1 "14 November 2014" "1.0" "decomp16 man page"
.PD 0
.SH NAME
decomp16 \- decompress 16bit compressed files on a 16bit Intel processor
.SH SYNOPSIS
decomp16 [-#] [in] [out]
.SH OPTIONS
.IP -#
If given a switch -#, where # is a digit from 0 to 4 (example: -2), the
program will run as that copy, reading from stdin and writing to stdout.
This allows decompressing with very limited RAM because only one of the
five passes is in memory at a time.
.IP in
File to decompress
.IP out
File to output decompressed data to
.SH DESCRIPTION
decompresses files compressed with compress(1)
This program works by forking four more copies of itself. The five
programs form a pipeline. Copy 0 writes to stdout, and forks copy 1
to supply its input, which in turn forks and reads from copy 2, etc.
The arguments -0 to -4 run only the corresponding pass.
.P
Thus:
.P
decomp16 -4 < compressed_file > 3;
.P
decomp16 -3 < 3 > 2;
.P
decomp16 -2 < 2 > 1;
.P
decomp16 -1 < 1 > 0;
.P
decomp16 -0 < 0 > decompressed_file
.P
will also work, as will connecting the passes by explicit pipes if
there is enough memory to do so.
.SH EXAMPLES
.P
decomp16 comp_file decomp_file # Decompresses comp_file to decomp_file.
.P
decomp16 < comp_file > decomp_file # Same as above but with output redirects.
.SH SEE ALSO
compress(1)
.SH AUTHOR
Manpage written by Jacob Adams <tookmund@gmail.com>

View File

@ -1,438 +0,0 @@
/* decomp16: decompress 16bit compressed files on a 16bit Intel processor
*
* Version 1.3 of 25 Mar 92.
*
* This was written by John N. White on 6/30/91 and is Public Domain.
* Patched to run under news by Will Rose, Feb 92.
* J N White's (earlier) patches added by Will Rose, 20 Feb 92.
* Unsigned int increment/wrap bug fixed by Will Rose, 24 Mar 92.
* Argument bug fixed, stdio generalised by Will Rose, 25 Mar 92.
*
* decomp16 can use as as little as 512 bytes of stack; since it forks
* four additional copies, it's probably worth using minimum stack rather
* than the 8192 byte Minix default. To reduce memory still further,
* change BUFSZ below to 256; it is currently set to 1024 for speed. The
* minimal decomp16 needs about 280k to run in pipe mode (56k per copy).
*
* This program acts as a filter:
* decomp16 < compressed_file > decompressed_file
* The arguments -0 to -4 run only the corresponding pass.
* Thus:
* decomp16 -4 < compressed_file > 3;
* decomp16 -3 < 3 > 2;
* decomp16 -2 < 2 > 1;
* decomp16 -1 < 1 > 0;
* decomp16 -0 < 0 > decompressed_file
* will also work, as will connecting the passes by explicit pipes if
* there is enough memory to do so. File name arguments can also be
* given directly on the command line.
*
* Compress uses a modified LZW compression algorithm. A compressed file
* is a set of indices into a dictionary of strings. The number of bits
* used to store each index depends on the number of entries currently
* in the dictionary. If there are between 257 and 512 entries, 9 bits
* are used. With 513 entries, 10 bits are used, etc. The initial dictionary
* consists of 0-255 (which are the corresponding chars) and 256 (which
* is a special CLEAR code). As each index in the compressed file is read,
* a new entry is added to the dictionary consisting of the current string
* with the first char of the next string appended. When the dictionary
* is full, no further entries are added. If a CLEAR code is received,
* the dictionary will be completely reset. The first two bytes of the
* compressed file are a magic number, and the third byte indicates the
* maximum number of bits, and whether the CLEAR code is used (older versions
* of compress didn't have CLEAR).
*
* This program works by forking four more copies of itself. The five
* programs form a pipeline. Copy 0 writes to stdout, and forks copy 1
* to supply its input, which in turn forks and reads from copy 2, etc.
* This sequence is used so that when the program exits, all writes
* are completed and a program that has exec'd uncompress (such as news)
* can immediately use the uncompressed data when the wait() call returns.
*
* If given a switch -#, where # is a digit from 0 to 4 (example: -2), the
* program will run as that copy, reading from stdin and writing to stdout.
* This allows decompressing with very limited RAM because only one of the
* five passes is in memory at a time.
*
* The compressed data is a series of string indices (and a header at
* the beginning and an occasional CLEAR code). As these indices flow
* through the pipes, each program decodes the ones it can. The result
* of each decoding will be indices that the following programs can handle.
*
* Each of the 65536 strings in the dictionary is an earlier string with
* some character added to the end (except for the the 256 predefined
* single char strings). When new entries are made to the dictionary,
* the string index part will just be the last index to pass through.
* But the char part is the first char of the next string, which isn't
* known yet. So the string can be stored as a pair of indices. When
* this string is specified, it is converted to this pair of indices,
* which are flagged so that the first will be decoded in full while
* the second will be decoded to its first char. The dictionary takes
* 256k to store (64k strings of 2 indices of 2 bytes each). This is
* too big for a 64k data segment, so it is divided into 5 equal parts.
* Copy 4 of the program maintains the high part and copy 0 holds the
* low part.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFSZ 1024 /* size of i/o buffers */
#define BUFSZ_2 (BUFSZ/2) /* # of unsigned shorts in i/o bufs */
#define DICTSZ (unsigned)13056 /* # of local dictionary entries */
#define EOF_INDEX (unsigned short)0xFFFF /* EOF flag for pipeline */
#define FALSE 0
#define TRUE ~FALSE
int fdin, fdout, fderr; /* input, output, and error file descriptors */
int ibufstart, obufind, ibufend;/* i/o buffer indices */
int ipbufind = BUFSZ_2; /* pipe buffer indices */
int opbufind = 0;
int pnum = -1; /* ID of this copy */
unsigned short ipbuf[BUFSZ_2]; /* for buffering input */
unsigned short opbuf[BUFSZ_2]; /* for buffering output */
unsigned char *ibuf = (unsigned char *) ipbuf;
unsigned char *obuf = (unsigned char *) opbuf;
unsigned short dindex[DICTSZ]; /* dictionary: index to substring */
unsigned short dchar[DICTSZ]; /* dictionary: last char of string */
unsigned iindex, tindex, tindex2; /* holds index being processed */
unsigned base; /* where in global dict local dict starts */
unsigned tbase;
unsigned locend; /* where in global dict local dict ends */
unsigned curend = 256; /* current end of global dict */
unsigned maxend; /* max end of global dict */
int dcharp; /* ptr to dchar that needs next index entry */
int curbits; /* number of bits for getbits() to read */
int maxbits; /* limit on number of bits */
int clearflg; /* if set, allow CLEAR */
int inmod; /* mod 8 for getbits() */
int main(int argc, char **argv);
void ffork(void);
void die(char *s);
void myputc(unsigned c);
unsigned mygetc(void);
void getbits(void);
void getpipe(void);
void putpipe(unsigned u, int flag);
int main(int argc, char **argv)
{
char c, *cp;
int j, k, fdtmp;
unsigned int len;
/* Find the program name */
j = 0;
while (argv[0][j] != '\0') j++;
len = (unsigned int) j;
while (j--)
if (argv[0][j] == '/') break;
if (argv[0][j] == '/') j++;
cp = argv[0] + j;
len -= j;
/* Sort out the flags */
for (k = 1; k < argc; k++) {
if (argv[k][0] == '-') {
c = argv[k][1];
switch (c) {
case '0': /* pass numbers */
case '1':
case '2':
case '3':
case '4': pnum = c - '0'; break;
case 'd': /* used by news */
break;
default:
(void) write(1, "Usage: ", 7);
(void) write(1, cp, len);
(void) write(1, " [-#] [in] [out]\n", 17);
exit(0);
break;
}
/* Once it's checked, lose it anyway */
for (j = k; j < argc; j++) argv[j] = argv[j + 1];
argc--;
k--;
}
}
/* Default i/o settings */
fdin = 0;
fdout = 1;
fderr = 2;
/* Try to open specific files and connect them to stdin/stdout */
if (argc > 1) {
if ((fdtmp = open(argv[1], 0)) == -1) die("input open failed");
(void) close(0);
if ((fdin = dup(fdtmp)) == -1) die("input dup failed\n");
(void) close(fdtmp);
}
if (argc > 2) {
(void) unlink(argv[2]);
if ((fdtmp = creat(argv[2], 0666)) == -1) die("output creat failed");
(void) close(1);
if ((fdout = dup(fdtmp)) == -1) die("output dup failed\n");
(void) close(fdtmp);
}
/* Sort out type of compression */
if (pnum == -1 || pnum == 4) {/* if this is pass 4 */
/* Check header of compressed file */
if (mygetc() != 0x1F || mygetc() != 0x9D) /* check magic number */
die("not a compressed file\n");
iindex = mygetc(); /* get compression style */
} else
getpipe(); /* get compression style */
maxbits = iindex & 0x1F;
clearflg = ((iindex & 0x80) != 0) ? TRUE : FALSE;
if (maxbits < 9 || maxbits > 16) /* check for valid maxbits */
die("can't decompress\n");
if (pnum != -1 && pnum != 0)
putpipe(iindex, 0); /* pass style to next copy */
/* Fork off an ancestor if necessary - ffork() increments pnum */
if (pnum == -1) {
pnum = 0;
if (pnum == 0) ffork();
if (pnum == 1) ffork();
if (pnum == 2) ffork();
if (pnum == 3) ffork();
}
/* Preliminary inits. Note: end/maxend/curend are highest, not
* highest + 1 */
base = DICTSZ * pnum + 256;
locend = base + DICTSZ - 1;
maxend = (1 << maxbits) - 1;
if (maxend > locend) maxend = locend;
while (TRUE) {
curend = 255 + (clearflg ? 1 : 0); /* init dictionary */
dcharp = DICTSZ; /* flag for none needed */
curbits = 9; /* init curbits (for copy 0) */
while (TRUE) { /* for each index in input */
if (pnum == 4) {/* get index using getbits() */
if (curbits < maxbits && (1 << curbits) <= curend) {
/* Curbits needs to be increased */
/* Due to uglyness in compress, these
* indices in the compressed file are
* wasted */
while (inmod) getbits();
curbits++;
}
getbits();
} else
getpipe(); /* get next index */
if (iindex == 256 && clearflg) {
if (pnum > 0) putpipe(iindex, 0);
/* Due to uglyness in compress, these indices
* in the compressed file are wasted */
while (inmod) getbits();
break;
}
tindex = iindex;
/* Convert the index part, ignoring spawned chars */
while (tindex >= base) tindex = dindex[tindex - base];
/* Pass on the index */
putpipe(tindex, 0);
/* Save the char of the last added entry, if any */
if (dcharp < DICTSZ) dchar[dcharp++] = tindex;
if (curend < maxend && ++curend > (base - 1))
dindex[dcharp = (curend - base)] = iindex;
/* Do spawned chars. They are naturally produced in
* the wrong order. To get them in the right order
* without using memory, a series of passes,
* progressively less deep, are used */
tbase = base;
while ((tindex = iindex) >= tbase) {/* for each char to spawn*/
while ((tindex2 = dindex[tindex - base]) >= tbase)
tindex = tindex2; /* scan to desired char */
putpipe(dchar[tindex-base], 1); /* put it to the pipe*/
tbase = tindex + 1;
if (tbase == 0) break; /* it's a wrap */
}
}
}
}
/* F f o r k
*
* Fork off the previous pass - the parent reads from the child.
*/
void ffork()
{
int j, pfd[2];
if (pipe(pfd) == -1) die("pipe() error\n");
if ((j = fork()) == -1) die("fork() error\n");
if (j == 0) { /* this is the child */
if (close(1) == -1) die("close(1) error\n");
if (dup(pfd[1]) != 1) die("dup(1) error\n");
(void) close(pfd[0]);
pnum++;
} else { /* this is the parent */
if (close(0) == -1) die("close(0) error\n");
if (dup(pfd[0]) != 0) die("dup(0) error\n");
(void) close(pfd[1]);
}
}
/* D i e
*
* If s is a message, write it to stderr. Flush buffers if needed. Then exit.
*/
void die(char *s)
{
/* Flush stdout buffer if needed */
if (obufind != 0) {
if (write(fdout, (char *) obuf, (unsigned) obufind) != obufind)
s = "bad stdout write\n";
obufind = 0;
}
/* Flush pipe if needed */
do
putpipe(EOF_INDEX, 0);
while (opbufind);
/* Write any error message */
if (s != (char *) NULL) {
while (*s) (void) write(fderr, s++, 1);
}
exit((s == (char *) NULL) ? 0 : 1);
}
/* M p u t c
*
* Put a char to stdout.
*/
void myputc(unsigned c)
{
obuf[obufind++] = c;
if (obufind >= BUFSZ) { /* if stdout buffer full */
if (write(fdout, (char *) obuf, BUFSZ) != BUFSZ) /* flush to stdout */
die("bad stdout write\n");
obufind = 0;
}
}
/* M y g e t c
*
* Get a char from stdin. If EOF, then die() and exit.
*/
unsigned mygetc()
{
if (ibufstart >= ibufend) { /* if stdin buffer empty */
if ((ibufend = read(fdin, (char *) ibuf, BUFSZ)) <= 0)
die((char *) NULL); /* if EOF, do normal exit */
ibufstart = 0;
}
return(ibuf[ibufstart++] & 0xff);
}
/* G e t b i t s
*
* Put curbits bits into index from stdin. Note: only copy 4 uses this.
* The bits within a byte are in the correct order. But when the bits
* cross a byte boundry, the lowest bits will be in the higher part of
* the current byte, and the higher bits will be in the lower part of
* the next byte.
*/
void getbits()
{
int have;
static unsigned curbyte; /* byte having bits extracted from it */
static int left; /* how many bits are left in curbyte */
inmod = (inmod + 1) & 7; /* count input mod 8 */
iindex = curbyte;
have = left;
if (curbits - have > 8) {
iindex |= mygetc() << have;
have += 8;
}
iindex |= ((curbyte = mygetc()) << have) & ~((unsigned) 0xFFFF << curbits);
curbyte >>= curbits - have;
left = 8 - (curbits - have);
}
/* G e t p i p e
*
* Get an index from the pipeline. If flagged firstonly, handle it here.
*/
void getpipe()
{
static short flags;
static int n = 0; /* number of flags in flags */
while (TRUE) { /* while index with firstonly flag set */
if (n <= 0) {
if (ipbufind >= BUFSZ_2) { /* if pipe input buffer
* empty */
if (read(fdin, (char *) ipbuf, BUFSZ) != BUFSZ)
die("bad pipe read\n");
ipbufind = 0;
}
flags = ipbuf[ipbufind++];
n = 15;
}
iindex = ipbuf[ipbufind++];
if (iindex > curend)
die((iindex == EOF_INDEX) ? (char *) NULL : "invalid data\n");
flags <<= 1;
n--;
/* Assume flags < 0 if highest remaining flag is set */
if (flags < 0) { /* if firstonly flag for index is not set */
while (iindex >= base) iindex = dindex[iindex - base];
putpipe(iindex, 1);
} else
return; /* return with valid non-firstonly index */
}
}
/* P u t p i p e
*
* put an index into the pipeline.
*/
void putpipe(unsigned u, int flag)
{
static unsigned short flags, *flagp;
static int n = 0; /* number of flags in flags */
if (pnum == 0) { /* if we should write to stdout */
myputc(u); /* index will be the char value */
return;
}
if (n == 0) { /* if we need to reserve a flag entry */
flags = 0;
flagp = opbuf + opbufind;
opbufind++;
}
opbuf[opbufind++] = u; /* add index to buffer */
flags = (flags << 1) | flag; /* add firstonly flag */
if (++n >= 15) { /* if block of 15 indices */
n = 0;
*flagp = flags; /* insert flags entry */
if (opbufind >= BUFSZ_2) { /* if pipe out buffer full */
opbufind = 0;
if (write(fdout, (char *) opbuf, BUFSZ) != BUFSZ)
die("bad pipe write\n");
}
}
}