CPM USQ (decompression) program to run under Unix
Geoff Kuenning
geoff at desint.UUCP
Mon Dec 3 10:56:13 AEST 1984
: This is a shar archive. Extract with sh, not csh.
: The rest of this file will extract:
:
: README Makefile sqcom.h usq.h usq.c utr.c
:
echo extracting - README
sed 's/^-//' > README << '/*EOF'
This archive contains a version of the CP/M USQ program which runs on a
68000 under System V. I make no promises about whether it works on any other
systems. If you find bugs, post them, don't send them to me. I don't use it
any more.
Geoff Kuenning
...!ihnp4!trwrb!desint!geoff
/*EOF
echo extracting - Makefile
sed 's/^-//' > Makefile << '/*EOF'
#
# %W% %G% %U%
#
CFLAGS=-v -O
usq: usq.o utr.o
$(CC) $(CFLAGS) $(LDFLAGS) -o usq usq.o utr.o
usq.o utr.o: usq.h sqcom.h
/*EOF
echo extracting - sqcom.h
sed 's/^-//' > sqcom.h << '/*EOF'
-/*
@(#)sqcom.h 1.3 9/4/84 19:57:00
*/
-/* Definitions and external declarations */
#define RECOGNIZE 0xFF76 /* unlikely pattern */
-/* *** Stuff for first translation module *** */
#define DLE 0x90
unsigned short crc; /* error check code */
#ifdef cpm
char outdrv[3]; /* current output drive (string) */
#endif
-/* *** Stuff for second translation module *** */
#define SPEOF 256 /* special endfile token */
#define NUMVALS 257 /* 256 data values plus SPEOF*/
#define CPMEOF 0x1a
#define ERROR (-1)
#define SECSIZ 128
#ifndef EOF
#define EOF (-1)
#endif
/*EOF
echo extracting - usq.h
sed 's/^-//' > usq.h << '/*EOF'
-/*
@(#)usq.h 1.3 9/4/84 19:57:23
*/
#define LARGE 30000
-/* Decoding tree */
struct {
int children[2]; /* left, right */
} dnode[NUMVALS - 1];
int bpos; /* last bit position read */
int curin; /* last byte value read */
-/* Variables associated with repetition decoding */
int repct; /*Number of times to retirn value*/
int value; /*current byte value or EOF */
/*EOF
echo extracting - usq.c
sed 's/^-//' > usq.c << '/*EOF'
static char Sccs_Id[] = "@(#)usq.c 1.3 9/4/84 19:57:05";
-/* USQ.C CHANGE HISTORY:
* 1.3 Converted to support USG Unix on 68000. Define unix to
* get unix version, cpm to get CP/M-68K version. Geoff Kuenning 9/3/84
* 1.2 Converted to Unix SCCS. Geoff Kuenning 9/3/84
* 1.1 Added WILDEXP. JEC 1/2/84
* 1.0 Converted to CP/M-68K C, Jim Cathey 11-5-83
* Taken from BDS C version 2.0
* 2.0 Added checkurk(), changed credits -CAF 8-14-83
* 1.9 Added wildexp -CAF 6-12-82
* 1.8 Output CPMEOF's while last output sector is partially filled.
* Needed if file was squeezed on a non-CP/M system. -CAF 3-10-82
* 1.7 Added -n to change NL to CRLF when unsqueezing files. Added CPMEOF
* at end of file in case of checksum error detected.
* 1.6 Lengthened permissible length of unsqueezed filename so long **nix
* pathnames won't choke unsqueeze(). -CAF 12-5-81
* 1.5 Break up long lines of introductory text
* -count no longer appends formfeed to preview of each file.
* -fcount (-f10, -F10) does append formfeed.
* 1.4 Add -count option to allow quick inspection of files.
* 1.3 Close inbuff to avoid exceeding maximum number of
* open files. Includes rearranging error exits.
*
* Program to unsqueeze files formed by sq.com
*
* Usage (CPM version):
* USQ item ...
* where ... represents more (optional) items and
* "item" is either:
* drive: to change the output drive
* file input file
* drive:file input file
* -<count> Previewing feature: redirects output
* files to standard output with parity stripped
* and unprintables except CR, LF, TAB and FF
* converted to periods. Limits each file
* to first count lines.
* Defaults to console, but see below how
* to capture all in one file for further
* processing, such as by PIP.
* Count defaults to a very high value.
* No CRC check is performed when previewing.
* Use drive: to cancel this.
*
* -f<count> Same as -count except formfeed
* appended to preview of each file.
* Example: -f10.
*
* -n Change NL to CRLF
*
* If no such items are given on the command line you will be
* prompted for commands (one at a time). An empty command
* terminates the program.
*
* Usage (USG Unix version):
* USQ item ...
* where ... represents more (optional) items and
* "item" is either:
* file input file
* -<count> Previewing feature: redirects output
* files to standard output with parity stripped
* and unprintables except CR, LF, TAB and FF
* converted to periods. Limits each file
* to first count lines.
* Count defaults to a very high value.
* No CRC check is performed when previewing.
* Use -e to cancel this.
*
* -f<count> Same as -<count> except formfeed
* appended to preview of each file.
* Example: -f10.
*
* -u Cancel -<count> or -f<count>.
* -n Change CRLF to NL. Note that this is the EXACT
* opposite of the meaning of this flag in CP/M.
*
* If no such items are given on the command line you will be
* prompted for commands (one at a time). An empty command
* terminates the program.
*
* The unsqueezed file name is recorded in the squeezed file.
*
* Examples (CP/M):
* A>USQ GRUMP.QQQ writes on a:
* A>USQ D:CRAP.XQZ writes on A:
* A>USQ B: D:CRAP.CQM writes on B:
* B>USQ X.AQ C: Y.BQ writes X.?? on B: and Y.?? on C:
*
* Examples (Unix):
* usq grump.qqq writes grump.q?q in current directory
* usq - crap.xqz writes cleaned-up crap to standard output
*/
#ifndef unix /* Make sure *something* is defined */
#define cpm
#endif
#ifdef unix
#include <stdio.h>
#include <ctype.h>
#else
#include <a:stdio.h>
#include <a:ctype.h>
#endif
#include "sqcom.h"
#include "usq.h"
#define VERSION "1.3 9/4/84" /* Version for titling output */
unsigned dispcnt; /* How much of each file to preview */
char ffflag; /* Formfeed separates preview from different files */
char nlmode; /* <>0 if adding/deleting cr's for host system */
#ifdef cpm
#define SENTINEL 055555 /* For catching out-of-memory conditions */
#ifndef PATHLEN
#define PATHLEN 16 /* Maximum length of an input filename */
#endif
#define LONGPATH 257 /* Maximum length of an output filename */
char origname[LONGPATH]; /* Original file name without drive */
unsigned Sentinel; /* be sure this doesn't get munged ! */
#endif
#ifdef unix
#ifndef PATHLEN
#define PATHLEN 512 /* Maximum length of a pathname */
#endif
#define LONGPATH PATHLEN
#endif
short brgetw ();
main(argc, argv)
int argc;
char *argv[];
{
int i,c;
char inparg[PATHLEN]; /* parameter from input */
#ifdef cpm
wildexp(&argc, &argv);
Sentinel = SENTINEL; /* unlikely value */
#endif
nlmode = dispcnt = 0; /* Not in preview or nlmode */
#ifdef cpm
/* Initialize output drive to default drive */
outdrv[0] = '\0';
/* But prepare for a specific drive */
outdrv[1] = ':';
outdrv[2] = '\0'; /* string terminator */
#endif
/* Process the parameters in order */
for(i = 1; i < argc; ++i)
obey(argv[i]);
if(argc < 2) {
fprintf(stderr, "File unsqueezer version %s\n", VERSION);
fprintf(stderr,"Conceived by Richard Greenlaw Modified by Chuck Forsberg et al.\n");
#ifdef cpm
fprintf(stderr, "Accepts redirection and wildcards.\n");
fprintf(stderr, "Usage: usq [-count][-Fcount][-N] [file ...]\n");
fprintf(stderr, "Parameters are from command line or one-at-a-time from standard\n");
fprintf(stderr, "input and are output drives and input file names. Empty to quit.\n");
#endif
#ifdef unix
fprintf(stderr, "Usage: usq [-<count>][-f<count>][-u][-n] [file ...]\n");
fprintf(stderr, "Parameters are from command line or one-at-a-time from standard\n");
fprintf(stderr, "input and are input file names. Empty to quit.\n");
#endif
do {
fprintf(stderr, "\n*");
for(i = 0; i < sizeof (inparg); ++i) {
if((c = getchar()) == EOF)
c = '\n'; /* force empty (exit) command */
if((inparg[i] = c) == '\n') {
inparg[i] = '\0';
break;
}
}
if(inparg[0] != '\0')
obey(inparg);
} while(inparg[0] != '\0');
}
#ifdef cpm
if (Sentinel != SENTINEL)
fprintf(stderr,"Out of memory: translation suspect!\007\n");
#endif
return 0;
}
obey(p)
char *p;
{
char *q;
if(*p == '-') {
if('n' ==tolower(p[1])) {
++nlmode; return;
}
#ifdef unix
if('e' == tolower (p[1])) {
dispcnt = 0; /* cancel previewing */
return;
}
#endif
if(ffflag = (tolower(*(p+1)) == 'f'))
++p;
/* Set number of lines of each file to view */
dispcnt = 65535; /* default */
if(*(p+1))
if((dispcnt = atoi(p + 1)) == 0)
fprintf(stderr, "\nBAD COUNT %s", p + 1);
return;
}
#ifdef cpm
if(*(p + 1) == ':') {
/* Got a drive */
if(isalpha(*p)) {
if(*(p+2) == '\0') {
/* Change output drive */
dispcnt = 0; /* cancel previewing */
printf("\nOutput drive =%s",p);
outdrv[0] = *p;
return;
}
} else {
fprintf(stderr, "\nERROR - Ignoring %s.", p);
return;
}
}
/* Check for ambiguous (wild-card) name */
for(q = p; *q != '\0'; ++q)
if(*q == '*' || *q == '?') {
fprintf(stderr, "\nCan't accept ambiguous name %s.", p);
return;
}
#endif
unsqueeze(p);
}
unsqueeze(infile)
char *infile;
{
FILE *inbuff, *outbuff; /* file buffers */
#ifdef cpm
FILE *fopenb(), *fdopen();
#endif
#ifdef unix
FILE *fopen (), *fdopen ();
#define creatb creat
#define fopenb fopen
#endif
int i, c, ofd;
char cc;
char *p;
unsigned short filecrc; /* checksum */
int numnodes; /* size of decoding tree */
char outfile[LONGPATH]; /* output file name */
unsigned linect; /* count of number of lines previewed */
if((inbuff = fopenb(infile,"r")) == 0) {
fprintf(stderr, "Can't open %s\n", infile);
return;
}
/* Initialization */
linect = 0;
crc = 0;
init_cr();
init_huff();
/* Process header */
if(brgetw (inbuff) != RECOGNIZE) {
fprintf(stderr, "'%s' is not a squeezed file!\n", infile);
goto closein;
}
filecrc = brgetw(inbuff);
/* Get original file name */
#ifdef cpm
p = origname; /* send it to array */
#endif
#ifdef unix
p = outfile;
#endif
do {
*p = getc(inbuff);
} while(*p++ != '\0');
#ifdef cpm
/* Combine with output drive */
outfile[0] = '\0'; /* empty */
strcat(outfile, outdrv); /* drive */
strcat(outfile, origname); /* name */
#endif
printf("\n%s -> %s: ", infile, outfile);
numnodes = brgetw(inbuff);
if(numnodes < 0 || numnodes >= NUMVALS) {
fprintf(stderr, "'%s' has invalid decode tree size.\n", infile);
goto closein;
}
/* Initialize for possible empty tree (SPEOF only) */
dnode[0].children[0] = -(SPEOF + 1);
dnode[0].children[1] = -(SPEOF + 1);
/* Get decoding tree from file */
for(i = 0; i < numnodes; ++i) {
dnode[i].children[0] = brgetw(inbuff);
dnode[i].children[1] = brgetw(inbuff);
}
if(dispcnt) {
/* Use standard output for previewing */
putchar('\n');
while(((c = getcr(inbuff)) != EOF) && (linect < dispcnt)) {
cc = 0x7f & c; /* strip parity */
if((cc < ' ') || (cc > '~'))
/* Unprintable */
switch(cc) {
case '\r': /* return */
/* newline will generate CR-LF */
goto next;
case '\n': /* newline */
++linect;
case '\f': /* formfeed */
case '\t': /* tab */
break;
default:
cc = '.';
}
putchar(cc);
next: ;
}
if(ffflag)
putchar('\f'); /* formfeed */
} else {
/* Create output file */
if((ofd = creatb(outfile, 0755)) == ERROR) {
fprintf(stderr, "Can't create '%s'.\n", outfile);
goto closeall;
}
outbuff = fdopen(ofd,"w");
/* Get translated output bytes and write file */
while((c = getcr(inbuff)) != EOF) {
crc += c;
if(nlmode && c=='\n')
fputc('\r',outbuff);
if((fputc(c, outbuff)) == ERROR) {
fprintf(stderr, "Write error in '%s'.\n", outfile);
goto closeall;
}
}
if(filecrc != crc) {
#ifdef cpm
fputc(CPMEOF, outbuff);
#endif
fprintf(stderr, "ERROR - checksum error in '%s'.\n", outfile);
}
closeall:
/*
* If the last sector is partially filled (this would happen
* iff the file was squeezed on MARC, Unix(TM), MS-DOS or
* similar system which avoids the CP/M EOF crock),
* pad it out with ^Z characters so editors,
* etc. won't choke on it. -CAF 3-10-82
*/
-/* while(outbuff._nleft % SECSIZ) /* for BDS C 1.4x only */
-/* putc(CPMEOF, &outbuff); */
fflush(outbuff);
fclose(outbuff);
}
closein:
fclose(inbuff);
}
short brgetw(stream)
FILE *stream;
{
-/* Get word from stream. Since BDS C is byte reversed and
CP/M-68K isn't, we need to swap every byte.
We don't use 'getw' because it returns 32 bits on a 32-bit machine.
*/
short wordin, wordout;
wordin = (getc (stream) << 8) | (getc (stream) & 0xFF);
swab(&wordin, &wordout, 2);
return wordout;
}
/*EOF
echo extracting - utr.c
sed 's/^-//' > utr.c << '/*EOF'
static char Sccs_Id[] = "@(#)utr.c 1.3 9/4/84 19:57:28";
#include <stdio.h>
#include "sqcom.h"
#include "usq.h"
-/* initialize decoding functions */
init_cr()
{
repct = 0;
}
init_huff()
{
bpos = 99; /* force initial read */
}
-/* Get bytes with decoding - this decodes repetition,
* calls getuhuff to decode file stream into byte
* level code with only repetition encoding.
*
* The code is simple passing through of bytes except
* that DLE is encoded as DLE-zero and other values
* repeated more than twice are encoded as value-DLE-count.
*/
int
getcr(ib)
FILE *ib;
{
int c;
if(repct > 0) {
/* Expanding a repeated char */
--repct;
return value;
} else {
/* Nothing unusual */
if((c = getuhuff(ib)) != DLE) {
/* It's not the special delimiter */
value = c;
if(value == EOF)
repct = LARGE;
return value;
} else {
/* Special token */
if((repct = getuhuff(ib)) == 0)
/* DLE, zero represents DLE */
return DLE;
else {
/* Begin expanding repetition */
repct -= 2; /* 2nd time */
return value;
}
}
}
}
-/* Decode file stream into a byte level code with only
* repetition encoding remaining.
*/
int
getuhuff(ib)
FILE *ib;
{
int i;
int bitval;
/* Follow bit stream in tree to a leaf*/
i = 0; /* Start at root of tree */
do {
if(++bpos > 7) {
if((curin = getc(ib)) == ERROR)
return ERROR;
bpos = 0;
/* move a level deeper in tree */
i = dnode[i].children[1 & curin];
} else
i = dnode[i].children[1 & (curin >>= 1)];
} while(i >= 0);
/* Decode fake node index to original data value */
i = -(i + 1);
/* Decode special endfile token to normal EOF */
i = (i == SPEOF) ? EOF : i;
return i;
}
/*EOF
exit
--
Geoff Kuenning
...!ihnp4!trwrb!desint!geoff
More information about the Comp.sources.unix
mailing list