/*
 *		lzdcmp [-options] [infile [outfile]]
 */
#ifdef	DOCUMENTATION

title	lzdcmp	File Decompression
index		File decompression

synopsis
	.s.nf
	lzdcmp [-options] [infile [outfile]]
	.s.f
description

	lzdcmp decompresses files compressed by lzcomp.  The
	documentation for lzcomp describes the process in
	greater detail.

	Options may be given in either case.
	.lm +8
	.p -8
	-B	Output file is "binary", not text.
	.p -8
	-N	Don't read magic header (for reading old files)
	.p -8
	-Q	Quiet -- don't write status messages.
	.p -8
	-D val	Debug (if compiled in), val is debug level.
	-V	Verbose dump (of string tables, debug must == 0)

Author
	This version by Martin Minow.  See lzcomp for more
	details.
#endif

/*
 * Compatible with compress.c, v3.0 84/11/27
 */

/*)BUILD
 *		$(PROGRAM) = lzdcmp
 *		$(INCLUDE) = lz.h
 *		$(FILES) = { lzdcm1.c lzdcm2.c lzio.c }
 */

#include	"lz.h"
#ifdef DEBUG
# ifdef unix
#  include <sys/types.h>
#  include <sys/timeb.h>
# else
#  include <timeb.h>
# endif
static struct timeb	start_time;
static struct timeb	end_time;
#endif

/*
 * These global parameters are read from the compressed file.
 * The decompressor needs them.
 */
short		maxbits = BITS;		/* settable max # bits/code	*/
short		block_compress = BLOCK_MASK;
code_int	maxmaxcode = 1 << BITS;

flag		binary = FALSE;		/* Read text if false		*/
flag		nomagic = FALSE;	/* No magic header if TRUE	*/
flag		quiet = FALSE;		/* don't talk about compression	*/
#ifdef	DEBUG
flag		debug = 0;
flag		verbose = FALSE;	/* Dump string tables		*/
#endif

static char_type magic_header[] =	/* First 2 bytes of compressed	*/
    { HEAD1_MAGIC, HEAD2_MAGIC, 0 };	/* data file.			*/
char		*infilename = NULL;	/* For error printouts		*/
char		*outfilename = NULL;	/* For openoutput and errors	*/

main(argc, argv)
int		argc;
char		*argv[];
/*
 * Decompress mainline
 */
{
#ifdef DEBUG
	int		msec;
#endif

	setup(argc, argv);
	if (maxbits < INIT_BITS)
	    maxbits = INIT_BITS;
	if (maxbits > BITS)
	    maxbits = BITS;
	maxmaxcode = 1 << maxbits;
	if (nomagic == FALSE) {
	    if (GET() != (magic_header[0] & 0xFF)
	     || GET() != (magic_header[1] & 0xFF)) {
		fprintf(stderr, "%s: not in compressed format\n", infilename);
		exit(IO_ERROR);
	    }
	    else {
		if ((maxbits = GET()) == -1) {
		    perror(infilename);		/* Early eof		*/
		    exit(IO_ERROR);
		}
		block_compress = maxbits & BLOCK_MASK;
		maxbits &= BIT_MASK;
		maxmaxcode = 1 << maxbits;
		if (maxbits > BITS) {
		    fprintf(stderr, "%s: compressed with %d bits,",
			infilename, maxbits);
		    fprintf(stderr, " can only handle %d bits\n", BITS);
		    exit(IO_ERROR);
		}
#ifdef	DEBUG
		fprintf(stderr, "%s: compressed with %d bits,",
		   infilename, maxbits);
		fprintf(stderr, " block compression %s.\n",
		    (block_compress != 0) ? "enabled" : "disabled");
#endif
	    }
	}
	openoutput();
#ifndef DEBUG
	decompress();
#else
	if (debug == 0) {
	    ftime(&start_time);
	    decompress();
	    if (!quiet) {
		ftime(&end_time);
		end_time.time -= start_time.time;
		msec = end_time.millitm - start_time.millitm;
		if (msec < 0) {
		    msec += 1000;
		    end_time.time--;
		}
		fprintf(stderr, "%ld.%03d seconds for decompression\n",
		    end_time.time, msec);
	    }
	}
	else {
	    printcodes(stdout);
	}
	if (verbose)
	    dump_tab(stdout);
#endif
	exit(IO_SUCCESS);
}

static
setup(argc, argv)
int		argc;
char		*argv[];
/*
 * Get parameters and open files.  Exit fatally on errors.
 */
{
	register char	*ap;
	register int	c;
	int		i, j;
	char		*arg;
#ifndef	unix
	char		filename[80];
#endif

#ifdef	vms
	argc = getredirection(argc, argv);
#endif
	for (i = j = 1; i < argc; i++) {
	    arg = ap = argv[i];
	    if (*ap++ != '-' || *ap == EOS)	/* Filename?		*/
		argv[j++] = argv[i];		/* Just copy it		*/
	    else {
		c = *ap++;			/* Option byte		*/
		if (islower(c))
		    c = toupper(c);
		switch (c) {
		case 'B':
		    binary = TRUE;
		    break;

		case 'N':
		    nomagic = TRUE;
		    break;

		case 'Q':
		    quiet = TRUE;
		    break;

#ifdef DEBUG
		case 'D':
		    if (isdigit(*ap)) {
			debug = atoi(ap);
			continue;
		    }
		    debug = 1;
		    break;

		case 'V':
		    verbose = TRUE;
		    break;
#endif
		default:
		    fprintf(stderr, "Unknown option \"%s\"\n", arg);
		    fprintf(stderr, "The following options are valid:\n\
-B\tBinary file (important on VMS/RSX, ignored on Unix)\n\
-N\tDon't look for header code\n\
-Q\tNo output to stderr, unless error.\n");
#ifdef	DEBUG
		    fprintf(stderr, "-Dn\tDebug (n = level)\n");
		    fprintf(stderr, "-V\tVerbose printouts\n");
#endif
		    exit(IO_ERROR);
		}				/* Switch on options	*/
	    }					/* If -option		*/
	}
	/* outfilename = NULL; */		/* Openoutput signal	*/
	switch (j) {				/* Any file arguments?	*/
	case 3:					/* both files given	*/
	    if (!streq(argv[2], "-"))
		outfilename = argv[2];
	case 2:					/* Input file given	*/
	    if (!streq(argv[1], "-")) {
#ifdef decus
		if (freopen(argv[1], "rn", stdin) == NULL) {
		    perror(argv[2]);
		    exit(IO_ERROR);
		}
#else
		/*
		 * Special case for vms too?
		 */
		if (freopen(argv[1], "r", stdin) == NULL) {
		    perror(argv[2]);
		    exit(IO_ERROR);
		}		    
#endif
		infilename = argv[1];
	    }
	    break;

	case 0:					/* None!		*/
	case 1:					/* No file arguments	*/
#ifdef	vms
	    fgetname(stdin, filename);
	    infilename = malloc(strlen(filename) + 1);
	    strcpy(infilename, filename);
#else
#ifdef decus
	    fgetname(stdin, filename);
	    infilename = malloc(strlen(filename) + 1);
	    strcpy(infilename, filename);
#else
	    infilename = "stdin";
#endif
#endif
	    break;

	default:
	    fprintf(stderr, "Too many file arguments\n");
	    exit(IO_ERROR);
	}
}

openoutput()
{
#ifndef unix
	char		filename[80];
#endif

	if (outfilename == NULL) {
#ifdef	vms
	    fgetname(stdout, filename);
	    outfilename = malloc(strlen(filename) + 1);
	    strcpy(outfilename, filename);
#else
#ifdef decus
	    fgetname(stdout, filename);
	    outfilename = malloc(strlen(filename) + 1);
	    strcpy(outfilename, filename);
#else
	    outfilename = "<stdout>";
#endif
#endif
	}
	else {
#ifdef vms
	    if (binary) {
		if (freopen(outfilename, "w", stdout) == NULL) {
		    perror(outfilename);
		    exit(IO_ERROR);
		}
	    }
	    else {
		int		i;

		if ((i = creat(outfilename, 0, "rat=cr", "rfm=var")) == -1
		 || dup2(i, fileno(stdout)) == -1) {
		    perror(outfilename);
		    exit(IO_ERROR);
		}
	    }
#else
#ifdef decus
	    if (freopen(outfilename, (binary) ? "wn" : "w", stdout) == NULL) {
		perror(outfilename);
		exit(IO_ERROR);
	    }
#else
	    if (freopen(outfilename, "w", stdout) == NULL) {
		perror(outfilename);
		exit(IO_ERROR);
	    }
#endif
#endif
	}
}
