Retire decomp16(1)
Change-Id: I455aac47b3efa4ffa5cc8305c6760f92e1e8642a
This commit is contained in:
parent
c0d9ad695c
commit
fd962fdd93
5 changed files with 3 additions and 499 deletions
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
PROG= decomp16
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -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>
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue