DataMuseum.dk

Presents historical artifacts from the history of:

CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦295ecaa55⟧ TextFile

    Length: 6912 (0x1b00)
    Types: TextFile
    Names: »SQ.C«

Derivation

└─⟦1275f6521⟧ Bits:30005823 BD Software C Compiler v1.50a
    └─ ⟦this⟧ »SQ.C« 

TextFile

/* This program compresses a file without loosing information.
 * The usq.com program is required to unsqueeze the file
 * before it can be used.
 *
 * Typical compression rates are:
 *	.COM	6%	(Don't bother)
 *	.ASM	33%	(using full ASCII set)
 *	.DIC	46%	(using only uppercase and a few others)
 * Squeezing a really big file takes a few minutes.
 *
 * Useage:
 *	SQ item ...
 * where ... represents more (optional) items and
 * "item" is either:
 *	drive:		to change the output drive
 *	file		input file
 *	drive:file	input file
 *	-		toggle debugging display mode
 *
 * 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.
 *
 * SQ uses the dio package, so input and output can be redirected
 * by special items on the command line such as:
 *	<file		reads console input from file
 *	>file		sends console output to file
 *	+file		sends console output to console and file
 * Also console output of another program using dio can be piped
 * to the input of this one or vice-versa. Example:
 *	A>fls parameters øsq
 * where fls might be a program that expands patterns like *.com
 * to a list of ambiguous file names for sq to squeeze.
 *
 * The squeezed file name is formed by changing the second
 * letter of the file type to Q. If there is no file type,
 * the squeezed file type is QQQ. If the name exists it is
 * overwritten!
 * 
 * Examples:
 *	A>SQ GRUMP		makes GRUMP.QQQ on A:
 *	A>SQ D:CRAP.XYZ		makes CRAP.XQZ on A:
 *	A>SQ B: D:CRAP.COM	makes CRAP.CQM on B:
 *	B>SQ X.A C: Y.B		makes X.AQ on B: and Y.BQ on C:
 *
 * The transformations compress strings of identical bytes and
 * then encode each resulting byte value and EOF as bit strings
 * having lengths in inverse proportion to their frequency of
 * occurrance in the intermediate input stream. The latter uses
 * the Huffman algorithm. Decoding information is included in
 * the squeezed file, so squeezing short files or files with
 * uniformly distributed byte values will actually increase size.
 */

/* CHANGE HISTORY:
 * 1.3	Close files properly in case of error exit.
 * 1.4	Break up long introductory lines.
 * 1.4	Send introduction only to console.
 * 1.4	Send errors only to console.
 * 1.5  Fix BUG that caused a rare few squeezed files
 *	to be incorrect and fail the USQ crc check.
 *	The problem was that some 17 bit codes were
 *	generated but are not supported by other code.
 *	THIS IS A MAJOR CHANGE affecting TR2.C and SQ.H and
 *	requires recompilation of all files which are part
 *	of SQ. Two basic changes were made: tree depth is now
 *	used as a tie breaker when weights are equal. This
 *	makes the tree shallower. Although that may always be
 *	sufficient, an error trap was added to cause rescaling
 *	of the counts if any code > 16 bits long is generated.
 * 1.5	Add debugging displays option '-'.
 */
\f


#define VERSION "1.5   08/29/81"

#include <bdscio.h>
#include <dio.h>
#include "sqcom.h"
#include "sq.h"
#define STDOUT 4	/* console only (error) stream */

main(argc, argv)
int argc;
char *argvÆÅ;
æ
	int i,c;
	int getchar();		/* Directed io version */
	char inpargÆ16Å;	/* parameter from input */

	dioinit(&argc, argv);	/* obey directed to args */

	debug = FALSE;
	fprintf(STDOUT,"File squeezer version %s byØnØtRichard GreenlawØnØt251 Colony Ct.ØnØtGahanna, Ohio 43230Øn", VERSION);
	fprintf(STDOUT,"Accepts redirection and pipes.ØnOmit other parameters for help and promptØn");

	/* Initialize output drive to default drive */
	outdrvÆ0Å  = 'Ø0';
	/* But prepare for a specific drive */
	outdrvÆ1Å = ':';
	outdrvÆ2Å = 'Ø0';	/* string terminator */

	/* Process the parameters in order */
	for(i = 1; i < argc; ++i)
		obey(argvÆiÅ);

	if(argc < 2) æ
		fprintf(STDOUT, "Parameters are from command line or one-at-a-time from standardØninput and are output drives and input file names. Empty to quit.Øn");
		do æ
			fprintf(STDOUT, "Øn*");
			for(i = 0; i < 16; ++i) æ
				if((c = getchar()) == EOF)
					c = 'Øn';	/* fake empty (exit) command */
				if((inpargÆiÅ = c) == 'Øn') æ
					inpargÆiÅ = 'Ø0';
					break;
				å
			å
			if(inpargÆ0Å != 'Ø0')
				obey(inparg);
		å while(inpargÆ0Å != 'Ø0');
	å
	dioflush();	/* clean up any directed io */
å
\f


obey(p)
char *p;
æ
	char *q;
	char outfileÆ16Å;	/* output file spec. */

	if(*p == '-') æ
		/* toggle debug option */
		debug = !debug;
		return;
	å
	if(*(p + 1) == ':') æ
		/* Got a drive */
		if(isalpha(*p)) æ
			if(*(p+2) == 'Ø0') æ
				/* Change output drive */
				printf("ØnOutput drive =%s",p);
				outdrvÆ0Å = *p;
				return;
			å
		å else æ
			fprintf(STDOUT, "ØnERROR - Ignoring %s", p);
			return;
		å
	å

	/* Check for ambiguous (wild-card) name */
	for(q = p; *q != 'Ø0'; ++q)
		if(*q == '*' øø *q == '?') æ
			fprintf(STDOUT, "ØnAmbiguous name %s ignored", p);
			return;
	å
	/* First build output file name */
	outfileÆ0Å = 'Ø0';		/* empty */
	strcat(outfile, outdrv);	/* drive */
	strcat(outfile, (*(p + 1) == ':') ? p + 2 : p);	/* input name */

	/* Find and change output file type */
	for(q = outfile; *q != 'Ø0'; ++q)
		if(*q == '.')
			if(*(q + 1) == 'Ø0')
				*q = 'Ø0';	/* kill trailing dot */
			else
				switch(*(q+2)) æ
				case 'q':
				case 'Q':
					fprintf(STDOUT, "Øn%s ignored ( already squeezed?)", p);
					return;
				case 'Ø0':
					*(q+3) = 'Ø0';
					/* fall thru */
				default:
					*(q + 2) = 'Q';
					goto named;
				å
	/* No file type */
	strcat(outfile, ".QQQ");
named:
	squeeze(p, outfile);
å
\f


squeeze(infile, outfile)
char *infile, *outfile;
æ
	int i, c;
	struct _buf inbuff, outbuff;	/* file buffers */

	printf("Øn%s -> %s: ", infile, outfile);

	if(fopen(infile, &inbuff) == ERROR) æ
		fprintf(STDOUT, "Can't open %s for input pass 1Øn", infile);
		return;
	å
	if(fcreat(outfile, &outbuff) == ERROR) æ
		fprintf(STDOUT, "Can't create %sØn", outfile);
		fclose(&inbuff);
		return;
	å

	/* First pass - get properties of file */
	crc = 0;	/* initialize checksum */
	printf("analyzing, ");
	/*init_ncr();*/
	init_huff(&inbuff);   
	fclose(&inbuff);

	/* Write output file header with decoding info */
	wrt_head(&outbuff, infile);

	/* Second pass - encode the file */
	printf("squeezing, ");
	if(fopen(infile, &inbuff) == ERROR) æ
		fprintf(STDOUT, "Can't open %s for input pass 2Øn", infile);
		goto closeout;
	å
	/*init_ncr();	*//* For second pass */

	/* Translate the input file into the output file */
	while((c = gethuff(&inbuff)) != EOF)
		if(putc(c, &outbuff) == ERROR) æ
			fprintf(STDOUT, "ERROR - write failure in %sØn", outfile);
			goto closeall;
		å
	printf(" done.");
closeall:
	fclose(&inbuff);
closeout:
	fflush(&outbuff);
	fclose(&outbuff);
å
«eof»