[alt.sources] ARC 5.20 w/Squashing, 8/9

hyc@umix.cc.umich.edu (Howard Chu) (04/14/88)

XX		 * Generate output characters in reverse order 
XX		 */
XX		while (code >= 256) {
XX			*stackp++ = suffix[code];
XX			code = prefix[code];
XX		}
XX		*stackp++ = finchar = suffix[code];
XX
XX		/*
XX		 * And put them out in forward order 
XX		 */
XX		do
XX			putc_unp(*--stackp, t);
XX		while (stackp > stack);
XX
XX		/*
XX		 * Generate the new entry. 
XX		 */
XX		if ((code = free_ent) < maxcodemax) {
XX			prefix[code] = (unsigned short) oldcode;
XX			suffix[code] = finchar;
XX			free_ent = code + 1;
XX		}
XX		/*
XX		 * Remember previous code. 
XX		 */
XX		oldcode = incode;
XX	}
XX}
SHAR_EOF
if test 11224 -ne "`wc -c arcsqs.c`"
then
echo shar: error transmitting arcsqs.c '(should have been 11224 characters)'
fi
echo shar: extracting arcsvc.c '(5470 characters)'
sed 's/^XX//' << \SHAR_EOF > arcsvc.c
XX/*
XX * $Log:	arcsvc.c,v $
XX * Revision 1.2  88/04/11  18:42:09  hyc
XX * re-synch with MTS...
XX * 
XX * Revision 1.1  88/04/11  18:39:02  hyc
XX * Initial revision
XX * 
XX * Revision 1.2  87/12/19  04:28:54  hyc
XX * fixing indent problems
XX * 
XX * Revision 1.1  87/12/19  04:27:04  hyc
XX * Initial revision
XX * 
XX * Revision 1.4  87/08/13  17:05:58  hyc
XX * Run thru indent, fixed some signed vs. unsigned problems
XX * with bp <-> buf, and inbuf and localbuf...
XX *  Revision 1.3  87/07/21  11:42:06  hyc *** empty
XX * log message ***
XX * 
XX * Revision 1.2  87/07/21  09:22:03  hyc *** empty log message ***
XX * 
XX */
XX
XX/*
XX * ARC - Archive utility - ARCSVC
XX * 
XX * Version 2.20, created on 10/24/86 at 12:17:00
XX * 
XX * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
XX * 
XX * By:  Thom Henderson
XX * 
XX * Description: This file contains service routines needed to maintain an
XX * archive.
XX * 
XX * Language: Computer Innovations Optimizing C86
XX */
XX#include <stdio.h>
XX#include "arc.h"
XX
XXINT
XXopenarc(chg)			/* open archive */
XX	INT             chg;	/* true to open for changes */
XX{
XX	FILE           *fopen();/* file opener */
XX
XX	if (!(arc = fopen(arcname, "rb"))) {
XX		if (chg)
XX			printf("Creating new archive: %s\n", arcname);
XX		else
XX			abort("Archive not found: %s", arcname);
XX	}
XX	if (chg) {		/* if opening for changes */
XX		if (!(new = fopen(newname, "wb")))
XX			abort("Cannot create archive copy: %s", newname);
XX	}
XX}
XX
XXINT
XXclosearc(chg)			/* close an archive */
XX	INT             chg;	/* true if archive was changed */
XX{
XX	if (arc) {		/* if we had an initial archive */
XX		if (kludge)	/* kludge to update timestamp */
XX			setstamp(arc, olddate, oldtime);
XX		fclose(arc);	/* then close it */
XX	}
XX	if (chg) {		/* if things have changed */
XX#ifdef MSDOS
XX		setstamp(new, arcdate, arctime);
XX#endif
XX		fclose(new);	/* close the new copy */
XX#ifdef BSD
XX		setstamp(newname, arcdate, arctime);
XX#endif
XX
XX		if (arc) {	/* if we had an original archive */
XX			if (keepbak) {	/* if a backup is wanted */
XX#ifdef BSD
XX				char           *buf;
XX				buf = (char *) malloc((5 + strlen(arcname) + strlen(bakname)) * sizeof(char));
XX				*buf = '\0';
XX				strcat(buf, "mv ");
XX				strcat(buf, arcname);
XX				strcat(buf, " ");
XX				strcat(buf, bakname);
XX				if (system(buf))
XX#else
XX				unlink(bakname);	/* erase any old copies */
XX				if (rename(arcname, bakname))
XX#endif
XX					abort("Cannot rename %s to %s", arcname, bakname);
XX				printf("Keeping backup archive: %s\n", bakname);
XX#ifdef BSD
XX				free(buf);
XX#endif
XX			} else if (unlink(arcname))
XX				abort("Cannot delete old archive: %s", arcname);
XX		}
XX#ifdef BSD
XX		{
XX			char           *buf;
XX			buf = (char *) malloc((5 + strlen(newname) + strlen(arcname)) * sizeof(char));
XX			*buf = '\0';
XX			strcat(buf, "mv ");
XX			strcat(buf, newname);
XX			strcat(buf, " ");
XX			strcat(buf, arcname);
XX			if (system(buf))
XX#else
XX		if (rename(newname, arcname))
XX#endif
XX			abort("Cannot rename %s to %s", newname, arcname);
XX#ifdef BSD
XX		free(buf);
XX	}
XX#endif
XX}
XX}
XX
XX/*
XX * CRC computation logic
XX * 
XX * The logic for this method of calculating the CRC 16 bit polynomial is taken
XX * from an article by David Schwaderer in the April 1985 issue of PC Tech
XX * Journal.
XX */
XX
XXstatic INT      crctab[] =	/* CRC lookup table */
XX{
XX 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
XX 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
XX 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
XX 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
XX 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
XX 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
XX 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
XX 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
XX 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
XX 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
XX 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
XX 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
XX 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
XX 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
XX 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
XX 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
XX 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
XX 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
XX 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
XX 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
XX 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
XX 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
XX 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
XX 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
XX 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
XX 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
XX 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
XX 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
XX 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
XX 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
XX 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
XX 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
XX};
XX
XXINT
XXaddcrc(crc, c)			/* update a CRC check */
XX	INT             crc;	/* running CRC value */
XX	unsigned char   c;	/* character to add */
XX{
XX	return ((crc >> 8) & 0x00ff) ^ crctab[(crc ^ c) & 0x00ff];
XX}
SHAR_EOF
if test 5470 -ne "`wc -c arcsvc.c`"
then
echo shar: error transmitting arcsvc.c '(should have been 5470 characters)'
fi
echo shar: extracting arctst.c '(1437 characters)'
sed 's/^XX//' << \SHAR_EOF > arctst.c
XX/*
XX * $Log:        arctst.c,v $
XX * Revision 1.3  87/08/13  17:06:06  hyc
XX * Run thru indent, fixed some signed vs. unsigned problems
XX * with bp <-> buf, and inbuf and localbuf...
XX *  Revision 1.2  87/07/21  09:24:37  hyc *** empty
XX * log message ***
XX * 
XX */
XX
XX/*
XX * ARC - Archive utility - ARCTST
XX * 
XX * Version 2.12, created on 02/03/86 at 23:00:40
XX * 
XX * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
XX * 
XX * By:  Thom Henderson
XX * 
XX * Description: This file contains the routines used to test archive integrity.
XX * 
XX * Language: Computer Innovations Optimizing C86
XX */
XX#include <stdio.h>
XX#include "arc.h"
XX
XXINT
XXtstarc()
XX{				/* test integrity of an archive */
XX	struct heads    hdr;	/* file header */
XX	LONG            arcsize, ftell();	/* archive size */
XX
XX	openarc(0);		/* open archive for reading */
XX	fseek(arc, 0L, 2);	/* move to end of archive */
XX	arcsize = ftell(arc);	/* see how big it is */
XX	fseek(arc, 0L, 0);	/* return to top of archive */
XX
XX	while (readhdr(&hdr, arc)) {
XX		if (ftell(arc) + hdr.size > arcsize) {
XX			printf("Archive truncated in file %s\n", hdr.name);
XX			nerrs++;
XX			break;
XX		} else {
XX			printf("Testing file: %-12s  ", hdr.name);
XX			fflush(stdout);
XX			if (unpack(arc, NULL, &hdr))
XX				nerrs++;
XX			else
XX				printf("okay\n");
XX		}
XX	}
XX
XX	if (nerrs < 1)
XX		printf("No errors detected\n");
XX	else if (nerrs == 1)
XX		printf("One error detected\n");
XX	else
XX		printf("%d errors detected\n", nerrs);
XX}
SHAR_EOF
if test 1437 -ne "`wc -c arctst.c`"
then
echo shar: error transmitting arctst.c '(should have been 1437 characters)'
fi
echo shar: extracting arcunp.c '(5622 characters)'
sed 's/^XX//' << \SHAR_EOF > arcunp.c
XX/*
XX * $Log:	arcunp.c,v $
XX * Revision 1.1  88/04/11  18:42:39  hyc
XX * Initial revision
XX * 
XX * Revision 1.3  87/12/20  03:10:14  hyc
XX * Ah hah! The value fgetc was returning was getting sign extended!
XX * Thus, 0xff was indistinguishable from EOF, causing the premature
XX * termination... The solution is to use getc, which doesn't do this
XX * (on the Apollos, anyway...)
XX * 
XX * Note that I could *not* duplicate this behavior in a 5 liner...?
XX * 
XX * Revision 1.2  87/12/19  04:11:22  hyc
XX * Move image mode code around from MTS only to non-MSDOS.
XX * 
XX * Revision 1.1  87/12/19  04:06:39  hyc
XX * Initial revision
XX * 
XX * Revision 1.3  87/08/13  17:06:08  hyc
XX * Run thru indent, fixed some signed vs. unsigned problems
XX * with bp <-> buf, and inbuf and localbuf...
XX *  Revision 1.2  87/07/21  09:28:31  hyc *** empty
XX * log message ***
XX * 
XX */
XX
XX/*
XX * ARC - Archive utility - ARCUNP
XX * 
XX * Version 3.17, created on 02/13/86 at 10:20:08
XX * 
XX * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
XX * 
XX * By:  Thom Henderson
XX * 
XX * Description: This file contains the routines used to expand a file when
XX * taking it out of an archive.
XX * 
XX * Language: Computer Innovations Optimizing C86
XX */
XX#include <stdio.h>
XX#include "arc.h"
XX
XX/* stuff for repeat unpacking */
XX
XX#define DLE 0x90		/* repeat byte flag */
XX
XXstatic INT      state;		/* repeat unpacking state */
XX
XX/* repeat unpacking states */
XX
XX#define NOHIST 0		/* no relevant history */
XX#define INREP 1			/* sending a repeated value */
XX
XXstatic INT      crcval;		/* CRC check value */
XXstatic LONG     size;		/* bytes to read */
XX
XXINT
XXunpack(f, t, hdr)		/* unpack an archive entry */
XX	FILE           *f, *t;	/* source, destination */
XX	struct heads   *hdr;	/* pointer to file header data */
XX{
XX	INT             c;	/* one char of stream */
XX	INT             putc_unp();
XX	INT             putc_ncr();
XX	INT             getc_unp();
XX
XX	/* setups common to all methods */
XX
XX	crcval = 0;		/* reset CRC check value */
XX	size = hdr->size;	/* set input byte counter */
XX	state = NOHIST;		/* initial repeat unpacking state */
XX	setcode();		/* set up for decoding */
XX
XX	/* use whatever method is appropriate */
XX
XX	switch (hdrver) {	/* choose proper unpack method */
XX	case 1:		/* standard packing */
XX	case 2:
XX		while ((c = getc_unp(f)) != EOF)
XX			putc_unp(c, t);
XX		break;
XX
XX	case 3:		/* non-repeat packing */
XX		while ((c = getc_unp(f)) != EOF)
XX			putc_ncr(c, t);
XX		break;
XX
XX	case 4:		/* Huffman squeezing */
XX		init_usq(f);
XX		while ((c = getc_usq(f)) != EOF)
XX			putc_ncr(c, t);
XX		break;
XX
XX	case 5:		/* Lempel-Zev compression */
XX		init_ucr(0);
XX		while ((c = getc_ucr(f)) != EOF)
XX			putc_unp(c, t);
XX		break;
XX
XX	case 6:		/* Lempel-Zev plus non-repeat */
XX		init_ucr(0);
XX		while ((c = getc_ucr(f)) != EOF)
XX			putc_ncr(c, t);
XX		break;
XX
XX	case 7:		/* L-Z plus ncr with new hash */
XX		init_ucr(1);
XX		while ((c = getc_ucr(f)) != EOF)
XX			putc_ncr(c, t);
XX		break;
XX
XX	case 8:		/* dynamic Lempel-Zev */
XX		decomp(f, t);
XX		break;
XX
XX	case 9:		/* Squashing */
XX		sqdecomp(f, t);
XX		break;
XX
XX	default:		/* unknown method */
XX		if (warn) {
XX			printf("I don't know how to unpack file %s\n", hdr->name);
XX			printf("I think you need a newer version of ARC\n");
XX			nerrs++;
XX		}
XX		fseek(f, hdr->size, 1);	/* skip over bad file */
XX		return 1;	/* note defective file */
XX	}
XX
XX	/* cleanups common to all methods */
XX
XX	if (crcval != hdr->crc) {
XX		if (warn || kludge) {
XX			printf("WARNING: File %s fails CRC check\n", hdr->name);
XX			nerrs++;
XX		}
XX		return 1;	/* note defective file */
XX	}
XX	return 0;		/* file is okay */
XX}
XX
XX/*
XX * This routine is used to put bytes in the output file.  It also performs
XX * various housekeeping functions, such as maintaining the CRC check value.
XX */
XX
XXINT
XXputc_unp(c, t)			/* output an unpacked byte */
XX	char            c;	/* byte to output */
XX	FILE           *t;	/* file to output to */
XX{
XX	crcval = addcrc(crcval, c);	/* update the CRC check value */
XX#ifdef	MTS
XX	if (!image)
XX		atoe(&c, 1);
XX#endif
XX#ifndef MSDOS
XX	if ((c != '\r') || image)
XX#endif
XX		putc_tst(c, t);
XX}
XX
XX/*
XX * This routine is used to decode non-repeat compression.  Bytes are passed
XX * one at a time in coded format, and are written out uncoded. The data is
XX * stored normally, except that runs of more than two characters are
XX * represented as:
XX * 
XX * <char> <DLE> <count>
XX * 
XX * With a special case that a count of zero indicates a DLE as data, not as a
XX * repeat marker.
XX */
XX
XXINT
XXputc_ncr(c, t)			/* put NCR coded bytes */
XX	unsigned char   c;	/* next byte of stream */
XX	FILE           *t;	/* file to receive data */
XX{
XX	static INT      lastc;	/* last character seen */
XX
XX	switch (state) {	/* action depends on our state */
XX	case NOHIST:		/* no previous history */
XX		if (c == DLE)	/* if starting a series */
XX			state = INREP;	/* then remember it next time */
XX		else
XX			putc_unp(lastc = c, t);	/* else nothing unusual */
XX		return;
XX
XX	case INREP:		/* in a repeat */
XX		if (c)		/* if count is nonzero */
XX			while (--c)	/* then repeatedly ... */
XX				putc_unp(lastc, t);	/* ... output the byte */
XX		else
XX			putc_unp(DLE, t);	/* else output DLE as data */
XX		state = NOHIST;	/* back to no history */
XX		return;
XX
XX	default:
XX		abort("Bad NCR unpacking state (%d)", state);
XX	}
XX}
XX
XX/*
XX * This routine provides low-level byte input from an archive.  This routine
XX * MUST be used, as end-of-file is simulated at the end of the archive entry.
XX */
XX
XXINT
XXgetc_unp(f)			/* get a byte from an archive */
XX	FILE           *f;	/* archive file to read */
XX{
XX	register INT    xx;
XX	if (!size)		/* if no data left */
XX		return EOF;	/* then pretend end of file */
XX
XX	size--;			/* deduct from input counter */
XX	xx = getc(f);
XX	return code(xx);	/* and return next decoded byte */
XX}
SHAR_EOF
if test 5622 -ne "`wc -c arcunp.c`"
then
echo shar: error transmitting arcunp.c '(should have been 5622 characters)'
fi
echo shar: extracting arcusq.c '(2678 characters)'
sed 's/^XX//' << \SHAR_EOF > arcusq.c
XX/*
XX * $Log:	arcusq.c,v $
XX * Revision 1.1  88/04/11  18:45:37  hyc
XX * Initial revision
XX * 
XX * Revision 1.3  87/08/13  17:06:12  hyc
XX * Run thru indent, fixed some signed vs. unsigned problems
XX * with bp <-> buf, and inbuf and localbuf...
XX *  Revision 1.2  87/07/21  09:31:43  hyc *** empty
XX * log message ***
XX * 
XX */
XX
XX/*
XX * ARC - Archive utility - ARCUSQ
XX * 
XX * Version 3.14, created on 07/25/86 at 13:04:19
XX * 
XX * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
XX * 
XX * By:  Thom Henderson
XX * 
XX * Description: This file contains the routines used to expand a file which was
XX * packed using Huffman squeezing.
XX * 
XX * Most of this code is taken from an USQ program by Richard Greenlaw, which was
XX * adapted to CI-C86 by Robert J. Beilstein.
XX * 
XX * Language: Computer Innovations Optimizing C86
XX */
XX#include <stdio.h>
XX#include "arc.h"
XX
XX/* stuff for Huffman unsqueezing */
XX
XX#define ERROR (-1)
XX
XX#define SPEOF 256		/* special endfile token */
XX#define NUMVALS 257		/* 256 data values plus SPEOF */
XX
XXstruct nd {			/* decoding tree */
XX	INT             child[2];	/* left, right */
XX}               node[NUMVALS];	/* use large buffer */
XX
XXstatic INT      bpos;		/* last bit position read */
XXstatic INT      curin;		/* last byte value read */
XXstatic INT      numnodes;	/* number of nodes in decode tree */
XX
XXstatic          INT
XXget_int(f)			/* get an integer */
XX	FILE           *f;	/* file to get it from */
XX{
XX	return (getc_unp(f) | (getc_unp(f) << 8)) & 0xFFFF;
XX}
XX
XXINT
XXinit_usq(f)			/* initialize Huffman unsqueezing */
XX	FILE           *f;	/* file containing squeezed data */
XX{
XX	INT             i;	/* node index */
XX
XX	bpos = 99;		/* force initial read */
XX
XX	numnodes = get_int(f);
XX
XX	if (numnodes < 0 || numnodes >= NUMVALS)
XX		abort("File has an invalid decode tree");
XX
XX	/* initialize for possible empty tree (SPEOF only) */
XX
XX	node[0].child[0] = -(SPEOF + 1);
XX	node[0].child[1] = -(SPEOF + 1);
XX
XX	for (i = 0; i < numnodes; ++i) {	/* get decoding tree from
XX						 * file */
XX		node[i].child[0] = get_int(f);
XX		node[i].child[1] = get_int(f);
XX	}
XX}
XX
XXint
XXgetc_usq(f)			/* get byte from squeezed file */
XX	FILE           *f;	/* file containing squeezed data */
XX{
XX	int             i;	/* tree index */
XX
XX	/* follow bit stream in tree to a leaf */
XX
XX	for (i = 0; i >= 0;) {	/* work down(up?) from root */
XX		if (++bpos > 7) {
XX			if ((curin = getc_unp(f)) == ERROR)
XX				return (ERROR);
XX			bpos = 0;
XX
XX			/* move a level deeper in tree */
XX			i = node[i].child[1 & curin];
XX		} else
XX			i = node[i].child[1 & (curin >>= 1)];
XX	}
XX
XX	/* decode fake node index to original data value */
XX
XX	i = -(i + 1);
XX
XX	/* decode special endfile token to normal EOF */
XX
XX	i = (i == SPEOF) ? EOF : i;
XX	return i;
XX}
SHAR_EOF
if test 2678 -ne "`wc -c arcusq.c`"
then
echo shar: error transmitting arcusq.c '(should have been 2678 characters)'
fi
echo shar: extracting dtime.c '(9035 characters)'
sed 's/^XX//' << \SHAR_EOF > dtime.c
XX/* dtime.c - routines to do ``ARPA-style'' time structures
XX
XXver  date   who remarks
XX--- ------- --- -------------------------------------------------------------
XX01B 15nov86 JP  Thouroughly hacked by Jef Poskanzer.
XX01A ??????? MTR Original version from the MH 6.5 distribution, courtesy
XX	          of Marshall Rose.
XX
XX*/
XX
XX
XX#include "tws.h"
XX#include <stdio.h>
XX#include <sys/types.h>
XX#include <time.h>
XX#ifdef  SYS5
XX#include <string.h>
XX#else SYS5
XX#include <strings.h>
XX#include <sys/timeb.h>
XX#endif SYS5
XX
XX#ifdef	SYS5
XXextern int  daylight;
XXextern long timezone;
XXextern char *tzname[];
XX#endif	SYS5
XX
XX/*  */
XX
XX#define	abs(a) ( a >= 0 ? a : -a )
XX
XXchar *tw_moty[] = {
XX    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
XX    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
XX
XXchar *tw_dotw[] = {
XX    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL };
XX
XXchar *tw_ldotw[] = {
XX    "Sunday", "Monday", "Tuesday", "Wednesday",
XX    "Thursday", "Friday", "Saturday", NULL };
XX
XX/*  */
XX
XXstatic struct zone
XX    {
XX    char *std;
XX    char *dst;
XX    int shift;
XX    }
XX    zones[] = {
XX	"GMT", "BST", 0,
XX	"EST", "EDT", -5,
XX	"CST", "CDT", -6,
XX	"MST", NULL, -7,
XX	"PST", "PDT", -8,
XX	"A", NULL, -1,
XX	"B", NULL, -2,
XX	"C", NULL, -3,
XX	"D", NULL, -4,
XX	"E", NULL, -5,
XX	"F", NULL, -6,
XX	"G", NULL, -7,
XX	"H", NULL, -8,
XX	"I", NULL, -9,
XX	"K", NULL, -10,
XX	"L", NULL, -11,
XX	"M", NULL, -12,
XX	"N", NULL, 1,
XX#ifndef	HUJI
XX	"O", NULL, 2,
XX#else	HUJI
XX	"JST", "JDT", 2,
XX#endif	HUJI
XX	"P", NULL, 3,
XX	"Q", NULL, 4,
XX	"R", NULL, 5,
XX	"S", NULL, 6,
XX	"T", NULL, 7,
XX	"U", NULL, 8,
XX	"V", NULL, 9,
XX	"W", NULL, 10,
XX	"X", NULL, 11,
XX	"Y", NULL, 12,
XX	NULL };
XX
XX#define CENTURY 19
XX
XXlong time( );
XXstruct tm *localtime( );
XX
XX/*  */
XX
XXchar *dtimenow( )
XX    {
XX    long clock;
XX
XX    (void) time( &clock );
XX    return ( dtime( &clock ) );
XX    }
XX
XX
XXchar *
XXdctime( tw )
XXstruct tws *tw;
XX    {
XX    static char buffer[25];
XX
XX    if ( tw == NULL )
XX	return ( NULL );
XX
XX    (void) sprintf( buffer, "%.3s %.3s %02d %02d:%02d:%02d %.4d\n",
XX	    tw_dotw[tw -> tw_wday], tw_moty[tw -> tw_mon], tw -> tw_mday,
XX	    tw -> tw_hour, tw -> tw_min, tw -> tw_sec,
XX	    tw -> tw_year >= 100 ? tw -> tw_year : 1900 + tw -> tw_year );
XX
XX    return ( buffer );
XX    }
XX
XX/*  */
XX
XXstruct tws *
XXdtwstime( )
XX    {
XX    long clock;
XX
XX    (void) time( &clock );
XX    return ( dlocaltime( &clock ) );
XX    }
XX
XX
XXstruct tws *
XXdlocaltime( clock )
XXlong *clock;
XX    {
XX    register struct tm *tm;
XX#ifndef SYS5
XX    struct timeb tb;
XX#endif not SYS5
XX    static struct tws tw;
XX
XX    if ( clock == NULL )
XX	return ( NULL );
XX    tw.tw_flags = TW_NULL;
XX
XX    tm = localtime( clock );
XX    tw.tw_sec = tm -> tm_sec;
XX    tw.tw_min = tm -> tm_min;
XX    tw.tw_hour = tm -> tm_hour;
XX    tw.tw_mday = tm -> tm_mday;
XX    tw.tw_mon = tm -> tm_mon;
XX    tw.tw_year = tm -> tm_year;
XX    tw.tw_wday = tm -> tm_wday;
XX    tw.tw_yday = tm -> tm_yday;
XX    if ( tm -> tm_isdst )
XX	tw.tw_flags |= TW_DST;
XX#ifndef  SYS5
XX    ftime( &tb );
XX    tw.tw_zone = -tb.timezone;
XX#else   SYS5
XX    tzset( );
XX    tw.tw_zone = -(timezone / 60);
XX#endif  SYS5
XX    tw.tw_flags &= ~TW_SDAY;
XX    tw.tw_flags |= TW_SEXP;
XX    tw.tw_clock = *clock;
XX
XX    return ( &tw );
XX    }
XX
XX
XXstruct tws *
XXdgmtime( clock )
XXlong *clock;
XX    {
XX    register struct tm *tm;
XX    static struct tws tw;
XX
XX    if ( clock == NULL )
XX	return ( NULL );
XX    tw.tw_flags = TW_NULL;
XX
XX    tm = gmtime( clock );
XX    tw.tw_sec = tm -> tm_sec;
XX    tw.tw_min = tm -> tm_min;
XX    tw.tw_hour = tm -> tm_hour;
XX    tw.tw_mday = tm -> tm_mday;
XX    tw.tw_mon = tm -> tm_mon;
XX    tw.tw_year = tm -> tm_year;
XX    tw.tw_wday = tm -> tm_wday;
XX    tw.tw_yday = tm -> tm_yday;
XX    if ( tm -> tm_isdst )
XX	tw.tw_flags |= TW_DST;
XX    tw.tw_zone = 0;
XX    tw.tw_flags &= ~TW_SDAY;
XX    tw.tw_flags |= TW_SEXP;
XX    tw.tw_clock = *clock;
XX
XX    return( &tw );
XX    }
XX
XX/*  */
XX
XXchar *
XXdasctime( tw, flags )
XXstruct tws *tw;
XXint flags;
XX    {
XX    static char buffer[80], result[80];
XX
XX    if ( tw == NULL )
XX	return ( NULL );
XX
XX    (void) sprintf( buffer, "%02d %s %02d %02d:%02d:%02d %s",
XX	    tw -> tw_mday, tw_moty[tw -> tw_mon], tw -> tw_year,
XX	    tw -> tw_hour, tw -> tw_min, tw -> tw_sec,
XX	    dtimezone( tw -> tw_zone, tw -> tw_flags | flags ) );
XX
XX    if ( (tw -> tw_flags & TW_SDAY) == TW_SEXP )
XX	(void) sprintf( result, "%s, %s", tw_dotw[tw -> tw_wday], buffer );
XX    else
XX	if ( (tw -> tw_flags & TW_SDAY) == TW_SNIL )
XX	    (void) strcpy( result, buffer );
XX	else
XX	    (void) sprintf( result, "%s (%s)", buffer, tw_dotw[tw -> tw_wday] );
XX
XX    return ( result );
XX    }
XX
XX/*  */
XX
XXchar *
XXdtimezone( offset, flags )
XXint offset, flags;
XX    {
XX    register int hours, mins;
XX    register struct zone *z;
XX    static char buffer[10];
XX
XX    if ( offset < 0 )
XX	{
XX	mins = -((-offset) % 60);
XX	hours = -((-offset) / 60);
XX	}
XX    else
XX	{
XX	mins = offset % 60;
XX	hours = offset / 60;
XX	}
XX
XX    if ( !(flags & TW_ZONE) && mins == 0 )
XX	for ( z = zones; z -> std; z++ )
XX	    if ( z -> shift == hours )
XX		return ( z -> dst && (flags & TW_DST) ? z -> dst : z -> std );
XX
XX#ifdef	DSTXXX
XX    if ( flags & TW_DST )
XX	hours += 1;
XX#endif	DSTXXX
XX    (void) sprintf( buffer, "%s%02d%02d",
XX	    offset < 0 ? "-" : "+", abs( hours ), abs( mins ) );
XX    return ( buffer );
XX    }
XX
XX/*  */
XX
XXvoid
XXtwscopy( tb, tw )
XXstruct tws *tb, *tw;
XX    {
XX#ifdef	notdef
XX    tb -> tw_sec = tw -> tw_sec;
XX    tb -> tw_min = tw -> tw_min;
XX    tb -> tw_hour = tw -> tw_hour;
XX    tb -> tw_mday = tw -> tw_mday;
XX    tb -> tw_mon = tw -> tw_mon;
XX    tb -> tw_year = tw -> tw_year;
XX    tb -> tw_wday = tw -> tw_wday;
XX    tb -> tw_yday = tw -> tw_yday;
XX    tb -> tw_zone = tw -> tw_zone;
XX    tb -> tw_clock = tw -> tw_clock;
XX    tb -> tw_flags = tw -> tw_flags;
XX#else	not notdef
XX    *tb = *tw;
XX#endif	not notdef
XX    }
XX
XX
XXint
XXtwsort( tw1, tw2 )
XXstruct tws *tw1, *tw2;
XX    {
XX    register long c1, c2;
XX
XX    (void) twclock( tw1 );
XX    (void) twclock( tw2 );
XX
XX    return ( (c1 = tw1 -> tw_clock) > (c2 = tw2 -> tw_clock) ? 1
XX	    : c1 == c2 ? 0 : -1 );
XX    }
XX
XX/*  */
XX
XX
XX/* Julian day number of the Unix* clock's origin, 01 Jan 1970. */
XX#define JD1970 2440587L
XX
XX
XXlong
XXtwjuliandate( tw )
XXstruct tws *tw;
XX    {
XX    register int mday, mon, year;
XX    register long a, b;
XX    double jd;
XX
XX    if ( (mday = tw -> tw_mday) < 1 || mday > 31 ||
XX	    (mon = tw -> tw_mon + 1) < 1 || mon > 12 ||
XX	    (year = tw -> tw_year) < 1 || year > 10000 )
XX	return ( -1L );
XX    if ( year < 100 )
XX	year += CENTURY * 100;
XX
XX    if ( mon == 1 || mon == 2 )
XX	{
XX	--year;
XX	mon += 12;
XX	}
XX    if ( year < 1583 )
XX	return ( -1L );
XX    a = year / 100;
XX    b = 2 - a + a / 4;
XX    b += (long) ( (double) year * 365.25 );
XX    b += (long) ( 30.6001 * ( (double) mon + 1.0 ) );
XX    jd = mday + b + 1720994.5;
XX    return ( (long) jd );
XX    }
XX
XX
XXlong
XXtwsubdayclock( tw )
XXstruct tws *tw;
XX    {
XX    register int i, sec, min, hour;
XX    register long result;
XX
XX    if ( (sec = tw -> tw_sec) < 0 || sec > 59 ||
XX	    (min = tw -> tw_min) < 0 || min > 59 ||
XX	    (hour = tw -> tw_hour) < 0 || hour > 23 )
XX	return ( -1L );
XX
XX    result = ( hour * 60 + min ) * 60 + sec;
XX    result -= 60 * tw -> tw_zone;
XX    if ( tw -> tw_flags & TW_DST )
XX	result -= 60 * 60;
XX
XX    return ( result );
XX    }
XX
XX
XXlong
XXtwclock( tw )
XXstruct tws *tw;
XX    {
XX    register long jd, sdc, result;
XX
XX    if ( tw -> tw_clock != 0L )
XX	return ( tw -> tw_clock );
XX
XX    if ( ( jd = twjuliandate( tw ) ) == -1L )
XX	return ( tw -> tw_clock = -1L );
XX    if ( ( sdc = twsubdayclock( tw ) ) == -1L )
XX	return ( tw -> tw_clock = -1L );