/*
 * Header file for all lz compression/decompression routines.
 *
 * Machine/Operating system/compiler selection: (#ifdef'ed)
 * vax				Vax/Unix or Vax/VMS
 * pdp11			makes a small compressor
 * M_XENIX			"large-model" Z8000
 * interdata			Signed long compare is slow
 * unix				Defined on true Unix systems
 * decus			Decus C (no signal)
 * vms				Vax/VMS (VMS_V4 may be set automatically)
 * #define readonly		If the compiler doesn't support it correctly.
 * 
 * Compiler configuration (#if'ed):
 * #define vax_asm   TRUE/FALSE	TRUE on Vax (4bsd) if the compiler supports
 *				the asm() operator.  Check the generated code!
 * #define UCHAR     TRUE/FALSE	TRUE if compiler supports unsigned char
 * #define DEBUG     TRUE/FALSE	TRUE to compile in debug printouts
 *
 * Algorithm Tuning parameters:
 * #define USERMEM   <n>	Memory available to compress.
 *				If large enough, a faster algorithm is used.
 * #define SACREDMEM <n>	Don't use this part of USERMEM.
 * #define BITS      <n>	Maximum number of code bits.
 * #define MAXIO     <n>	Output buffer size (squeeze memory if needed)
 */

#include <stdio.h>
#include <ctype.h>
#include <setjmp.h>
#ifndef decus
# include <signal.h>
/*
 * Arguments to signal():
 */
extern int	abort();		/* Debugging interrupt trap	*/
extern int	interrupt();		/* Non-debugging interrupt trap	*/
extern int	address_error();	/* "Segment" violation		*/
#endif

#ifndef	TRUE
# define FALSE		0
# define TRUE		1
#endif
#ifndef	EOS
# define EOS		'\0'
#endif
#define	streq(a, b)	(strcmp((a), (b)) == 0)
#define min(a,b)	((a) > (b)) ? (b) : (a))

/*
 * Set USERMEM to the maximum amount of physical user memory available
 * in bytes.  USERMEM is used to determine the maximum BITS that can be used
 * for compression.
 *
 * SACREDMEM is the amount of physical memory saved for others; compress
 * will hog the rest.
 */

#ifndef SACREDMEM
# define SACREDMEM	0
#endif

/*
 * Set machine-specific parameters
 */

#ifdef vax
# ifdef unix
#  define vax_asm	TRUE		/* If asm() supported on vax	*/
# endif
#endif
#ifndef	vax_asm
# define vax_asm	FALSE
#endif

#ifdef pdp11
# define BITS	12	/* max bits/code for 16-bit machine		*/
# define USERMEM 0	/* Force no user memory				*/
# define UCHAR	FALSE	/* TRUE if compiler supports unsigned char	*/
# define MAXIO 512	/* Buffer size for PDP-11 I/O buffers		*/
#endif

/*
 * Set default values for some parameters.
 */

#ifndef DEBUG
# define DEBUG	FALSE
#endif

#ifdef interdata
# define SIGNED_COMPARE_SLOW TRUE
#endif
#ifndef SIGNED_COMPARE_SLOW
# define SIGNED_COMPARE_SLOW FALSE
#endif

#ifndef USERMEM
# define USERMEM 750000	/* default user memory				*/
#endif

#ifndef	UCHAR
# define UCHAR	TRUE	/* Compiler supports unsigned char		*/
#endif

#ifndef MAXIO
# define MAXIO	2048	/* I/O buffer size				*/
#endif

/*
 * Set derived tuning parameters.
 */

#ifndef USERMEM
# define USERMEM	 0
#endif
#if USERMEM >=			(433484 + SACREDMEM)
# define PBITS		16
#else
# if USERMEM >=			(229600 + SACREDMEM)
#  define PBITS		15
# else
#  if USERMEM >=		(127536 + SACREDMEM)
#   define PBITS	14
#   else
#    if USERMEM >=		( 73464 + SACREDMEM)
#     define PBITS	13
#    else			/* Smaller systems			*/
#     define PBITS	12
#    endif
#   endif
# endif
#endif

#ifndef BITS
# define BITS PBITS
#endif

#ifdef M_XENIX
# if BITS >= 16
#  define XENIX_16		/* Enable special vector access macros	*/
# else
#  if BITS > 13
#   undef BITS
#   define BITS 13		/* Code only handles BITS = 12, 13, 16	*/
#  endif
# endif
#endif

/*
 * HSIZE is the size of the hash lookup table.  It is set to
 * 1 << BITS + fudge factor, rounded up to a prime number.
 * If it is too big, the "clear the hash" routine will take
 * too long.  The same numbers are replicated in the getsize()
 * routine's data table.
 */

#if BITS == 16
# define HSIZE	69001		/* 95% occupancy			*/
#endif
#if BITS == 15
# define HSIZE	35023		/* 94% occupancy			*/
#endif
#if BITS == 14
# define HSIZE	18013		/* 91% occupancy			*/
#endif
#if BITS == 13
# define HSIZE	 9001		/* 91% occupancy			*/
#endif
#if BITS <= 12
# define HSIZE	 5003		/* 80% occupancy			*/
#endif

/*
 * typedef's -- somewhat machine specific.
 */

/*
 * a code_int must be able to hold 2**BITS values of type int, and also -1
 */
#if BITS > 15
typedef long int	code_int;
#else
typedef int		code_int;
#endif

/*
 * A count_int must hold ((2**BITS)-1) + (255<<BITS)) and -1.
 *
 * count_int's also hold counters.
 *
 * count_short's hold small counters (for the interdata)
 *
 * Some implementations don't support unsigned char (Decus C, for example)
 * Decus C is also brain damaged with regards to unsigned shorts.
 */
#if SIGNED_COMPARE_SLOW
typedef unsigned long int count_int;
typedef unsigned short int count_short;
#else
typedef long int	count_int;
#endif

#if UCHAR
typedef	unsigned char	char_type;
#else
typedef char		char_type;
#endif

#ifdef decus
typedef unsigned	U_short;
#define	readonly			/* Dummy out readonly modifier	*/
#else
typedef unsigned short	U_short;
#endif

#ifdef unix
#define	readonly
#endif

typedef short		flag;		/* Boolean flag or parameter	*/

/*
 * The following define the "magic cookie" header
 */
#define	HEAD1_MAGIC	0x1F
#define HEAD2_MAGIC	0x9D
#define	VMS_HEAD2_MAGIC	0x9E		/* vms-private output format	*/

/*
 * Defines for third byte of header
 */
#define BIT_MASK	0x1F		/* Gets NBITS in the code	*/
#define BLOCK_MASK	0x80		/* Gets block_compress flag	*/
/*
 * Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
 * a fourth header byte (for expansion).
 */

/*
 * This is for backwards compatibilty with an old version of Unix compress.
 */
#ifdef COMPATIBLE			/* Compatible, but wrong!	*/
# define MAXCODE(n_bits)	(1 << (n_bits) - 1)
#else
# define MAXCODE(n_bits)	((1 << (n_bits)) - 1)
#endif

#define INIT_BITS 9			/* initial number of bits/code */

/*
 * One code could conceivably represent (1<<BITS) characters, but
 * to get a code of length N requires an input string of at least
 * N*(N-1)/2 characters.  With 5000 chars in the stack, an input
 * file would have to contain a 25Mb string of a single character.
 * This seems unlikely.
 */
#define MAXSTACK    8000		/* size of lzdcmp output stack	*/

#ifndef CHECK_GAP
# define CHECK_GAP 	10000		/* ratio check interval		*/
#endif

#ifndef __LINE__
# define NO__LINE__
#endif
#ifndef __FILE__
# define NO__LINE__
#endif
#if DEBUG
# define VERBOSE_DEFAULT    1
# ifndef NO__LINE__
#  define FAIL(why)					\
	fprintf(stderr, "\nfatal: %s (%s at %d)\n",	\
	    why, __FILE__, __LINE__); 			\
	longjmp(failure, 1);
# else
#  define FAIL(why)					\
	fprintf(stderr, "\nfatal: %s\n", why); 		\
	longjmp(failure, 1);
# endif
#else
# define VERBOSE_DEFAULT    0
# define FAIL(why)	longjmp(failure, 1);
#endif

/*
 * Note -- for compatibility with Unix compress,
 * NBR_CHAR and LZ_CLEAR must equal 256.
 * Also, (1 << (MIN_BITS - 1) should equal or exceed NBR_CHR
 */
#define	NBR_CHAR      256		/* Number of input codes	*/
#define MIN_BITS	9		/* Smallest code is 9 bits	*/
#if ((1 << BITS) < NBR_CHAR) || (BITS < MIN_BITS)
    << Can't compile: not enough bits for the input character set size >>
#endif
#define	LZ_CLEAR	(NBR_CHAR)	/* Clear code			*/
#define	LZ_SOH		(LZ_CLEAR + 1)	/* Start of header block	*/
#define	LZ_STX		(LZ_SOH   + 1)	/* Start of text block		*/
#define	LZ_EOR		(LZ_STX   + 1)	/* End of text record		*/
#define	LZ_ETX		(LZ_EOR   + 1)	/* End of header/text block	*/
#define	LZ_FIRST	(LZ_ETX   + 1)	/* First user (data) code	*/

#ifdef	vms
#include		errno
#include		ssdef
#include		stsdef
#define	IO_SUCCESS	(SS$_NORMAL | STS$M_INHIB_MSG)
#define	IO_ERROR	(SS$_ABORT)
#define VMS_V4		L_cuserid >= 16		/* Enable new stuff	*/
#else
#define VMS_V4		0			/* Disable new stuff	*/
extern int		errno;
#ifdef decus
#define	errno		$$ferr
#endif
#endif

/*
 * Define exit() codes.
 */

#ifndef	IO_SUCCESS
#define	IO_SUCCESS	0			/* Normal exit		*/
#define	IO_ERROR	1			/* Error exit		*/
#endif

/*
 * All I/O is done by way of "streams".  To establish a stream,
 * set the parameters appropriately and off you go.  The following
 * functions are provided:
 *	lz_fill(stream)		fills the buffer from stdin
 *	lz_flush(stream)	writes the buffer to stdout
 *	lz_eof(stream)		returns EOF (for fill from memory)
 *	lz_fail(stream)		abort (for writing to memory).
 *	lz_dummy(stream)	throw an output stream away.
 * Note: if VMS_V4 is enabled and the private (non-export) format
 * chosen, lz_fill and lz_flush access the files appropriately.
 * Stream elements are initialized as follows:
 *	Input:	bp = NULL;	bend = NULL;
 *	Output:	bp = bstart;	bend = bstart + bsize;
 */

typedef struct STREAM {
    char_type	*bp;		/* Next character to get/put		*/
    char_type	*bend;		/* -> end of stream buffer		*/
    char_type	*bstart;	/* Start of stream buffer		*/
    short	bsize;		/* Stream buffer size			*/
    int		(*func)();	/* Read/write a buffer function		*/
} STREAM;

/*
 * Note also that the compress routine uses putbuf(buf, count, outstream)
 * and the decompress routine uses getbuf(buf, count, instream) to (quickly)
 * transfer multiple bytes.
 */
#if UCHAR
#define	GET(s)		\
	(((s)->bp < (s)->bend) ? *(s)->bp++        : (*(s)->func)(s))
#else
#define	GET(s)		\
	(((s)->bp < (s)->bend) ? *(s)->bp++ & 0xFF : (*(s)->func)(s))
#endif
#define	PUT(c, s)	\
	((((s)->bp >= (s)->bend) ? (*(s)->func)(s) : 0), *(s)->bp++ = (c))

extern int lz_fill();
extern int lz_flush();
extern int lz_eof();
extern int lz_fail();
extern int lz_dummy();

#if DEBUG
extern readonly char *lz_names[];		/* "LZ_CLEAR" etc.	*/
#endif

/*
 * Options and globals.
 */
#if VMS_V4
#define	ATT_NAME	"vms$attributes "
#define	ATT_SIZE	15			/* strlen(ATT_NAME)	*/
extern int	fdl_status;	/* Error code from fdl library		*/
#endif

extern flag	binary;		/* -b Readable text file if FALSE	*/
extern flag	noheader;	/* -x3 No magic header if TRUE		*/
extern flag	export;		/* -x  (non-zero) Supress vms private	*/
extern flag	block_compress;	/* -x2					*/
extern flag	verbose;	/* -v  (non-zero) Verbose logging	*/
extern readonly flag is_compress; /* TRUE if compress, FALSE if decomp.	*/
extern char	*infilename;	/* For error printouts			*/
extern char	*outfilename;	/* For more error printouts		*/
extern short	n_bits;		/* Current # of bits in compressed file	*/
extern int	firstcode;	/* First value past signals		*/
extern jmp_buf	failure;	/* For longjmp() return			*/

