[net.sources] CPM USQ

geoff@desint.UUCP (Geoff Kuenning) (12/03/84)

: 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