[comp.unix.xenix] LHARC for XENIX

glenn@stsim.ocs.com (glenn ford) (03/28/90)

Here it is, I have tried posting to alt.sources and comp.sources.misc
and have failed, so since this is for SCO XENIX people only, grab it!
It should work under 386 Xenix as is, just type 'make'

Glenn Ford
BBS:  301-972-6131
HOME: 301-972-2310
UUCP: ..uunet!ocsmd!stsim


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  clharc.cs clharc.def dir_dos.c dir_os2.c lharc.c lhdir.h
#   lhio.c lhio.h lzhuf.c makefile mktemp.c pipes.c readme rename.c
# Wrapped by glenn@stsim on Tue Mar 27 19:12:19 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f clharc.cs -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"clharc.cs\"
else
echo shar: Extracting \"clharc.cs\" \(117 characters\)
sed "s/^X//" >clharc.cs <<'END_OF_clharc.cs'
X(-W1 lharc.c lhio.c dir_os2.c mktemp.c pipes.c)
X(-W1 -Ox lzhuf.c)
Xsetargv.obj
Xclharc.def
Xclharc.exe
X-as -lb -s0x2000
END_OF_clharc.cs
if test 117 -ne `wc -c <clharc.cs`; then
    echo shar: \"clharc.cs\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f clharc.def -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"clharc.def\"
else
echo shar: Extracting \"clharc.def\" \(74 characters\)
sed "s/^X//" >clharc.def <<'END_OF_clharc.def'
XNAME CLHARC WINDOWCOMPAT
XDESCRIPTION 'C-LHarc 1.00 - for MS-DOS and OS/2'
END_OF_clharc.def
if test 74 -ne `wc -c <clharc.def`; then
    echo shar: \"clharc.def\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f dir_dos.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"dir_dos.c\"
else
echo shar: Extracting \"dir_dos.c\" \(3587 characters\)
sed "s/^X//" >dir_dos.c <<'END_OF_dir_dos.c'
X/*
X * @(#)dir.c 1.4 87/11/06	Public Domain.
X *
X *  A public domain implementation of BSD directory routines for
X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
X *  August 1897
X *  Modified to use modern MS C library functions by Kai Uwe Rommel
X *  December 1989
X */
X
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<sys/dir.h>
X#include	<malloc.h>
X#include	<string.h>
X
X#include        <dos.h>
X
X#ifndef	NULL
X# define	NULL	0
X#endif	/* NULL */
X
X#ifndef	MAXPATHLEN
X# define	MAXPATHLEN	255
X#endif	/* MAXPATHLEN */
X
X/* attribute stuff */
X#define	A_RONLY		0x01
X#define	A_HIDDEN	0x02
X#define	A_SYSTEM	0x04
X#define	A_LABEL		0x08
X#define	A_DIR		0x10
X#define	A_ARCHIVE	0x20
X
X
X#define Newisnull(a, t) ((a = (t *) malloc(sizeof(t))) == (t *) NULL)
X
X#define ATTRIBUTES      (A_DIR)
X/* #define ATTRIBUTES      (A_DIR | A_HIDDEN | A_SYSTEM) */
X/* #define ATTRIBUTES      (A_RONLY | A_SYSTEM | A_DIR) */
X
Xstatic  char    *getdirent(char *);
Xstatic	void	free_dircontents(struct _dircontents *);
X
Xstatic struct find_t find;
X
X
XDIR	*
Xopendir(name)
X	char	*name;
X{
X	struct	stat		statb;
X	DIR			*dirp;
X	char			c;
X	char			*s;
X	struct _dircontents	*dp;
X	char			nbuf[MAXPATHLEN + 1];
X
X	if (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
X		return (DIR *) NULL;
X	if (Newisnull(dirp, DIR))
X		return (DIR *) NULL;
X	if (*name && (c = name[strlen(name) - 1]) != '\\' && c != '/')
X		(void) strcat(strcpy(nbuf, name), "\\*.*");
X	else
X		(void) strcat(strcpy(nbuf, name), "*.*");
X	dirp->dd_loc = 0;
X        dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL;
X
X	if ((s = getdirent(nbuf)) == (char *) NULL)
X		return dirp;
X	do {
X		if (Newisnull(dp, struct _dircontents) || (dp->_d_entry =
X			malloc((unsigned) (strlen(s) + 1))) == (char *) NULL)
X		{
X			if (dp)
X				free((char *) dp);
X			free_dircontents(dirp->dd_contents);
X			return (DIR *) NULL;
X		}
X		if (dirp->dd_contents)
X			dirp->dd_cp = dirp->dd_cp->_d_next = dp;
X		else
X			dirp->dd_contents = dirp->dd_cp = dp;
X		(void) strcpy(dp->_d_entry, s);
X		dp->_d_next = (struct _dircontents *) NULL;
X        } while ((s = getdirent((char *) NULL)) != (char *) NULL);
X
X	dirp->dd_cp = dirp->dd_contents;
X
X	return dirp;
X}
X
Xvoid
Xclosedir(dirp)
X	DIR	*dirp;
X{
X	free_dircontents(dirp->dd_contents);
X	free((char *) dirp);
X}
X
Xstruct direct	*
Xreaddir(dirp)
X	DIR	*dirp;
X{
X	static	struct direct	dp;
X
X	if (dirp->dd_cp == (struct _dircontents *) NULL)
X		return (struct direct *) NULL;
X	dp.d_namlen = dp.d_reclen =
X		strlen(strcpy(dp.d_name, dirp->dd_cp->_d_entry));
X	strlwr(dp.d_name);		/* JF */
X	dp.d_ino = 0;
X	dirp->dd_cp = dirp->dd_cp->_d_next;
X	dirp->dd_loc++;
X
X	return &dp;
X}
X
Xvoid
Xseekdir(dirp, off)
X	DIR	*dirp;
X	long	off;
X{
X	long			i = off;
X	struct _dircontents	*dp;
X
X	if (off < 0)
X		return;
X	for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
X		;
X	dirp->dd_loc = off - (i + 1);
X	dirp->dd_cp = dp;
X}
X
Xlong
Xtelldir(dirp)
X	DIR	*dirp;
X{
X	return dirp->dd_loc;
X}
X
Xstatic	void
Xfree_dircontents(dp)
X	struct	_dircontents	*dp;
X{
X	struct _dircontents	*odp;
X
X	while (dp) {
X		if (dp->_d_entry)
X			free(dp->_d_entry);
X		dp = (odp = dp)->_d_next;
X		free((char *) odp);
X	}
X}
X
Xstatic char *getdirent(dir)
Xchar *dir;
X{
X  int done;
X
X  if (dir != (char *) NULL)
X    done = _dos_findfirst(dir, ATTRIBUTES, &find);
X  else                                  /* get next entry */
X    done = _dos_findnext(&find);
X
X  if (done==0)
X    return find.name;
X  else
X    return (char *) NULL;
X}
X
X
Xsetfilemode(char *name, unsigned attr)
X{
X  _dos_setfileattr(name, attr);
X}
X
Xgetfilemode(char *name, unsigned *attr)
X{
X  _dos_getfileattr(name, attr);
X}
END_OF_dir_dos.c
if test 3587 -ne `wc -c <dir_dos.c`; then
    echo shar: \"dir_dos.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f dir_os2.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"dir_os2.c\"
else
echo shar: Extracting \"dir_os2.c\" \(3837 characters\)
sed "s/^X//" >dir_os2.c <<'END_OF_dir_os2.c'
X/*
X * @(#)dir.c 1.4 87/11/06	Public Domain.
X *
X *  A public domain implementation of BSD directory routines for
X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
X *  August 1897
X *  Ported to OS/2 by Kai Uwe Rommel
X *  December 1989
X */
X
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<sys/dir.h>
X#include	<malloc.h>
X#include	<string.h>
X
X#define INCL_NOPM
X#include <os2.h>
X
X#ifndef	NULL
X# define	NULL	0
X#endif	/* NULL */
X
X#ifndef	MAXPATHLEN
X# define	MAXPATHLEN	255
X#endif	/* MAXPATHLEN */
X
X/* attribute stuff */
X#define	A_RONLY		0x01
X#define	A_HIDDEN	0x02
X#define	A_SYSTEM	0x04
X#define	A_LABEL		0x08
X#define	A_DIR		0x10
X#define	A_ARCHIVE	0x20
X
X
X#define Newisnull(a, t) ((a = (t *) malloc(sizeof(t))) == (t *) NULL)
X
X#define ATTRIBUTES      (A_DIR)
X/* #define ATTRIBUTES      (A_DIR | A_HIDDEN | A_SYSTEM) */
X/* #define ATTRIBUTES      (A_RONLY | A_SYSTEM | A_DIR) */
X
Xstatic  char    *getdirent(char *);
Xstatic	void	free_dircontents(struct _dircontents *);
X
Xstatic HDIR hdir;
Xstatic USHORT count;
Xstatic FILEFINDBUF find;
X
X
XDIR	*
Xopendir(name)
X	char	*name;
X{
X	struct	stat		statb;
X	DIR			*dirp;
X	char			c;
X	char			*s;
X	struct _dircontents	*dp;
X	char			nbuf[MAXPATHLEN + 1];
X
X	if (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
X		return (DIR *) NULL;
X	if (Newisnull(dirp, DIR))
X		return (DIR *) NULL;
X	if (*name && (c = name[strlen(name) - 1]) != '\\' && c != '/')
X		(void) strcat(strcpy(nbuf, name), "\\*.*");
X	else
X		(void) strcat(strcpy(nbuf, name), "*.*");
X	dirp->dd_loc = 0;
X        dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL;
X
X	if ((s = getdirent(nbuf)) == (char *) NULL)
X		return dirp;
X	do {
X		if (Newisnull(dp, struct _dircontents) || (dp->_d_entry =
X			malloc((unsigned) (strlen(s) + 1))) == (char *) NULL)
X		{
X			if (dp)
X				free((char *) dp);
X			free_dircontents(dirp->dd_contents);
X			return (DIR *) NULL;
X		}
X		if (dirp->dd_contents)
X			dirp->dd_cp = dirp->dd_cp->_d_next = dp;
X		else
X			dirp->dd_contents = dirp->dd_cp = dp;
X		(void) strcpy(dp->_d_entry, s);
X		dp->_d_next = (struct _dircontents *) NULL;
X        } while ((s = getdirent((char *) NULL)) != (char *) NULL);
X
X	dirp->dd_cp = dirp->dd_contents;
X
X	return dirp;
X}
X
Xvoid
Xclosedir(dirp)
X	DIR	*dirp;
X{
X	free_dircontents(dirp->dd_contents);
X	free((char *) dirp);
X}
X
Xstruct direct	*
Xreaddir(dirp)
X	DIR	*dirp;
X{
X	static	struct direct	dp;
X
X	if (dirp->dd_cp == (struct _dircontents *) NULL)
X		return (struct direct *) NULL;
X	dp.d_namlen = dp.d_reclen =
X		strlen(strcpy(dp.d_name, dirp->dd_cp->_d_entry));
X	strlwr(dp.d_name);		/* JF */
X	dp.d_ino = 0;
X	dirp->dd_cp = dirp->dd_cp->_d_next;
X	dirp->dd_loc++;
X
X	return &dp;
X}
X
Xvoid
Xseekdir(dirp, off)
X	DIR	*dirp;
X	long	off;
X{
X	long			i = off;
X	struct _dircontents	*dp;
X
X	if (off < 0)
X		return;
X	for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
X		;
X	dirp->dd_loc = off - (i + 1);
X	dirp->dd_cp = dp;
X}
X
Xlong
Xtelldir(dirp)
X	DIR	*dirp;
X{
X	return dirp->dd_loc;
X}
X
Xstatic	void
Xfree_dircontents(dp)
X	struct	_dircontents	*dp;
X{
X	struct _dircontents	*odp;
X
X	while (dp) {
X		if (dp->_d_entry)
X			free(dp->_d_entry);
X		dp = (odp = dp)->_d_next;
X		free((char *) odp);
X	}
X}
X
Xstatic char *getdirent(dir)
Xchar *dir;
X{
X  int done;
X
X  if (dir != (char *) NULL)
X  {                                     /* get first entry */
X    hdir = HDIR_CREATE;
X    count = 1;
X    done = DosFindFirst(dir, &hdir, ATTRIBUTES,
X                        &find, sizeof(find), &count, 0L);
X  }
X  else                                  /* get next entry */
X    done = DosFindNext(hdir, &find, sizeof(find), &count);
X
X  if (done==0)
X    return find.achName;
X  else
X  {
X    DosFindClose(hdir);
X    return (char *) NULL;
X  }
X}
X
X
Xsetfilemode(char *name, unsigned attr)
X{
X  DosSetFileMode(name, attr, 0L);
X}
X
Xgetfilemode(char *name, unsigned *attr)
X{
X  DosQFileMode(name, (PUSHORT) attr, 0L);
X}
END_OF_dir_os2.c
if test 3837 -ne `wc -c <dir_os2.c`; then
    echo shar: \"dir_os2.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lharc.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lharc.c\"
else
echo shar: Extracting \"lharc.c\" \(49791 characters\)
sed "s/^X//" >lharc.c <<'END_OF_lharc.c'
X/*----------------------------------------------------------------------*/
X/*		LHarc Archiver Driver for UNIX				*/
X/*									*/
X/*		Copyright(C) MCMLXXXIX  Yooichi.Tagawa			*/
X/*		Thanks to H.Yoshizaki. (MS-DOS LHarc)			*/
X/*									*/
X/*  V0.00  Original				1988.05.23  Y.Tagawa	*/
X/*  V0.01  Alpha Version (for 4.2BSD)		1989.05.28  Y.Tagawa	*/
X/*  V0.02  Alpha Version Rel.2			1989.05.29  Y.Tagawa	*/
X/*  V0.03  Release #3  Beta Version		1989.07.02  Y.Tagawa	*/
X/*  V0.03a Fix few bug                          1989.07.03  Y.Tagawa    */
X/*  V0.04  A lot of bugs fixed, strict mode     1990.01.13  Kai Uwe Rommel */
X/*  V1.00  f and t commands, v option added     1990.01.27  Kai Uwe Rommel */
X/*----------------------------------------------------------------------*/
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <prototypes.h>
X
X#ifdef PROF
X#include <profile.h>
X#endif
X
X#define STRICT
X#define FASTCOPY
X
X#ifdef MSDOS
X#include <fcntl.h>
Xextern unsigned char _osmode;
Xextern FILE *popen();
Xextern pclose();
X#define ftruncate chsize
X#define mktemp Mktemp
X#define SYSTIME_HAS_NO_TM
X#define NOBSTRING
X#define SYSNAME (_osmode ? "OS/2" : "MS-DOS")
X#define OUR_EXTEND (_osmode ? EXTEND_OS2 : EXTEND_MSDOS)
X#define FILENAME_LENGTH 128
X#define NULLFILE "nul"
X#define TMP_FILENAME_TEMPLATE "lhXXXXXX"
X#define NOT_COMPATIBLE_MODE
X#define RMODE "rb"
X#define WMODE "wb"
X#else
X#include <sys/file.h>
X#include <time.h>
X#define SYSNAME "UNIX"
X#define ftruncate chsize
X#define OUR_EXTEND EXTEND_UNIX
X#define FILENAME_LENGTH	1024
X#define NULLFILE "/dev/null"
X#define RMODE "r"
X#define WMODE "w"
X#endif
X
X#ifdef SYSTIME_HAS_NO_TM
X/* most of System V,  define SYSTIME_HAS_NO_TM */
X#include <time.h>
X#endif
X
X/* #include <strings.h> */
X#include <string.h>
X#include <sys/select.h>
X#include <sys/fcntl.h>
X/*----------------------------------------------------------------------*/
X/*			DIRECTORY ACCESS STUFF				*/
X/*----------------------------------------------------------------------*/
X#ifndef NODIRECTORY
X#ifdef SYSV_SYSTEM_DIR
X
X#include <dirent.h>
X#define DIRENTRY	struct dirent
X#define NAMLEN(p)	strlen (p->d_name)
X
X#else	/* not SYSV_SYSTEM_DIR */
X
X#ifdef NONSYSTEM_DIR_LIBRARY
X#include "lhdir.h"
X#else	/* not NONSYSTEM_DIR_LIBRARY */
X#include <sys/dir.h>
X#endif	/* not NONSYSTEM_DIR_LIBRARY */
X
X#define DIRENTRY	struct direct
X#define NAMLEN(p)	p->d_namlen
X
Xextern DIR *opendir ();
Xextern struct direct *readdir ();
X
X#endif	/* not SYSV_SYSTEM_DIR */
X#endif
X
X/*----------------------------------------------------------------------*/
X/*			FILE ATTRIBUTES					*/
X/*----------------------------------------------------------------------*/
X
X/* If file mode is not compatible between your Machine/OS and
X   LHarc standard UNIX file mode.
X   (See UNIX Manual stat(1), <sys/stat.h>,
X   and/or below UNIX_* difinitions. ) */
X/* #define NOT_COMPATIBLE_MODE */
X
X
X/*----------------------------------------------------------------------*/
X/*			MEMORY FUNCTIONS 				*/
X/*----------------------------------------------------------------------*/
X
X#ifdef NOBSTRING
X#ifdef __ANSI__
X#include "mem.h"
X#define bcmp(a,b,n) memcmp ((a),(b),(n))
X#define bcopy(s,d,n) memmove((d),(s),(n))
X#define bzero(d,n) memset((d),0,(n))
X#else	/* not __ANSI__ */
X#include "memory.h"
X#define bcmp(a,b,n) memcmp ((a),(b),(n))
X#define bcopy(s,d,n) memcpy ((d),(s),(n))	/* movmem((s),(d),(n)) */
X#define bzero(d,n) memset((d),0,(n))
X#endif	/* not __ANSI__ */
X#endif	/* NOBSTRING */
X
X
X/*----------------------------------------------------------------------*/
X/*			YOUR CUSTOMIZIES				*/
X/*----------------------------------------------------------------------*/
X/* These difinitions are changable to you like. */
X #define ARCHIVENAME_EXTENTION	".lzh"
X/* #define TMP_FILENAME_TEMPLATE	"/tmp/lhXXXXXX" */
X/* #define BACKUPNAME_EXTENTION		".BAK"		*/
X/* #define MULTIBYTE_CHAR				*/
X
X
X
X#define SJC_FIRST_P(c)			\
X  (((unsigned char)(c) >= 0x80) &&	\
X   (((unsigned char)(c) < 0xa0) ||	\
X    ((unsigned char)(c) >= 0xe0) &&	\
X    ((unsigned char)(c) < 0xfd)))
X#define SJC_SECOND_P(c)			\
X  (((unsigned char)(c) >= 0x40) &&	\
X   ((unsigned char)(c) < 0xfd) &&	\
X   ((ungigned char)(c) != 0x7f))
X
X#ifdef MULTIBYTE_CHAR
X#define MULTIBYTE_FIRST_P	SJC_FIRST_P
X#define MULTIBYTE_SECOND_P	SJC_SECOND_P
X#endif
X
X/*----------------------------------------------------------------------*/
X/*			OTHER DIFINITIONS				*/
X/*----------------------------------------------------------------------*/
X
X#ifndef SEEK_SET
X#define SEEK_SET	0
X#define SEEK_CUR	1
X#define SEEK_END	2
X#endif
X
X
X/* non-integral functions */
Xextern struct tm *localtime ();
Xextern char *getenv ();
Xextern char *malloc ();
Xextern char *realloc ();
X
Xextern int rson[];
X
X/* external variables */
Xextern int errno;
X
X
X#define	FALSE	0
X#define TRUE	1
Xtypedef int boolean;
X
X
X/*----------------------------------------------------------------------*/
X/*		LHarc FILE DIFINITIONS					*/
X/*----------------------------------------------------------------------*/
X#define METHOD_TYPE_STRAGE	5
X#define LZHUFF0_METHOD		"-lh0-"
X#define LZHUFF1_METHOD		"-lh1-"
X#define LARC4_METHOD		"-lz4-"
X#define LARC5_METHOD		"-lz5-"
X
X#define I_HEADER_SIZE			0
X#define I_HEADER_CHECKSUM		1
X#define I_METHOD			2
X#define I_PACKED_SIZE			7
X#define I_ORIGINAL_SIZE			11
X#define I_LAST_MODIFIED_STAMP		15
X#define I_ATTRIBUTE			19
X#define I_NAME_LENGTH			21
X#define I_NAME				22
X
X#define I_CRC				22 /* + name_length */
X#define I_EXTEND_TYPE			24 /* + name_length */
X#define I_MINOR_VERSION			25 /* + name_length */
X#define I_UNIX_LAST_MODIFIED_STAMP	26 /* + name_length */
X#define I_UNIX_MODE			30 /* + name_length */
X#define I_UNIX_UID			32 /* + name_length */
X#define I_UNIX_GID			34 /* + name_length */
X#define I_UNIX_EXTEND_BOTTOM		36 /* + name_length */
X
X
X
X#define EXTEND_GENERIC  0
X#define EXTEND_UNIX	'U'
X#define EXTEND_MSDOS	'M'
X#define EXTEND_MACOS	'm'
X#define EXTEND_OS9	'9'
X#define EXTEND_OS2	'2'
X#define EXTEND_OS68K	'K'
X#define EXTEND_OS386	'3'
X#define EXTEND_HUMAN	'H'
X#define EXTEND_CPM	'C'
X#define EXTEND_FLEX	'F'
X
X#define GENERIC_ATTRIBUTE		0x20
X#define GENERIC_DIRECTORY_ATTRIBUTE	0x10
X
X#define CURRENT_UNIX_MINOR_VERSION	0x00
X
X
X
Xtypedef struct LzHeader {
X  unsigned char		header_size;
X  char			method[METHOD_TYPE_STRAGE];
X  long			packed_size;
X  long			original_size;
X  long			last_modified_stamp;
X  unsigned short	attribute;
X  char			name[256];
X  unsigned short	crc;
X  boolean		has_crc;
X  unsigned char		extend_type;
X  unsigned char		minor_version;
X  /*  extend_type == EXTEND_UNIX  and convert from other type. */
X  time_t		unix_last_modified_stamp;
X  unsigned short	unix_mode;
X  unsigned short	unix_uid;
X  unsigned short	unix_gid;
X} LzHeader;
X
X#define UNIX_FILE_TYPEMASK	0170000
X#define UNIX_FILE_REGULAR	0100000
X#define UNIX_FILE_DIRECTORY	0040000
X#define UNIX_SETUID		0004000
X#define UNIX_SETGID		0002000
X#define UNIX_STYCKYBIT		0001000
X#define UNIX_OWNER_READ_PERM	0000400
X#define UNIX_OWNER_WRITE_PERM	0000200
X#define UNIX_OWNER_EXEC_PERM	0000100
X#define UNIX_GROUP_READ_PERM	0000040
X#define UNIX_GROUP_WRITE_PERM	0000020
X#define UNIX_GROUP_EXEC_PERM	0000010
X#define UNIX_OTHER_READ_PERM	0000004
X#define UNIX_OTHER_WRITE_PERM	0000002
X#define UNIX_OTHER_EXEC_PERM	0000001
X#define UNIX_RW_RW_RW		0000666
X
X#define LZHEADER_STRAGE		256
X
X/*----------------------------------------------------------------------*/
X/*		PROGRAM 						*/
X/*----------------------------------------------------------------------*/
X
X
X#define CMD_UNKNOWN	0
X#define CMD_EXTRACT	1
X#define CMD_APPEND	2
X#define CMD_VIEW	3
X
Xint      cmd = CMD_UNKNOWN;
Xchar     **cmd_filev;
Xint      cmd_filec;
Xchar     *archive_name;
X
Xchar     expanded_archive_name[FILENAME_LENGTH];
Xchar     temporary_name[FILENAME_LENGTH];
Xchar     pager[FILENAME_LENGTH];
X
X
X/* options */
Xboolean	quiet = FALSE;
Xboolean	text_mode = FALSE;
X/*boolean  verbose = FALSE; */
Xboolean  noexec = FALSE; /* debugging option */
Xboolean  force = FALSE;
Xboolean  prof = FALSE;
X
X
X/* view flags */
Xboolean  long_format_listing = FALSE;
X
X/* extract flags */
Xboolean  output_to_test = FALSE;
Xboolean  output_to_stdout = FALSE;
X
X/* append flags */
Xboolean  new_archive = FALSE;
Xboolean  update_if_newer = FALSE;
Xboolean  update_freshen = FALSE;
Xboolean  delete_after_append = FALSE;
Xboolean  delete_from_archive = FALSE;
X
Xboolean  remove_temporary_at_error = FALSE;
X
X
X/*----------------------------------------------------------------------*/
X/* NOTES :	Text File Format					*/
X/*	GENERATOR		NewLine					*/
X/*	[generic]		0D 0A					*/
X/*	[MS-DOS]		0D 0A					*/
X/*	[MacOS]			0D					*/
X/*	[UNIX]			0A					*/
X/*----------------------------------------------------------------------*/
X
Xchar *myname;
X
X
Xvoid userbreak()
X{
X    error("Interrupt.");
X}
X
X
Xmain (argc, argv)
X     int argc;
X     char *argv[];
X{
X  char *p;
X
X  myname = argv[0];
X  signal(SIGINT, userbreak);
X
X#ifdef PROF
X  PROFINIT(PT_USER|PT_USEKP, NULL);
X  PROFCLEAR(PT_USER);
X  PROFON(PT_USER);
X#endif
X
X  if (argc < 3)
X    print_tiny_usage_and_exit ();
X
X  /* commands */
X#ifdef MSDOS
X  switch (tolower(argv[1][0]))
X#else
X  switch (argv[1][0])
X#endif
X    {
X    case 'x':
X    case 'e':
X      cmd = CMD_EXTRACT;
X      break;
X
X    case 't':
X      output_to_test = TRUE;
X      cmd = CMD_EXTRACT;
X      break;
X
X    case 'p':
X      output_to_stdout = TRUE;
X      cmd = CMD_EXTRACT;
X      break;
X
X    case 'c':
X      new_archive = TRUE;
X      cmd = CMD_APPEND;
X      break;
X
X    case 'a':
X      cmd = CMD_APPEND;
X      break;
X
X    case 'd':
X      delete_from_archive = TRUE;
X      cmd = CMD_APPEND;
X      break;
X
X    case 'u':
X      update_if_newer = TRUE;
X      cmd = CMD_APPEND;
X      break;
X
X    case 'f':
X      update_if_newer = update_freshen = TRUE;
X      cmd = CMD_APPEND;
X      break;
X
X    case 'm':
X      delete_after_append = TRUE;
X      cmd = CMD_APPEND;
X      break;
X
X    case 'v':
X      cmd = CMD_VIEW;
X      break;
X
X    case 'l':
X      long_format_listing = TRUE;
X      cmd = CMD_VIEW;
X      break;
X
X    case 'h':
X    default:
X      print_tiny_usage_and_exit ();
X    }
X
X  /* options */
X  p = &argv[1][1];
X  for (p = &argv[1][1]; *p; p++)
X    {
X#ifdef MSDOS
X      switch (tolower(*p))
X#else
X      switch (*p)
X#endif
X	{
X	case 'q':	quiet = TRUE; break;
X	case 'f':	force = TRUE; break;
X/*      case 'p':       prof = TRUE; break; */
X/*      case 'v':       verbose = TRUE; break; */
X        case 'v':       strcpy(pager, p + 1); *(p + 1) = 0; break;
X	case 't':	text_mode = TRUE; break;
X	case 'n':	noexec = TRUE; break;
X
X	default:
X          fprintf (stderr, "unknown option '%c'.\n", *p);
X	  exit (1);
X        }
X    }
X
X  /* archive file name */
X  archive_name = argv[2];
X
X  /* target file name */
X  cmd_filec = argc - 3;
X  cmd_filev = argv + 3;
X  sort_files ();
X
X  switch (cmd)
X    {
X    case CMD_EXTRACT:	cmd_extract ();	break;
X    case CMD_APPEND:	cmd_append ();	break;
X    case CMD_VIEW:	cmd_view ();	break;
X    }
X
X#ifdef PROF
X  PROFOFF(PT_USER);
X  PROFDUMP(PT_USER, "profile.out");
X  PROFFREE(PT_USER);
X#endif
X
X  exit (0);
X}
X
Xprint_tiny_usage_and_exit ()
X{
X  printf("\nC-LHarc for %s Version 1.00   (C) 1989-1990 Y.Tagawa, Kai Uwe Rommel\n"
X         "\nUsage: %s {axevlufdmctp}[qnftv] archive_file [files or directories...]\n",
X         SYSNAME, myname);
X  printf("\nCommands:                    Options:\n"
X         "  a   Append                   q   quiet\n"
X         "  x,e EXtract                  n   no execute\n"
X         "  v,l View/List                f   force (over write at extract)\n"
X         "  u   Update                   t   files are TEXT files\n"
X         "  f   Freshen                  v<pager>  use file pager for p command\n"
X         "  d   Delete\n"
X         "  m   Move\n"
X         "  c   re-Construct new archive\n"
X         "  t   Test archive\n"
X         "  p   Print to STDOUT\n");
X  exit (1);
X}
X
Xmessage (title, msg)
X     char *title, *msg;
X{
X  fprintf (stderr, "%s ", myname);
X  if (errno == 0)
X    fprintf (stderr, "%s %s\n", title, msg);
X  else
X    perror (msg);
X}
X
Xwarning (msg)
X     char *msg;
X{
X  message ("Warning:", msg);
X}
X
Xerror (msg)
X     char *msg;
X{
X  message ("Error:", msg);
X
X  if (remove_temporary_at_error)
X  {
X#ifdef MSDOS
X    fcloseall();
X#endif
X    unlink (temporary_name);
X  }
X
X  exit (1);
X}
X
Xchar *writting_filename;
Xchar *reading_filename;
X
Xwrite_error ()
X{
X  error (writting_filename);
X}
X
Xread_error ()
X{
X  error (reading_filename);
X}
X
X
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
Xboolean expand_archive_name (dst, src)
X     char *dst, *src;
X{
X  register char *p, *dot;
X
X  strcpy (dst, src);
X
X  for (p = dst, dot = (char*)0; *p; p++)
X    if (*p == '.')
X      dot = p;
X    else if (*p == '/' || *p == '\\')
X      dot = (char*)0;
X
X  if (dot)
X    p = dot;
X
X#ifdef ARCHIVENAME_EXTENTION
X  strcpy (p, ARCHIVENAME_EXTENTION);
X#else
X  strcpy (p, ".lzh");
X#endif
X  return (strcmp (dst, src) != 0);
X}
X
X#ifdef MSDOS
X#define STRING_COMPARE(a,b) stricmp((a),(b))
X#else
X#define STRING_COMPARE(a,b) strcmp((a),(b))
X#endif
X
Xint sort_by_ascii (a, b)
X     char **a, **b;
X{
X  return STRING_COMPARE (*a, *b);
X}
X
Xsort_files ()
X{
X  qsort (cmd_filev, cmd_filec, sizeof (char*), sort_by_ascii);
X}
X
X#ifndef MSDOS
Xchar *strdup (string)
X     char *string;
X{
X  int	len = strlen (string) + 1;
X  char	*p = malloc (len);
X  bcopy (string, p, len);
X  return p;
X}
X#endif
X
X#ifdef NODIRECTORY
X/* please need your imprementation */
Xboolean find_files (name, v_filec, v_filev)
X     char	*name;
X     int	*v_filec;
X     char	***v_filev;
X{
X  return FALSE;			/* DUMMY */
X}
X#else
Xboolean find_files (name, v_filec, v_filev)
X     char	*name;
X     int	*v_filec;
X     char	***v_filev;
X{
X  char		newname[FILENAME_LENGTH];
X  int 		len, n;
X  DIR		*dirp;
X  DIRENTRY	*dp;
X  int           alloc_size = 64; /* any (^_^) */
X  char		**filev;
X  int		filec = 0;
X
X  if ( strcmp(name, ".") == 0 )
X    newname[0] = 0;
X  else
X    strcpy (newname, name);
X
X  len = strlen (newname);
X  dirp = opendir (name);
X
X  if (dirp)
X    {
X      filev = (char**)malloc (alloc_size * sizeof(char *));
X      if (!filev)
X	error ("not enough memory");
X
X      for (dp = readdir (dirp); dp != NULL; dp = readdir (dirp))
X	{
X	  n = NAMLEN (dp);
X          if (
X#ifndef MSDOS
X              (dp->d_ino != 0) &&
X#endif
X              ((dp->d_name[0] != '.') ||
X                 ((n != 1) &&
X                 ((dp->d_name[1] != '.') ||
X		 (n != 2)))) &&			/* exclude '.' and '..' */
X	      (strcmp (dp->d_name, temporary_name) != 0) &&
X	      (strcmp (dp->d_name, archive_name) != 0))
X	    {
X              if ((len != 0) && (newname[len-1] != '/') && (newname[len-1] != '\\'))
X                {
X#ifdef MSDOS
X                  newname[len] = '\\';
X#else
X                  newname[len] = '/';
X#endif
X		  strncpy (newname+len+1, dp->d_name, n);
X		  newname[len+n+1] = '\0';
X		}
X	      else
X		{
X		  strncpy (newname+len, dp->d_name, n);
X		  newname[len+n] = '\0';
X		}
X
X	      filev[filec++] = strdup (newname);
X	      if (filec == alloc_size)
X		{
X                  alloc_size += 64;
X                  filev = (char**)realloc (filev, alloc_size * sizeof(char *));
X		}
X	    }
X	}
X      closedir (dirp);
X    }
X
X  *v_filev = filev;
X  *v_filec = filec;
X  if (dirp)
X    {
X      qsort (filev, filec, sizeof (char*), sort_by_ascii);
X      return TRUE;
X    }
X  else
X    return FALSE;
X}
X#endif
X
Xfree_files (filec, filev)
X     int	filec;
X     char	**filev;
X{
X  int		i;
X
X  for (i = 0; i < filec; i ++)
X    free (filev[i]);
X
X  free (filev);
X}
X
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
Xint calc_sum (p, len)
X     register char *p;
X     register int len;
X{
X  register int sum;
X
X  for (sum = 0; len; len--)
X    sum += *p++;
X
X  return sum & 0xff;
X}
X
Xunsigned char *get_ptr;
X#define setup_get(PTR) get_ptr = (unsigned char*)(PTR)
X#define get_byte() (*get_ptr++)
X#define put_ptr	get_ptr
X#define setup_put(PTR) put_ptr = (unsigned char*)(PTR)
X#define put_byte(c) *put_ptr++ = (unsigned char)(c)
X
Xunsigned short get_word ()
X{
X  int b0, b1;
X
X  b0 = get_byte ();
X  b1 = get_byte ();
X  return (b1 << 8) + b0;
X}
X
Xput_word (v)
X     unsigned int	v;
X{
X  put_byte (v);
X  put_byte (v >> 8);
X}
X
Xlong get_longword ()
X{
X  long b0, b1, b2, b3;
X
X  b0 = get_byte ();
X  b1 = get_byte ();
X  b2 = get_byte ();
X  b3 = get_byte ();
X  return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
X}
X
Xput_longword (v)
X     long v;
X{
X  put_byte (v);
X  put_byte (v >> 8);
X  put_byte (v >> 16);
X  put_byte (v >> 24);
X}
X
X
Xmsdos_to_unix_filename (name, len)
X     register char *name;
X     register int len;
X{
X  register int i;
X
X#ifdef MULTIBYTE_CHAR
X  for (i = 0; i < len; i ++)
X    {
X      if (MULTIBYTE_FIRST_P (name[i]) &&
X	  MULTIBYTE_SECOND_P (name[i+1]))
X        i ++;
X#ifndef MSDOS
X      else if (name[i] == '\\')
X        name[i] = '/';
X#endif
X      else if (isupper (name[i]))
X	name[i] = tolower (name[i]);
X    }
X#else
X  for (i = 0; i < len; i ++)
X    {
X#ifndef MSDOS
X      if (name[i] == '\\')
X	name[i] = '/';
X      else
X#endif
X        if (isupper (name[i]))
X          name[i] = tolower (name[i]);
X    }
X#endif
X}
X
Xgeneric_to_unix_filename (name, len)
X     register char *name;
X     register int len;
X{
X  register int i;
X  boolean	lower_case_used = FALSE;
X
X#ifdef MULTIBYTE_CHAR
X  for (i = 0; i < len; i ++)
X    {
X      if (MULTIBYTE_FIRST_P (name[i]) &&
X	  MULTIBYTE_SECOND_P (name[i+1]))
X	i ++;
X      else if (islower (name[i]))
X	{
X	  lower_case_used = TRUE;
X	  break;
X	}
X    }
X  for (i = 0; i < len; i ++)
X    {
X      if (MULTIBYTE_FIRST_P (name[i]) &&
X	  MULTIBYTE_SECOND_P (name[i+1]))
X        i ++;
X#ifndef MSDOS
X      else if (name[i] == '\\')
X        name[i] = '/';
X#endif
X      else if (!lower_case_used && isupper (name[i]))
X	name[i] = tolower (name[i]);
X    }
X#else
X  for (i = 0; i < len; i ++)
X    if (islower (name[i]))
X      {
X	lower_case_used = TRUE;
X	break;
X      }
X  for (i = 0; i < len; i ++)
X    {
X#ifndef MSDOS
X      if (name[i] == '\\')
X	name[i] = '/';
X      else
X#endif
X        if (!lower_case_used && isupper (name[i]))
X          name[i] = tolower (name[i]);
X    }
X#endif
X}
X
Xmacos_to_unix_filename (name, len)
X     register char *name;
X     register int len;
X{
X  register int i;
X
X  for (i = 0; i < len; i ++)
X    {
X      if (name[i] == ':')
X	name[i] = '/';
X      else if (name[i] == '/')
X	name[i] = ':';
X    }
X}
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*	Generic stamp format:						*/
X/*									*/
X/*	 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16		*/
X/*	|<-------- year ------->|<- month ->|<-- day -->|		*/
X/*									*/
X/*	 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0		*/
X/*	|<--- hour --->|<---- minute --->|<- second*2 ->|		*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
X
Xlong gettz ()
X{
X#ifdef MSDOS
X   return timezone;
X#else
X   struct timeval	tp;
X/*   struct timezone	tzp;*/
X/*   gettimeofday (&tp, &tzp);*/	/* specific to 4.3BSD */
X/* return (tzp.tz_minuteswest * 60 + (tzp.tz_dsttime != 0 ? 60L * 60L : 0));*/
X   return (60);
X#endif
X}
X
X#ifdef NOT_USED
Xstruct tm *msdos_to_unix_stamp_tm (a)
X     long a;
X{
X  static struct tm t;
X  t.tm_sec	= ( a          & 0x1f) * 2;
X  t.tm_min	=  (a >>    5) & 0x3f;
X  t.tm_hour	=  (a >>   11) & 0x1f;
X  t.tm_mday	=  (a >>   16) & 0x1f;
X  t.tm_mon	=  (a >> 16+5) & 0x0f - 1;
X  t.tm_year	= ((a >> 16+9) & 0x7f) + 80;
X  return &t;
X}
X#endif
X
Xtime_t generic_to_unix_stamp (t)
X     long t;
X{
X  struct tm tm;
X  long longtime;
X  static unsigned int dsboy[12] =
X    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
X  unsigned long days;
X
X  tm.tm_year =  ((int)(t >> 25) & 0x7f) + 80;
X  tm.tm_mon  =  ((int)(t >> 21) & 0x0f) - 1;     /* 0..11 means Jan..Dec */
X  tm.tm_mday =  (int)(t >> 16) & 0x1f;         /* 1..31 means 1st,...31st */
X
X  tm.tm_hour =  ((int)t >> 11) & 0x1f;
X  tm.tm_min  =  ((int)t >> 5)  & 0x3f;
X  tm.tm_sec  =  ((int)t        & 0x1f) * 2;
X
X#ifdef MSDOS
X  longtime = mktime(&tm);
X#else
X                                      /* Calculate days since 1970.01.01 */
X  days = (365 * (tm.tm_year - 70) +   /* days due to whole years */
X          (tm.tm_year - 70 + 1) / 4 + /* days due to leap years */
X          dsboy[tm.tm_mon] +          /* days since beginning of this year */
X          tm.tm_mday-1);              /* days since beginning of month */
X
X  if ((tm.tm_year % 4 == 0) &&
X      (tm.tm_year % 400 != 0) &&
X      (tm.tm_mon >= 2))         /* if this is a leap year and month */
X    days++;			/* is March or later, add a day */
X
X  /* Knowing the days, we can find seconds */
X  longtime = (((days * 24) + tm.tm_hour) * 60 + tm.tm_min) * 60 + tm.tm_sec;
X  longtime += gettz ();      /* adjust for timezone */
X#endif
X
X  /* special case:  if MSDOS format date and time were zero, then we set
X     time to be zero here too. */
X  if (t == 0)
X    longtime = 0;
X
X  /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00.  */
X  return (time_t)longtime;
X}
X
Xlong unix_to_generic_stamp (t)
X     time_t t;
X{
X  struct tm *tm = localtime (&t);
X  unsigned long stamp;
X
X  stamp =  ( ((long)(tm->tm_year - 80)) << 25 );
X  stamp += ( ((long)(tm->tm_mon + 1))   << 21 );
X  stamp += ( ((long)(tm->tm_mday))      << 16 );
X  stamp += ( ((long)(tm->tm_hour))      << 11 );
X  stamp += ( ((long)(tm->tm_min))       << 5 );
X  stamp += ( ((long)(tm->tm_sec))       >> 1 );
X
X  return stamp;
X}
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
Xboolean get_header (fp, hdr)
X     FILE *fp;
X     register LzHeader *hdr;
X{
X  int		header_size;
X  int		name_length;
X  char		data[LZHEADER_STRAGE];
X  int		checksum;
X  int		i;
X
X  bzero (hdr, sizeof (LzHeader));
X
X  if (((header_size = getc (fp)) == EOF) || (header_size == 0))
X    {
X      return FALSE;		/* finish */
X    }
X
X  if (fread (data + I_HEADER_CHECKSUM,
X		  sizeof (char), header_size + 1, fp) < header_size + 1)
X    {
X      error ("Invalid header (LHarc file ?)\a");
X      return FALSE;		/* finish */
X    }
X
X  setup_get (data + I_HEADER_CHECKSUM);
X  checksum = calc_sum (data + I_METHOD, header_size);
X  if (get_byte () != checksum)
X    warning ("Checksum error (LHarc file?)\a");
X
X  hdr->header_size = header_size;
X  bcopy (data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE);
X#ifdef OLD
X  if ((bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) != 0) &&
X      (bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) != 0) &&
X      (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) != 0) &&
X      (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) != 0))
X    {
X      warning ("Unknown method (LHarc file ?)");
X      return FALSE;		/* invalid method */
X    }
X#endif
X  setup_get (data + I_PACKED_SIZE);
X  hdr->packed_size	= get_longword ();
X  hdr->original_size	= get_longword ();
X  hdr->last_modified_stamp = get_longword ();
X  hdr->attribute	= get_word ();
X  name_length		= get_byte ();
X  for (i = 0; i < name_length; i ++)
X    hdr->name[i] =(char)get_byte ();
X  hdr->name[name_length] = '\0';
X
X  /* defaults for other type */
X  hdr->unix_mode	= UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
X  hdr->unix_gid 	= 0;
X  hdr->unix_uid		= 0;
X
X  if (header_size - name_length >= 24)
X    {				/* EXTEND FORMAT */
X      hdr->crc				= get_word ();
X      hdr->extend_type			= get_byte ();
X      hdr->minor_version		= get_byte ();
X      hdr->has_crc = TRUE;
X    }
X  else if (header_size - name_length == 22)
X    {				/* Generic with CRC */
X      hdr->crc				= get_word ();
X      hdr->extend_type			= EXTEND_GENERIC;
X      hdr->has_crc = TRUE;
X    }
X  else if (header_size - name_length == 20)
X    {				/* Generic no CRC */
X      hdr->extend_type			= EXTEND_GENERIC;
X      hdr->has_crc = FALSE;
X    }
X  else
X    {
X      warning ("Unknown header (LHarc file ?)");
X      return FALSE;
X    }
X
X  switch (hdr->extend_type)
X    {
X    case EXTEND_MSDOS:
X      msdos_to_unix_filename (hdr->name, name_length);
X      hdr->unix_last_modified_stamp	=
X	generic_to_unix_stamp (hdr->last_modified_stamp);
X      break;
X
X    case EXTEND_UNIX:
X      hdr->unix_last_modified_stamp	= (time_t)get_longword ();
X      hdr->unix_mode			= get_word ();
X      hdr->unix_uid			= get_word ();
X      hdr->unix_gid			= get_word ();
X      break;
X
X    case EXTEND_MACOS:
X      macos_to_unix_filename (hdr->name, name_length);
X      hdr->unix_last_modified_stamp	=
X	generic_to_unix_stamp (hdr->last_modified_stamp);
X      break;
X
X    default:
X      generic_to_unix_filename (hdr->name, name_length);
X      hdr->unix_last_modified_stamp	=
X	generic_to_unix_stamp (hdr->last_modified_stamp);
X    }
X
X  return TRUE;
X}
X
Xinit_header (name, v_stat, hdr)
X     char *name;
X     struct stat *v_stat;
X     LzHeader *hdr;
X{
X  bcopy (LZHUFF1_METHOD, hdr->method, METHOD_TYPE_STRAGE);
X  hdr->packed_size		= 0;
X  hdr->original_size		= v_stat->st_size;
X  hdr->last_modified_stamp      = unix_to_generic_stamp (v_stat->st_mtime);
X#ifdef MSDOS
X  getfilemode(name, &(hdr->attribute));
X#else
X  hdr->attribute                = GENERIC_ATTRIBUTE;
X#endif
X  strcpy (hdr->name, name);
X  hdr->crc			= 0x0000;
X  hdr->extend_type              = OUR_EXTEND;
X  hdr->unix_last_modified_stamp	= v_stat->st_mtime;
X				/* 00:00:00 since JAN.1.1970 */
X#ifdef NOT_COMPATIBLE_MODE
X  hdr->unix_mode		= v_stat->st_mode;
X#else
X  hdr->unix_mode		= v_stat->st_mode;
X#endif
X
X  hdr->unix_uid			= v_stat->st_uid;
X  hdr->unix_gid			= v_stat->st_gid;
X
X  if ((v_stat->st_mode & S_IFMT) == S_IFDIR)
X    {
X      bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
X      hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
X      hdr->original_size = 0;
X      strcat (hdr->name, "/");
X    }
X}
X
X/* Write only unix extended header. */
Xwrite_header (nafp, hdr)
X     FILE *nafp;
X     LzHeader *hdr;
X{
X  int		header_size;
X  int		name_length;
X  char          data[LZHEADER_STRAGE], *ptr;
X  int           cnt;
X
X  bzero (data, LZHEADER_STRAGE);
X  bcopy (hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE);
X  setup_put (data + I_PACKED_SIZE);
X  put_longword (hdr->packed_size);
X  put_longword (hdr->original_size);
X  put_longword (hdr->last_modified_stamp);
X  put_word (hdr->attribute);
X  
X#ifdef STRICT
X
X  if ( hdr->name[1] == ':' )
X  {
X    name_length = strlen(hdr->name + 2);
X    put_byte (name_length);
X    bcopy (hdr->name + 2, data + I_NAME, name_length);
X  }
X  else
X  {
X    name_length = strlen(hdr->name);
X    put_byte (name_length);
X    bcopy (hdr->name, data + I_NAME, name_length);
X  }
X  
X  for ( ptr = data + I_NAME, cnt = 0; cnt < name_length; ptr++, cnt++ )
X  {
X    *ptr = toupper(*ptr);
X
X    if ( *ptr == '/' )
X      *ptr = '\\';
X  }
X#else
X  name_length = strlen (hdr->name);
X  put_byte (name_length);
X  bcopy (hdr->name, data + I_NAME, name_length);
X#endif
X  
X  setup_put (data + I_NAME + name_length);
X  put_word (hdr->crc);
X#ifdef STRICT
X  header_size = I_EXTEND_TYPE - 2 + name_length;
X#else
X  put_byte (OUR_EXTEND);
X  put_byte (CURRENT_UNIX_MINOR_VERSION);
X  put_longword ((long)hdr->unix_last_modified_stamp);
X  put_word (hdr->unix_mode);
X  put_word (hdr->unix_uid);
X  put_word (hdr->unix_gid);
X  header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
X#endif
X  data[I_HEADER_SIZE] = header_size;
X  data[I_HEADER_CHECKSUM] = calc_sum (data + I_METHOD, header_size);
X
X  if (fwrite (data, sizeof (char), header_size + 2, nafp) == NULL)
X    error ("cannot write to temporary file");
X}
X
Xboolean archive_is_msdos_sfx1 (name)
X     char *name;
X{
X  int	len = strlen (name);
X  return ((len >= 4) &&
X	  (strcmp (name + len - 4, ".com") == 0 ||
X	   strcmp (name + len - 4, ".exe") == 0));
X}
X
Xboolean skip_msdos_sfx1_code (fp)
X     FILE *fp;
X{
X  unsigned char buffer[2048];
X  unsigned char *p, *q;
X  int	n;
X
X  n = fread (buffer, sizeof (char), 2048, fp);
X
X  for (p = buffer + 2, q = buffer + n - 5; p < q; p ++)
X    {
X      /* found "-l??-" keyword (as METHOD type string) */
X      if (p[0] == '-' && p[1] == 'l' && p[4] == '-')
X	{
X	  /* size and checksum validate check */
X	  if (p[-2] > 20 && p[-1] == calc_sum (p, p[-2]))
X	    {
X              fseek (fp, (long) ((p - 2) - buffer) - n, SEEK_CUR);
X	      return TRUE;
X	    }
X	}
X    }
X
X  fseek (fp, (long) -n, SEEK_CUR);
X  return FALSE;
X}
X
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
Xmake_tmp_name (original, name)
X     char *original;
X     char *name;
X{
X#ifdef TMP_FILENAME_TEMPLATE
X  /* "/tmp/lhXXXXXX" etc. */
X  strcpy (name, TMP_FILENAME_TEMPLATE);
X#else
X  char *p, *s;
X
X  strcpy (name, original);
X  for (p = name, s = (char*)0; *p; p++)
X    if (*p == '/' || *p == '\\')
X      s = p;
X
X  strcpy ((s ? s+1 : name), "lhXXXXXX");
X#endif
X
X  mktemp (name);
X}
X
Xmake_backup_name (name, orginal)
X     char *name;
X     char *orginal;
X{
X  register char *p, *dot;
X
X  strcpy (name, orginal);
X  for (p = name, dot = (char*)0; *p; p ++)
X    {
X      if (*p == '.')
X	dot = p;
X      else if (*p == '/' || *p == '\\')
X	dot = (char*)0;
X    }
X
X  if (dot)
X    p = dot;
X
X#ifdef BACKUPNAME_EXTENTION
X  strcpy (p, BACKUPNAME_EXTENTION)
X#else
X  strcpy (p, ".bak");
X#endif
X}
X
Xmake_standard_archive_name (name, orginal)
X     char *name;
X     char *orginal;
X{
X  register char *p, *dot;
X
X  strcpy (name, orginal);
X  for (p = name, dot = (char*)0; *p; p ++)
X    {
X      if (*p == '.')
X	dot = p;
X      else if (*p == '/' || *p == '\\')
X	dot = (char*)0;
X    }
X
X  if (dot)
X    p = dot;
X
X#ifdef ARCHIVENAME_EXTENTION
X  strcpy (p, ARCHIVENAME_EXTENTION);
X#else
X  strcpy (p, ".lzh");
X#endif
X}
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
X
Xboolean need_file (name)
X     char *name;
X{
X  int	i;
X
X  if (cmd_filec == 0)
X    return TRUE;
X
X  for (i = 0; i < cmd_filec; i ++)
X    {
X      if (STRING_COMPARE (cmd_filev[i], name) == 0)
X	return TRUE;
X    }
X
X  return FALSE;
X}
X
XFILE *xfopen (name, mode)
X     char *name, *mode;
X{
X  FILE *fp;
X
X  if ((fp = fopen (name, mode)) == NULL)
X    error (name);
X
X  return fp;
X}
X
X
X/*----------------------------------------------------------------------*/
X/*		Listing Stuff						*/
X/*----------------------------------------------------------------------*/
X
X/* need 14 or 22 (when long_format_listing is TRUE) column spaces */
Xprint_size (packed_size, original_size)
X     long packed_size, original_size;
X{
X  if (long_format_listing)
X    printf ("%7ld ", packed_size);
X
X  printf ("%7ld ", original_size);
X
X  if (original_size == 0L)
X    printf ("******");
X  else
X    printf ("%3d.%1d%%",
X	    (int)((packed_size * 100L) / original_size),
X	    (int)((packed_size * 1000L) / original_size) % 10);
X}
X
X/* need 12 or 17 (when long_format_listing is TRUE) column spaces */
Xprint_stamp (t)
X     time_t t;
X{
X  static boolean	got_now = FALSE;
X  static time_t		now;
X  static unsigned int	threshold;
X  static char   t_month[12*3+1] = "JanFebMarAprMayJunJulAugSepOctNovDec";
X  struct tm		*p;
X
X  if (t == 0)
X    {
X      if (long_format_listing)
X	printf ("                 "); /* 17 spaces */
X      else
X	printf ("            ");	/* 12 spaces */
X
X      return;
X    }
X
X  if (!got_now)
X    {
X      time (&now);
X      p = localtime (&now);
X      threshold = p->tm_year * 12 + p->tm_mon - 6;
X      got_now = TRUE;
X    }
X
X  p = localtime (&t);
X
X  if (long_format_listing)
X    printf ("%.3s %2d %02d:%02d %04d",
X	    &t_month[p->tm_mon * 3], p->tm_mday,
X	    p->tm_hour, p->tm_min, p->tm_year + 1900);
X  else
X    if (p->tm_year * 12 + p->tm_mon > threshold)
X      printf ("%.3s %2d %02d:%02d",
X	      &t_month[p->tm_mon * 3], p->tm_mday, p->tm_hour, p->tm_min);
X    else
X      printf ("%.3s %2d  %04d",
X	      &t_month[p->tm_mon * 3], p->tm_mday, p->tm_year + 1900);
X}
X
Xprint_bar ()
X{
X  /* 17+1+(0 or 7+1)+7+1+6+1+(0 or 1+4)+(12 or 17)+1+20 */
X  /*       12345678901234567_  1234567_123456  _123456789012   1234      */
X  if (long_format_listing)
X#ifdef STRICT
X    printf ("------- ------- ------ ---- ----------------- -------------\n");
X#else
X    printf ("----------------- ------- ------- ------ ---- ----------------- -------------\n");
X#endif
X  else
X#ifdef STRICT
X    printf ("------- ------ ------------ --------------------\n");
X#else
X    printf ("----------------- ------- ------ ------------ --------------------\n");
X#endif
X}
X
X
X/*
X  view
X */
Xcmd_view ()
X{
X  FILE		*fp;
X  LzHeader	hdr;
X  register char	*p;
X  long		a_packed_size = 0L;
X  long		a_original_size = 0L;
X  int		n_files = 0;
X  struct stat	v_stat;
X
X  if ((fp = fopen (archive_name, RMODE)) == NULL)
X    if (!expand_archive_name (expanded_archive_name, archive_name))
X      error (archive_name);
X    else
X      {
X	errno = 0;
X        fp = xfopen (expanded_archive_name, RMODE);
X	archive_name = expanded_archive_name;
X      }
X
X  if (archive_is_msdos_sfx1 (archive_name))
X    {
X      skip_msdos_sfx1_code (fp);
X    }
X
X  if (!quiet)
X    {
X      /*       12345678901234567_  1234567_123456  _  123456789012  1234 */
X#ifdef STRICT
X      printf ("%s   SIZE  RATIO%s %s    STAMP   %s NAME\n",
X#else
X      printf (" PERMSSN  UID GID %s   SIZE  RATIO%s %s    STAMP   %s NAME\n",
X#endif
X	      long_format_listing ? " PACKED " : "", /* 8,0 */
X	      long_format_listing ? "  CRC" : "", /* 5,0 */
X	      long_format_listing ? "  " : "", /* 2,0 */
X	      long_format_listing ? "   " : ""); /* 3,0 */
X      print_bar ();
X    }
X
X  while (get_header (fp, &hdr))
X    {
X      if (need_file (hdr.name))
X	{
X	  if (hdr.extend_type == EXTEND_UNIX)
X            {
X#ifndef STRICT
X              printf ("%c%c%c%c%c%c%c%c%c%4d/%-4d",
X		  ((hdr.unix_mode & UNIX_OWNER_READ_PERM)  ? 'r' : '-'),
X		  ((hdr.unix_mode & UNIX_OWNER_WRITE_PERM) ? 'w' : '-'),
X		  ((hdr.unix_mode & UNIX_OWNER_EXEC_PERM)  ? 'x' : '-'),
X		  ((hdr.unix_mode & UNIX_GROUP_READ_PERM)  ? 'r' : '-'),
X		  ((hdr.unix_mode & UNIX_GROUP_WRITE_PERM) ? 'w' : '-'),
X		  ((hdr.unix_mode & UNIX_GROUP_EXEC_PERM)  ? 'x' : '-'),
X		  ((hdr.unix_mode & UNIX_OTHER_READ_PERM)  ? 'r' : '-'),
X		  ((hdr.unix_mode & UNIX_OTHER_WRITE_PERM) ? 'w' : '-'),
X		  ((hdr.unix_mode & UNIX_OTHER_EXEC_PERM)  ? 'x' : '-'),
X		  hdr.unix_uid, hdr.unix_gid);
X#endif
X	    }
X	  else
X	    {
X	      switch (hdr.extend_type)
X		{			/* max 18 characters */
X                case EXTEND_GENERIC:    p = "[Generic]"; break;
X
X		case EXTEND_CPM:	p = "[CP/M]"; break;
X
X		  /* OS-9 and FLEX's CPU is MC-6809. I like it. :-)  */
X		case EXTEND_FLEX:	p = "[FLEX]"; break;
X
X		case EXTEND_OS9:	p = "[OS-9]"; break;
X
X		  /* I guessed from this ID.  Is this right? */
X		case EXTEND_OS68K:	p = "[OS-9/68K]"; break;
X
X		case EXTEND_MSDOS:	p = "[MS-DOS]"; break;
X
X		  /* I have Macintosh. :-)  */
X		case EXTEND_MACOS:	p = "[Mac OS]"; break;
X
X		case EXTEND_OS2:	p = "[OS/2]"; break;
X
X		case EXTEND_HUMAN:	p = "[Human68K]"; break;
X
X		case EXTEND_OS386:	p = "[OS-386]"; break;
X
X#ifdef EXTEND_TOWNSOS
X		  /* This ID isn't fixed */
X		case EXTEND_TOWNSOS:	p = "[TownsOS]"; break;
X#endif
X
X		  /* Ouch!  Please customize it's ID.  */
X                default:                p = "[Unknown]"; break;
X                }
X#ifndef STRICT
X              printf ("%-18.18s", p);
X#endif
X	    }
X
X	  print_size (hdr.packed_size, hdr.original_size);
X
X	  if (long_format_listing)
X	    if (hdr.has_crc)
X	      printf (" %04x", hdr.crc);
X	    else
X	      printf (" ****");
X
X	  printf (" ");
X	  print_stamp (hdr.unix_last_modified_stamp);
X	  printf (" %s\n", hdr.name);
X	  n_files ++;
X	  a_packed_size += hdr.packed_size;
X	  a_original_size += hdr.original_size;
X	}
X      fseek (fp, hdr.packed_size, SEEK_CUR);
X    }
X
X  fclose (fp);
X  if (!quiet)
X    {
X      print_bar ();
X
X#ifndef STRICT
X      printf (" Total %4d file%c ",
X	      n_files, (n_files == 1) ? ' ' : 's');
X#endif
X      print_size (a_packed_size, a_original_size);
X      printf (" ");
X
X      if (long_format_listing)
X	printf ("     ");
X
X      if (stat (archive_name, &v_stat) < 0)
X	print_stamp ((time_t)0);
X      else
X	print_stamp (v_stat.st_mtime);
X
X#ifdef STRICT
X      printf (" %4d file%c ",
X	      n_files, (n_files == 1) ? ' ' : 's');
X#endif
X      printf ("\n");
X    }
X
X  return;
X}
X
X
Xboolean make_parent_path (name)
X     char *name;
X{
X  char		path[FILENAME_LENGTH];
X  struct stat	v_stat;
X  register char	*p;
X
X /* make parent directory name into PATH for recursive call */
X  strcpy (path, name);
X  for (p = path + strlen (path); p > path; p --)
X    if (p[-1] == '/' || p[-1] == '\\')
X      {
X	p[-1] = '\0';
X	break;
X      }
X
X  if (p == path)
X    return FALSE;		/* no more parent. */
X
X  if (stat (path, &v_stat) >= 0)
X    {
X      if ((v_stat.st_mode & S_IFMT) != S_IFDIR)
X	return FALSE;		/* already exist. but it isn't directory. */
X      return TRUE;		/* already exist its directory. */
X    }
X
X  errno = 0;
X
X  if (!quiet)
X    message ("Making Directory", path);
X
X  if (mkdir (path, 0777) >= 0)	/* try */
X    return TRUE;		/* successful done. */
X
X  errno = 0;
X
X  if (!make_parent_path (path))
X    return FALSE;
X
X  if (mkdir (path, 0777) < 0)		/* try again */
X    return FALSE;
X
X  return TRUE;
X}
X
XFILE *open_with_make_path (name)
X     char *name;
X{
X  FILE		*fp;
X  struct stat	v_stat;
X  char		buffer[1024];
X
X  if (stat (name, &v_stat) >= 0)
X    {
X      if ((v_stat.st_mode & S_IFMT) != S_IFREG)
X	return NULL;
X
X      if (!force)
X	{
X	  for (;;)
X	    {
X	      fprintf (stderr, "%s OverWrite ?(Yes/No/All) ", name);
X	      fflush (stderr);
X	      gets (buffer);
X	      if (buffer[0] == 'N' || buffer[0] == 'n')
X		return NULL;
X	      if (buffer[0] == 'Y' || buffer[0] == 'y')
X		break;
X	      if (buffer[0] == 'A' || buffer[0] == 'a')
X		{
X		  force = TRUE;
X		  break;
X		}
X	    }
X	}
X    }
X
X  fp = fopen (name, WMODE);
X  if (!fp)
X    {
X      errno = 0;
X      if (!make_parent_path (name))
X	return NULL;
X
X      fp = fopen (name, WMODE);
X      if (!fp)
X        message ("Error:", name);
X    }
X  return fp;
X}
X
X#ifdef MSDOS
Xvoid dosname(char *name)
X{
X  char *ptr, *first = NULL, *last = NULL;
X  char temp[8];
X
X  for ( ptr = strchr(name, 0); ptr >= name; ptr-- )
X    if ( *ptr == '.' )
X    {
X      if ( last == NULL )
X        last = ptr;
X    }
X    else if ( (*ptr == '/') || (*ptr == '\\') )
X    {
X      first = ptr + 1;
X      break;
X    }
X
X  if ( first == NULL )
X    first = name;
X  if ( last == NULL )
X    last = strchr(name, 0);
X
X  for ( ptr = first; ptr < last; ptr++ )
X    if ( *ptr == '.' )
X      *ptr = '_';
X
X  if ( strlen(last) > 4 )
X    last[4] = 0;
X
X  if ( last - first > 8 )
X  {
X    strcpy(temp, last);
X    strcpy(first + 8, last);
X  }
X}
X#endif
X
Xextern int decode_lzhuf (), decode_larc ();
Xextern int decode_stored_crc (), decode_stored_nocrc ();
X
Xextract_one (fp, hdr)
X     FILE *fp;
X     LzHeader *hdr;
X{
X  FILE		*ofp;		/* output file */
X  char		name[1024];
X  time_t	utimebuf[2];
X  int		crc;
X  int		(*decode_proc)(); /* (ifp,ofp,original_size,name) */
X  int		save_quiet;
X
X  strcpy (name, hdr->name);
X  if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR)
X    {
X      if (bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) == 0)
X	decode_proc = decode_lzhuf;
X      else if ((bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) == 0) ||
X	       (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) == 0))
X	decode_proc = (hdr->has_crc) ? decode_stored_crc : decode_stored_nocrc;
X      else if (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) == 0)
X	decode_proc = decode_larc;
X      else
X        message ("Error:", "Sorry, Cannot Extract this method.");
X
X      reading_filename = archive_name;
X      writting_filename = name;
X      if (output_to_stdout)
X	{
X          if (!quiet)
X            printf ("::::::::\r\n%s\r\n::::::::\r\n", name);
X
X          if ( strlen(pager) != 0 )
X            ofp = popen(pager, WMODE);
X          else
X            ofp = stdout;
X
X	  save_quiet = quiet;
X          quiet = TRUE;
X          crc = (*decode_proc) (fp, ofp, hdr->original_size, name);
X          quiet = save_quiet;
X
X          if ( strlen(pager) != 0 )
X            pclose(ofp);
X	}
X      else if (output_to_test)
X        {
X          ofp = fopen(NULLFILE, WMODE);
X          crc = (*decode_proc) (fp, ofp, hdr->original_size, name);
X          fclose(ofp);
X        }
X      else
X        {
X#ifdef MSDOS
X          dosname(name);
X#endif
X	  if ((ofp = open_with_make_path (name)) == NULL)
X	    return;
X	  else
X	    {
X	      crc = (*decode_proc) (fp, ofp, hdr->original_size, name);
X	      fclose (ofp);
X	    }
X	}
X
X      if (hdr->has_crc && (crc != hdr->crc))
X        if (output_to_test)
X          message ("Error:", "CRC failed\a");
X        else
X          error ("CRC failed\a");
X    }
X  else
X    {
X      /* NAME has trailing SLASH '/', (^_^) */
X      if (!output_to_stdout &&
X	  !make_parent_path (name))
X	error (name);
X    }
X
X  if (!output_to_stdout && !output_to_test)
X    {
X      utimebuf[0] = utimebuf[1] = hdr->unix_last_modified_stamp;
X      utime (name, utimebuf);
X
X#ifdef NOT_COMPATIBLE_MODE
X      setfilemode(name, hdr->attribute);
X#else
X      chmod (name, hdr->unix_mode);
X#endif
X
X#ifndef MSDOS
X      chown (name, hdr->unix_uid, hdr->unix_gid);
X#endif
X      errno = 0;
X    }
X}
X
X
X/*
X  extract
X */
Xcmd_extract ()
X{
X  LzHeader	hdr;
X  long		pos;
X  FILE		*fp;
X
X  if ((fp = fopen (archive_name, RMODE)) == NULL)
X    if (!expand_archive_name (expanded_archive_name, archive_name))
X      error (archive_name);
X    else
X      {
X	errno = 0;
X        fp = xfopen (expanded_archive_name, RMODE);
X	archive_name = expanded_archive_name;
X      }
X
X  if (archive_is_msdos_sfx1 (archive_name))
X    {
X      skip_msdos_sfx1_code (fp);
X    }
X
X  while (get_header (fp, &hdr))
X    {
X      if (need_file (hdr.name))
X	{
X	  pos = ftell (fp);
X	  extract_one (fp, &hdr);
X	  fseek (fp, pos + hdr.packed_size, SEEK_SET);
X	} else {
X	  fseek (fp, hdr.packed_size, SEEK_CUR);
X	}
X    }
X
X  fclose (fp);
X
X  return;
X}
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
Xextern int encode_lzhuf ();
Xextern int encode_storerd_crc ();
X
Xappend_one (fp, nafp, hdr)
X     FILE *fp, *nafp;
X     LzHeader *hdr;
X{
X  long	header_pos, next_pos, org_pos, data_pos;
X  long	v_original_size, v_packed_size;
X
X  reading_filename = hdr->name;
X  writting_filename = temporary_name;
X
X  org_pos = ftell (fp);
X  header_pos = ftell (nafp);
X  write_header (nafp, hdr);	/* DUMMY */
X
X  if (hdr->original_size == 0)
X    return;			/* previous write_header is not DUMMY. (^_^) */
X
X  data_pos = ftell (nafp);
X  hdr->crc = encode_lzhuf (fp, nafp, hdr->original_size,
X			   &v_original_size, &v_packed_size, hdr->name);
X  if (v_packed_size < v_original_size)
X    {
X      next_pos = ftell (nafp);
X    }
X  else
X    {				/* retry by stored method */
X      fseek (fp, org_pos, SEEK_SET);
X      fseek (nafp, data_pos, SEEK_SET);
X      hdr->crc = encode_stored_crc (fp, nafp, hdr->original_size,
X				    &v_original_size, &v_packed_size);
X      fflush (nafp);
X      next_pos = ftell (nafp);
X      ftruncate (fileno (nafp), next_pos);
X      bcopy (LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
X    }
X  hdr->original_size = v_original_size;
X  hdr->packed_size = v_packed_size;
X  fseek (nafp, header_pos, SEEK_SET);
X  write_header (nafp, hdr);
X  fseek (nafp, next_pos, SEEK_SET);
X}
X
Xwrite_tail (nafp)
X     FILE *nafp;
X{
X  putc (0x00, nafp);
X}
X
Xcopy_old_one (oafp, nafp, hdr)
X     FILE *oafp, *nafp;
X     LzHeader *hdr;
X{
X  if (noexec)
X    {
X      fseek (oafp, (long)(hdr->header_size + 2) + hdr->packed_size, SEEK_CUR);
X    }
X  else
X    {
X      reading_filename = archive_name;
X      writting_filename = temporary_name;
X      copy_file (oafp, nafp, (long)(hdr->header_size + 2) + hdr->packed_size);
X    }
X}
X
X
XFILE *append_it (name, oafp, nafp)
X     char *name;
X     FILE *oafp, *nafp;
X{
X  LzHeader	ahdr, hdr;
X  FILE		*fp;
X  long		old_header;
X  int		cmp;
X  int		filec;
X  char		**filev;
X  int		i;
X
X  struct stat	v_stat;
X  boolean	directory;
X
X  if (!delete_from_archive)
X    if (stat (name, &v_stat) < 0)
X      {
X        message ("Error:", name);
X        return oafp;
X      }
X
X  directory = ((v_stat.st_mode & S_IFMT) == S_IFDIR);
X
X  init_header (name, &v_stat, &hdr);
X
X  if (!delete_from_archive && !directory && !noexec)
X    fp = xfopen (name, RMODE);
X
X  while (oafp)
X    {
X      old_header = ftell (oafp);
X      if (!get_header (oafp, &ahdr))
X	{
X	  fclose (oafp);
X	  oafp = NULL;
X	  break;
X	}
X      else
X	{
X	  cmp = STRING_COMPARE (ahdr.name, hdr.name);
X	  if (cmp < 0)
X	    {		/* SKIP */
X	      fseek (oafp, old_header, SEEK_SET);
X	      copy_old_one (oafp, nafp, &ahdr);
X	    }
X	  else if (cmp == 0)
X	    {		/* REPLACE */
X	      fseek (oafp, ahdr.packed_size, SEEK_CUR);
X	      break;
X	    }
X	  else		/* cmp > 0, INSERT */
X	    {
X	      fseek (oafp, old_header, SEEK_SET);
X	      break;
X	    }
X	}
X    }
X
X  if (delete_from_archive)
X    {
X      if (noexec)
X        fprintf (stderr, "DELETE %s\n", name);
X      else
X        printf ("%s - Deleted\n", name);
X    }
X  else
X    {
X      if ( !oafp || (cmp > 0) || !update_if_newer
X           || (ahdr.unix_last_modified_stamp < hdr.unix_last_modified_stamp) )
X	{
X	  if (noexec)
X	    fprintf (stderr, "APPEND %s\n", name);
X          else
X#ifdef STRICT
X            if ( !directory )
X#endif
X              if ( !update_freshen || (cmp == 0) )
X                append_one (fp, nafp, &hdr);
X	}
X      else
X	{					/* archive has old one */
X	  fseek (oafp, old_header, SEEK_SET);
X	  copy_old_one (oafp, nafp, &ahdr);
X	}
X
X      if (!directory)
X	{
X	  if (!noexec)
X	    fclose (fp);
X	}
X      else
X	{			/* recurcive call */
X	  if (find_files (name, &filec, &filev))
X	    {
X	      for (i = 0; i < filec; i ++)
X		oafp = append_it (filev[i], oafp, nafp);
X	      free_files (filec, filev);
X	    }
X	  return oafp;
X	}
X    }
X
X  return oafp;
X}
X
X
Xremove_it (name)
X     char *name;
X{
X  struct stat	v_stat;
X  int		i;
X  char		**filev;
X  int		filec;
X
X  if (stat (name, &v_stat) < 0)
X    {
X      fprintf (stderr, "Cannot access \"%s\".\n", name);
X      return;
X    }
X
X  if ((v_stat.st_mode & S_IFMT) == S_IFDIR)
X    {
X      if (!find_files (name, &filec, &filev))
X	{
X          fprintf (stderr, "Cannot open directory \"%s\".\n", name);
X	  return;
X	}
X
X      for (i = 0; i < filec; i ++)
X	remove_it (filev[i]);
X
X      free_files (filec, filev);
X
X      if (noexec)
X        printf ("REMOVE DIR %s\n", name);
X      else if (rmdir (name) < 0)
X        fprintf (stderr, "Cannot remove directory \"%s\".\n", name);
X      else if (!quiet)
X        printf ("%s - Removed\n", name);
X    }
X  else
X    {
X      if (noexec)
X        printf ("REMOVE %s\n", name);
X      else if (unlink (name) < 0)
X        fprintf (stderr, "Cannot delete \"%s\".\n", name);
X      else if (!quiet)
X        printf ("%s - Removed\n", name);
X    }
X}
X
X#ifdef FASTCOPY
X#define BUFFER_SIZE 16384
X
X#ifndef O_BINARY
X#define O_BINARY 0
X#endif
X
Xcopy_archive(src,dst )
Xchar *src;
Xchar *dst;
X{
X  int ih, oh;
X  unsigned chunk;
X  char *buffer = (char *) rson;
X
X  printf ("Copying temp to archive ... ");
X
X  ih = open (src, O_RDONLY | O_BINARY);
X  if ( ih == -1 )
X    error(src);
X  oh = open (dst, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
X  if ( oh == -1 )
X    error(dst);
X
X  while ( (chunk = read(ih, buffer, BUFFER_SIZE)) > 0 )
X    if ( write(oh, buffer, chunk) != chunk )
X      error(dst);
X
X  close (ih);
X  close (oh);
X
X  printf("\b\b\b\b   \b\b\b\b.\n");
X}
X#endif
X
Xcmd_append ()
X{
X  LzHeader	ahdr;
X  FILE		*oafp, *nafp;
X  char		backup_archive_name [ FILENAME_LENGTH ];
X  char		new_archive_name_buffer [ FILENAME_LENGTH ];
X  char		*new_archive_name;
X  int		i;
X  long		old_header;
X  struct stat	v_stat;
X  boolean	old_archive_exist;
X  extern	rename();
X
X  if (cmd_filec == 0)
X    return;
X
X  make_tmp_name (archive_name, temporary_name);
X
X  if ((oafp = fopen (archive_name, RMODE)) == NULL)
X    if (expand_archive_name (expanded_archive_name, archive_name))
X      {
X	errno = 0;
X        oafp = fopen (expanded_archive_name, RMODE);
X	archive_name = expanded_archive_name;
X      }
X
X  old_archive_exist = (oafp) ? TRUE : FALSE;
X  if (new_archive && oafp)
X    {
X      fclose (oafp);
X      oafp = NULL;
X    }
X
X  if (oafp && archive_is_msdos_sfx1 (archive_name))
X    {
X      skip_msdos_sfx1_code (oafp);
X      make_standard_archive_name (new_archive_name_buffer, archive_name);
X      new_archive_name = new_archive_name_buffer;
X    }
X  else
X    {
X      new_archive_name = archive_name;
X    }
X
X  errno = 0;
X  if (!noexec)
X    {
X      nafp = xfopen (temporary_name, WMODE);
X      remove_temporary_at_error = TRUE;
X    }
X
X  for (i = 0; i < cmd_filec; i ++)
X    oafp = append_it (cmd_filev[i], oafp, nafp);
X
X  if (oafp)
X    {
X      old_header = ftell (oafp);
X      while (get_header (oafp, &ahdr))
X	{
X	  fseek (oafp, old_header, SEEK_SET);
X	  copy_old_one (oafp, nafp, &ahdr);
X	  old_header = ftell (oafp);
X	}
X      fclose (oafp);
X    }
X
X  if (!noexec)
X    {
X      write_tail (nafp);
X      fclose (nafp);
X    }
X
X  make_backup_name (backup_archive_name, archive_name);
X
X  if (!noexec && old_archive_exist)
X  {
X#ifdef ORIGINAL
X    if (rename(archive_name, backup_archive_name) < 0)
X      error (archive_name);
X    unlink(backup_archive_name);
X#endif
X  }
X
X  if (!quiet && new_archive_name == new_archive_name_buffer)
X    {				/* warning at old archive is SFX */
X      printf ("New Archive File is \"%s\"\n", new_archive_name);
X    }
X
X#ifdef ORIGINAL
X  if (!noexec && rename(temporary_name, new_archive_name) < 0)
X#endif
X
X    {
X
X      if (stat (temporary_name, &v_stat) < 0)
X	error (temporary_name);
X#ifdef FASTCOPY
X      copy_archive(temporary_name, archive_name);
X#else
X      oafp = xfopen (temporary_name, RMODE);
X      nafp = xfopen (archive_name, WMODE);
X      reading_filename = temporary_name;
X      writting_filename = archive_name;
X      copy_file (oafp, nafp, (long)v_stat.st_size);
X      fclose (nafp);
X      fclose (oafp);
X#endif
X
X      unlink (temporary_name);
X    }
X  remove_temporary_at_error = FALSE;
X
X  if (delete_after_append)
X    {
X      if (!quiet && !noexec)
X	printf ("Erasing...\n");
X      for (i = 0; i < cmd_filec; i ++)
X	remove_it (cmd_filev[i]);
X    }
X
X  return;
X}
END_OF_lharc.c
if test 49791 -ne `wc -c <lharc.c`; then
    echo shar: \"lharc.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lhdir.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lhdir.h\"
else
echo shar: Extracting \"lhdir.h\" \(1254 characters\)
sed "s/^X//" >lhdir.h <<'END_OF_lhdir.h'
X/*
X * @(#) dir.h 1.4 87/11/06   Public Domain.
X *
X *  A public domain implementation of BSD directory routines for
X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
X *  August 1897
X *  Ported to OS/2 by Kai Uwe Rommel and added scandir prototype
X *  December 1989
X */
X
X#define	rewinddir(dirp)	seekdir(dirp, 0L)
X
X#define	MAXNAMLEN	12
X
Xstruct direct
X{
X	ino_t	d_ino;			/* a bit of a farce */
X	int	d_reclen;		/* more farce */
X	int	d_namlen;		/* length of d_name */
X        char    d_name[MAXNAMLEN + 1];  /* garentee null termination */
X};
X
Xstruct _dircontents
X{
X	char	*_d_entry;
X	struct _dircontents	*_d_next;
X};
X
Xtypedef struct _dirdesc
X{
X	int		dd_id;	/* uniquely identify each open directory */
X	long		dd_loc;	/* where we are in directory entry is this */
X	struct _dircontents	*dd_contents;	/* pointer to contents of dir */
X	struct _dircontents	*dd_cp;	/* pointer to current position */
X} DIR;
X
Xextern  DIR            *opendir(char *);
Xextern  struct direct  *readdir(DIR *);
Xextern  void            seekdir(DIR *, long);
Xextern  long            telldir(DIR *);
Xextern  void            closedir(DIR *);
X
Xextern  int             scandir(char *, struct direct ***,
X                                int (*)(struct direct *), int (*)());
END_OF_lhdir.h
if test 1254 -ne `wc -c <lhdir.h`; then
    echo shar: \"lhdir.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lhio.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lhio.c\"
else
echo shar: Extracting \"lhio.c\" \(6280 characters\)
sed "s/^X//" >lhio.c <<'END_OF_lhio.c'
X/*----------------------------------------------------------------------*/
X/*		File I/O module for LHarc UNIX				*/
X/*									*/
X/*		Copyright(C) MCMLXXXIX  Yooichi.Tagawa			*/
X/*									*/
X/*  V0.00  Original				1989.06.25  Y.Tagawa	*/
X/*  V0.03  Release #3  Beta Version		1989.07.02  Y.Tagawa	*/
X/*  V0.03a Fix few bugs				1989.07.04  Y.Tagawa	*/
X/*----------------------------------------------------------------------*/
X
X#include <stdio.h>
X#include "lhio.h"
X
X#ifndef BUFFER_SIZE
X#define BUFFER_SIZE	16384
X#endif
X
X
Xextern int	text_mode;			/* in lharc.c */
XFILE            *crc_infile, *crc_outfile;      /* in lzhuf.c */
X
Xextern int rson[];
X
X/* These functions are NO-RETURN */
Xextern read_error ();
Xextern write_error ();
X
X
Xint		crc_getc_cashe;
Xunsigned int	crc_value;
Xunsigned int	crc_table[0x100];
Xlong		crc_size;
X
X
Xcrcsub (ptr, length)
X     char		*ptr;
X     register int	length;
X{
X  register unsigned char	*p;
X  register unsigned int		ctmp;
X
X  if (length != 0)
X    {
X      ctmp = crc_value;
X      p = (unsigned char*)ptr;
X      for (; length; length --)
X	{
X	  ctmp ^= (unsigned int)*p++;
X	  ctmp = (ctmp >> 8) ^ crc_table [ ctmp & 0xff ];
X	}
X      crc_value = ctmp;
X    }
X}
X
X#ifndef __GNUC__
Xvoid putc_crc (c)
X     int c;
X{
X  CRC_CHAR (c);
X  if (!text_mode || (c != 0x0d && c != 0x1a))
X    {
X      putc (c, crc_outfile);
X    }
X}
X
Xint getc_crc ()
X{
X  int	c;
X
X  if (crc_getc_cashe != EOF)
X    {
X      c = crc_getc_cashe;
X      crc_getc_cashe = EOF;
X      CRC_CHAR (c);
X      crc_size++;
X    }
X  else if ((c = getc (crc_infile)) != EOF)
X    {
X      if (text_mode && c == 0x0a)
X	{
X	  crc_getc_cashe = c;
X	  c = 0x0d;
X	}
X      CRC_CHAR (c);
X      crc_size++;
X    }
X  return c;
X}
X#endif
X
X
X
Xinit_crc ()
X{
X  static int		inited = 0;
X  register unsigned int	*p = crc_table;
X  register int		i, j;
X  register unsigned int	x;
X
X  if (!inited) {
X    for (j = 0; j < 256; j ++) {
X      x = j;
X      for (i = 0; i < 8; i ++) {
X	if ((x & 1) != 0) {
X	  x = (x >> 1) ^ 0xa001;
X	} else {
X	  x = (x >> 1);
X	}
X      }
X      *p ++ = x;
X    }
X    inited = 1;
X  }
X  crc_value = 0;
X  crc_getc_cashe = EOF;
X  crc_size = 0;
X}
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
X/* if return value is -1, see errno */
Xcopy_binary_file (ifp, ofp, size, crc_flag)
X     FILE	*ifp, *ofp;
X     long	size;
X     int	crc_flag;	/* as boolean value */
X{
X  char *buffer = (char *) rson;
X  int read_size;
X  int n;
X
X  /* safty */
X  fflush (ofp);
X
X  while (size > 0)
X    {
X      read_size = ((size < (long)BUFFER_SIZE) ? (int)size : BUFFER_SIZE);
X
X      n = fread (buffer, sizeof (char), read_size, ifp);
X
X      if (n == 0)
X	read_error ();
X
X      if (fwrite (buffer, sizeof (char), n, ofp) < n)
X	write_error ();
X
X      if (crc_flag)
X	crcsub (buffer, n);
X
X      size -= (long)n;
X    }
X}
X
X/* read UNIX text file '0A' and write generic text file '0D0A' */
Xwrite_generic_text_file (ifp, ofp, size)
X     FILE	*ifp, *ofp;
X     long	size;
X{
X  char		buffer[BUFFER_SIZE];
X  int		read_size, write_count, n, m;
X  register char	*p, *p1, *e;
X
X  /* safty */
X  fflush (ofp);
X
X  write_count = 0;
X
X  while (size > 0)
X    {
X      read_size = ((size < BUFFER_SIZE) ? (int)size : BUFFER_SIZE);
X
X      n = fread (buffer, sizeof (char), read_size, ifp);
X
X      if (n == 0)
X	read_error ();
X
X      for (p1 = p = buffer, e = buffer + n; p < e; p++)
X	{
X	  if (*p == '\n')
X	    {
X	      if ((m = p - p1) != 0)
X		{
X		  if (fwrite (p1, sizeof (char), m, ofp) < m)
X		    write_error ();
X		  crcsub (p1, m);
X		}
X	      putc (0x0d, ofp);
X	      if (feof (ofp))
X		write_error ();
X	      CRC_CHAR (0x0d);
X	      p1 = p;
X	      write_count ++;
X	    }
X	}
X      if ((m = p - p1) != 0)
X	{
X	  if (fwrite (p1, sizeof (char), m, ofp) < m)
X	    write_error ();
X	  crcsub (p1, m);
X	}
X
X      write_count += (long)n;
X      size -= (long)n;
X    }
X
X  crc_size = write_count;
X}
X
X/* read generic text file '0D0A' and write UNIX text file '0A' */
Xread_generic_text_file (ifp, ofp, size, crc_flag)
X     FILE	*ifp, *ofp;
X     long	size;
X     int	crc_flag;
X{
X  char		buffer[BUFFER_SIZE];
X  int		read_size, write_size, n, m;
X  register char *p, *p1, *e;
X
X  /* safty */
X  fflush (ofp);
X
X  while (size > 0)
X    {
X      read_size = ((size < BUFFER_SIZE) ? (int)size : BUFFER_SIZE);
X
X      n = fread (buffer, sizeof (char), read_size, ifp);
X
X      if (n == 0)
X	read_error ();
X
X      crcsub (buffer, n);
X
X      for (p1 = p = buffer, e = buffer + n; p < e; p ++)
X	{
X	  if (*p == 0x0d)
X	    {
X	      if ((m = p - p1) != 0)
X		{
X		  if (fwrite (p1, sizeof (char), m, ofp) < m)
X		    write_error ();
X		}
X	      p1 = p+1;
X	    }
X	}
X      if ((m = p - p1) != 0)
X	{
X	  if (fwrite (p1, sizeof (char), m, ofp) < m)
X	    write_error ();
X	}
X
X      size -= (long)n;
X    }
X}
X
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
X
Xcopy_file (ifp, ofp, size)
X     FILE	*ifp, *ofp;
X     long	size;
X{
X  copy_binary_file (ifp, ofp, size, 0);
X}
X
X/*ARGSUSED*/
Xint decode_stored_crc (ifp, ofp, original_size, name)
X     FILE	*ifp, *ofp;
X     long	original_size;
X     char	*name;
X{
X  init_crc ();
X
X  if (text_mode)
X    {
X      read_generic_text_file (ifp, ofp, original_size, 1);
X      return crc_value;
X    }
X  else
X    {
X      copy_binary_file (ifp, ofp, original_size, 1);
X      return crc_value;
X    }
X}
X
X/*ARGSUSED*/
Xint decode_stored_nocrc (ifp, ofp, original_size, name)
X     FILE	*ifp, *ofp;
X     long	original_size;
X     char	*name;
X{
X  if (text_mode)
X    {
X      read_generic_text_file (ifp, ofp, original_size, 0);
X      return 0;			/* DUMMY */
X    }
X  else
X    {
X      copy_binary_file (ifp, ofp, original_size, 0);
X    }
X  return 0;			/* DUMMY */
X}
X
Xint encode_stored_crc (ifp, ofp, size, original_size_var, write_size_var)
X     FILE       *ifp, *ofp;
X     long       size;
X     long	*original_size_var;
X     long	*write_size_var;
X{
X  init_crc ();
X
X  if (text_mode)
X    {
X      write_generic_text_file (ifp, ofp, size);
X      *original_size_var = *write_size_var = crc_size;
X      return crc_value;
X    }
X  else
X    {
X      copy_binary_file (ifp, ofp, size, 1);
X      *original_size_var = size;
X      *write_size_var = size;
X      return crc_value;
X    }
X}
END_OF_lhio.c
if test 6280 -ne `wc -c <lhio.c`; then
    echo shar: \"lhio.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lhio.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lhio.h\"
else
echo shar: Extracting \"lhio.h\" \(1388 characters\)
sed "s/^X//" >lhio.h <<'END_OF_lhio.h'
X/*----------------------------------------------------------------------*/
X/*		File I/O module for LHarc UNIX				*/
X/*									*/
X/*		Copyright(C) MCMLXXXIX  Yooichi.Tagawa			*/
X/*									*/
X/*  V0.00  Original				1989.06.25  Y.Tagawa	*/
X/*  V0.03  Release #3  Beta Version		1989.07.02  Y.Tagawa	*/
X/*----------------------------------------------------------------------*/
X
Xextern int		text_mode;
X
Xextern unsigned int	crc_table[0x100];
Xextern unsigned int	crc_value;
Xextern int		crc_getc_cashe;
Xextern FILE		*crc_infile, *crc_outfile;
Xextern long		crc_size;
X
X
X#define CRC_CHAR(c)						\
X{ register unsigned int ctmp = crc_value ^ c; 			\
X    crc_value = (ctmp >> 8) ^ crc_table [ ctmp & 0xff ]; }
X
X
X
X#if defined (__GNUC__)
X/*#define inlnie*/
X
X/* DECODING */
X/* '0D0A' -> '0A' conversion and strip '1A' when text_mode */
Xstatic inline putc_crc (int c)
X{
X  CRC_CHAR (c);
X  if (!text_mode || (c != 0x0d && c != 0x1a))
X    {
X      putc (c, crc_outfile);
X    }
X}
X
X/* ENCODING */
X/* '0A' -> '0D0A' conversion when text_mode */
Xstatic inline int getc_crc ()
X{
X  int	c;
X
X  if (crc_getc_cashe != EOF)
X    {
X      c = crc_getc_cashe;
X      crc_getc_cashe = EOF;
X      CRC_CHAR (c);
X      crc_size++;
X    }
X  else if ((c = getc (crc_infile)) != EOF)
X    {
X      if (text_mode && c == 0x0a)
X	{
X	  crc_getc_cashe = c;
X	  c = 0x0d;
X	}
X      CRC_CHAR (c);
X      crc_size++;
X    }
X  return c;
X}
X#endif
END_OF_lhio.h
if test 1388 -ne `wc -c <lhio.h`; then
    echo shar: \"lhio.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f lzhuf.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"lzhuf.c\"
else
echo shar: Extracting \"lzhuf.c\" \(22465 characters\)
sed "s/^X//" >lzhuf.c <<'END_OF_lzhuf.c'
X/*----------------------------------------------------------------------*/
X/*		lzhuf.c : Encoding/Decoding module for LHarc		*/
X/*									*/
X/*	LZSS Algorithm			Haruhiko.Okumura		*/
X/*	Adaptic Huffman Encoding	1989.05.27  Haruyasu.Yoshizaki	*/
X/*									*/
X/*									*/
X/*	Modified for UNIX LHarc V0.01	1989.05.28  Y.Tagawa		*/
X/*	Modified for UNIX LHarc V0.02	1989.05.29  Y.Tagawa		*/
X/*	Modified for UNIX LHarc V0.03	1989.07.02  Y.Tagawa		*/
X/*----------------------------------------------------------------------*/
X
X/* Use ANSI sequences for using only one line per file but
X * indicator dots on next line */
X/* #define ANSI */
X
X#ifndef ANSI
X#define DOT       '.'
X#define BALL      'o'
X#else
X#define DOT       249
X#define BALL      3
X#define CURSORUP  "\033[A"
X#define ERASEEOL  "\033[K"
X#endif
X
X#include <stdio.h>
X
X#ifndef SELFMAIN
X#include "lhio.h"
X#else
X#define EXIT_SUCCESS	0
X#define EXIT_FAILURE	1
X#endif
X
X
X
XFILE *infile, *outfile;
Xlong textsize, codesize;
X
X
X#define INDICATOR_THRESHOLD	4096L
X#define MAX_INDICATOR_COUNT     78
Xlong indicator_count;
Xlong indicator_threshold;
X
X#ifdef SELFMAIN
Xint quiet = 0;
X#else
Xextern int quiet;
Xextern int output_to_test;
X#endif
X
X
X#ifdef SELFMAIN
X#define SETUP_PUTC_CRC(fp)	/* nothing */
X#define SETUP_GETC_CRC(fp)	/* nothing */
X#define PUTC_CRC(c)		putc((c),(outfile))
X#define GETC_CRC()		getc(infile)
X#define END_PUTC_CRC()
X#define END_GETC_CRC()
X#else
X#define SETUP_PUTC_CRC(fp)	crc_outfile = fp
X#define SETUP_GETC_CRC(fp)	crc_infile = fp
X#define PUTC_CRC(c)		putc_crc(c)
X#define GETC_CRC()		getc_crc()
X#define END_PUTC_CRC()
X#define END_GETC_CRC()
X#endif
X
X
X
X
X#ifdef SELFMAIN
Xvoid Error (message)
X	char *message;
X{
X	printf("\n%s\n", message);
X	exit(EXIT_FAILURE);
X}
X#endif
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*		LZSS ENCODING						*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
X#define N		4096	/* buffer size */
X#define F		60	/* pre-sence buffer size */
X#define THRESHOLD	2
X#define NIL		N	/* term of tree */
X
Xunsigned char    text_buf[N + F - 1];
Xunsigned int     match_position, match_length;
Xint              lson[N + 1], rson[N + 1 + N], dad[N + 1];
Xunsigned char    same[N + 1];
X
X
X/* Initialize Tree */
XInitTree ()
X{
X	register int *p, *e;
X
X	for (p = rson + N + 1, e = rson + N + N; p <= e; )
X		*p++ = NIL;
X	for (p = dad, e = dad + N; p < e; )
X		*p++ = NIL;
X}
X
X
X/* Insert to node */
XInsertNode (r)
X	register int r;
X{
X	register int		p;
X	int			cmp;
X	register unsigned char	*key;
X	register unsigned int	c;
X	register unsigned int	i, j;
X
X	cmp = 1;
X	key = &text_buf[r];
X	i = key[1] ^ key[2];
X	i ^= i >> 4;
X	p = N + 1 + key[0] + ((i & 0x0f) << 8);
X	rson[r] = lson[r] = NIL;
X	match_length = 0;
X	i = j = 1;
X	for ( ; ; ) {
X		if (cmp >= 0) {
X			if (rson[p] != NIL) {
X				p = rson[p];
X				j = same[p];
X			} else {
X				rson[p] = r;
X				dad[r] = p;
X				same[r] = i;
X				return;
X			}
X		} else {
X			if (lson[p] != NIL) {
X				p = lson[p];
X				j = same[p];
X			} else {
X				lson[p] = r;
X				dad[r] = p;
X				same[r] = i;
X				return;
X			}
X		}
X
X		if (i > j) {
X			i = j;
X			cmp = key[i] - text_buf[p + i];
X		} else
X		if (i == j) {
X			for (; i < F; i++)
X				if ((cmp = key[i] - text_buf[p + i]) != 0)
X					break;
X		}
X
X		if (i > THRESHOLD) {
X			if (i > match_length) {
X				match_position = ((r - p) & (N - 1)) - 1;
X				if ((match_length = i) >= F)
X					break;
X			} else
X			if (i == match_length) {
X				if ((c = ((r - p) & (N - 1)) - 1) < match_position) {
X					match_position = c;
X				}
X			}
X		}
X	}
X	same[r] = same[p];
X	dad[r] = dad[p];
X	lson[r] = lson[p];
X	rson[r] = rson[p];
X	dad[lson[p]] = r;
X	dad[rson[p]] = r;
X	if (rson[dad[p]] == p)
X		rson[dad[p]] = r;
X	else
X		lson[dad[p]] = r;
X	dad[p] = NIL;  /* remove p */
X}
X
X
Xlink (n, p, q)
X	int n, p, q;
X{
X	register unsigned char *s1, *s2, *s3;
X	if (p >= NIL) {
X		same[q] = 1;
X		return;
X	}
X	s1 = text_buf + p + n;
X	s2 = text_buf + q + n;
X	s3 = text_buf + p + F;
X	while (s1 < s3) {
X		if (*s1++ != *s2++) {
X			same[q] = s1 - 1 - text_buf - p;
X			return;
X		}
X	}
X	same[q] = F;
X}
X
X
Xlinknode (p, q, r)
X	int p, q, r;
X{
X	int cmp;
X
X	if ((cmp = same[q] - same[r]) == 0) {
X		link(same[q], p, r);
X	} else if (cmp < 0) {
X		same[r] = same[q];
X	}
X}
X
XDeleteNode (p)
X	register int p;
X{
X	register int  q;
X
X	if (dad[p] == NIL)
X		return;			/* has no linked */
X	if (rson[p] == NIL) {
X		if ((q = lson[p]) != NIL)
X			linknode(dad[p], p, q);
X	} else
X	if (lson[p] == NIL) {
X		q = rson[p];
X		linknode(dad[p], p, q);
X	} else {
X		q = lson[p];
X		if (rson[q] != NIL) {
X			do {
X				q = rson[q];
X			} while (rson[q] != NIL);
X			if (lson[q] != NIL)
X				linknode(dad[q], q, lson[q]);
X			link(1, q, lson[p]);
X			rson[dad[q]] = lson[q];
X			dad[lson[q]] = dad[q];
X			lson[q] = lson[p];
X			dad[lson[p]] = q;
X		}
X		link(1, dad[p], q);
X		link(1, q, rson[p]);
X		rson[q] = rson[p];
X		dad[rson[p]] = q;
X	}
X	dad[q] = dad[p];
X	if (rson[dad[p]] == p)
X		rson[dad[p]] = q;
X	else
X		lson[dad[p]] = q;
X	dad[p] = NIL;
X}
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*		HUFFMAN ENCODING					*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
X#define N_CHAR  	(256 - THRESHOLD + F) /* {code : 0 .. N_CHAR-1} */
X#define T 		(N_CHAR * 2 - 1)	/* size of table */
X#define R 		(T - 1)			/* root position */
X#define MAX_FREQ	0x8000	/* tree update timing from frequency */
X
Xtypedef unsigned char uchar;
X
X
X
X/* TABLE OF ENCODE/DECODE for upper 6bits position information */
X
X/* for encode */
Xuchar p_len[64] = {
X	0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
X	0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
X	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
X	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
X};
X
Xuchar p_code[64] = {
X	0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
X	0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
X	0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
X	0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
X	0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
X	0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
X	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
X	0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
X};
X
X/* for decode */
Xuchar d_code[256] = {
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
X	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
X	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
X	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
X	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
X	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
X	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
X	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
X	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
X	0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
X	0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
X	0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
X	0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
X	0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
X	0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
X	0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
X	0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
X	0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
X	0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
X	0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
X	0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
X	0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
X	0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
X	0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
X	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
X	0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
X};
X
Xuchar d_len[256] = {
X	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
X	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
X	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
X	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
X	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
X	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
X	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
X	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
X	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
X	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
X	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
X	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
X	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
X	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
X	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
X	0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
X	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
X	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
X};
X
Xunsigned freq[T + 1];    /* frequency table */
X
Xint prnt[T + N_CHAR];    /* points to parent node */
X/* notes :
X   prnt[T .. T + N_CHAR - 1] used by
X   indicates leaf position that corresponding to code */
X
Xint son[T];              /* points to son node (son[i],son[i+]) */
X
Xunsigned getbuf = 0;
Xuchar getlen = 0;
X
X
X/* get one bit */
X/* returning in Bit 0 */
Xint GetBit ()
X{
X	register unsigned int dx = getbuf;
X	register unsigned int c;
X
X	if (getlen <= 8)
X		{
X			c = getc (infile);
X			if ((int)c < 0) c = 0;
X			dx |= c << (8 - getlen);
X			getlen += 8;
X		}
X	getbuf = dx << 1;
X	getlen--;
X	return (dx & 0x8000) ? 1 : 0;
X}
X
X/* get one byte */
X/* returning in Bit7...0 */
Xint GetByte ()
X{
X	register unsigned int dx = getbuf;
X	register unsigned c;
X
X	if (getlen <= 8) {
X		c = getc (infile);
X		if ((int)c < 0) c = 0;
X		dx |= c << (8 - getlen);
X		getlen += 8;
X	}
X	getbuf = dx << 8;
X	getlen -= 8;
X	return (dx >> 8) & 0xff;
X}
X
X/* get N bit */
X/* returning in Bit(N-1)...Bit 0 */
Xint GetNBits (n)
X	register unsigned int n;
X{
X	register unsigned int dx = getbuf;
X	register unsigned int c;
X	static int mask[17] = {
X		0x0000,
X		0x0001, 0x0003, 0x0007, 0x000f,
X		0x001f, 0x003f, 0x007f, 0x00ff,
X		0x01ff, 0x03ff, 0x07ff, 0x0fff,
X		0x1fff, 0x3fff, 0x0fff, 0xffff };
X	static int shift[17] = {
X		16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
X
X	if (getlen <= 8)
X		{
X			c = getc (infile);
X			if ((int)c < 0) c = 0;
X			dx |= c << (8 - getlen);
X			getlen += 8;
X		}
X	getbuf = dx << n;
X	getlen -= n;
X	return (dx >> shift[n]) & mask[n];
X}
X
Xunsigned putbuf = 0;
Xuchar putlen = 0;
X
X/* output C bits */
XPutcode (l, c)
X	register int l;
X	register unsigned int c;
X{
X	register len = putlen;
X	register unsigned int b = putbuf;
X	b |= c >> len;
X	if ((len += l) >= 8) {
X		putc (b >> 8, outfile);
X		if ((len -= 8) >= 8) {
X			putc (b, outfile);
X			codesize += 2;
X			len -= 8;
X			b = c << (l - len);
X		} else {
X			b <<= 8;
X			codesize++;
X		}
X	}
X	putbuf = b;
X	putlen = len;
X}
X
X
X/* Initialize tree */
X
XStartHuff ()
X{
X	register int i, j;
X
X	for (i = 0; i < N_CHAR; i++) {
X		freq[i] = 1;
X		son[i] = i + T;
X		prnt[i + T] = i;
X	}
X	i = 0; j = N_CHAR;
X	while (j <= R) {
X		freq[j] = freq[i] + freq[i + 1];
X		son[j] = i;
X		prnt[i] = prnt[i + 1] = j;
X		i += 2; j++;
X	}
X	freq[T] = 0xffff;
X	prnt[R] = 0;
X	putlen = getlen = 0;
X	putbuf = getbuf = 0;
X}
X
X
X/* reconstruct tree */
Xreconst ()
X{
X	register int i, j, k;
X	register unsigned f;
X
X	/* correct leaf node into of first half,
X	   and set these freqency to (freq+1)/2       */
X	j = 0;
X	for (i = 0; i < T; i++) {
X		if (son[i] >= T) {
X			freq[j] = (freq[i] + 1) / 2;
X			son[j] = son[i];
X			j++;
X		}
X	}
X	/* build tree.  Link sons first */
X	for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
X		k = i + 1;
X		f = freq[j] = freq[i] + freq[k];
X		for (k = j - 1; f < freq[k]; k--);
X		k++;
X		{	register unsigned *p, *e;
X			for (p = &freq[j], e = &freq[k]; p > e; p--)
X				p[0] = p[-1];
X			freq[k] = f;
X		}
X		{	register int *p, *e;
X			for (p = &son[j], e = &son[k]; p > e; p--)
X				p[0] = p[-1];
X			son[k] = i;
X		}
X	}
X	/* link parents */
X	for (i = 0; i < T; i++) {
X		if ((k = son[i]) >= T) {
X			prnt[k] = i;
X		} else {
X			prnt[k] = prnt[k + 1] = i;
X		}
X	}
X}
X
X
X/* update given code's frequency, and update tree */
X
Xupdate (c)
X	unsigned int	c;
X{
X	register unsigned *p;
X	register int i, j, k, l;
X
X	if (freq[R] == MAX_FREQ) {
X		reconst();
X	}
X	c = prnt[c + T];
X	do {
X		k = ++freq[c];
X
X		/* swap nodes when become wrong frequency order. */
X		if (k > freq[l = c + 1]) {
X			for (p = freq+l+1; k > *p++; ) ;
X			l = p - freq - 2;
X			freq[c] = p[-2];
X			p[-2] = k;
X
X			i = son[c];
X			prnt[i] = l;
X			if (i < T) prnt[i + 1] = l;
X
X			j = son[l];
X			son[l] = i;
X
X			prnt[j] = c;
X			if (j < T) prnt[j + 1] = c;
X			son[c] = j;
X
X			c = l;
X		}
X	} while ((c = prnt[c]) != 0);	/* loop until reach to root */
X}
X
X/* unsigned code, len; */
X
XEncodeChar (c)
X	unsigned c;
X{
X	register int *p;
X	register unsigned long i;
X	register int j, k;
X
X	i = 0;
X	j = 0;
X	p = prnt;
X	k = p[c + T];
X
X	/* trace links from leaf node to root */
X	do {
X		i >>= 1;
X
X		/* if node index is odd, trace larger of sons */
X		if (k & 1) i += 0x80000000;
X
X		j++;
X	} while ((k = p[k]) != R) ;
X	if (j > 16) {
X		Putcode(16, (unsigned int)(i >> 16));
X		Putcode(j - 16, (unsigned int)i);
X	} else {
X		Putcode(j, (unsigned int)(i >> 16));
X	}
X/*	code = i; */
X/* 	len = j; */
X	update(c);
X}
X
XEncodePosition (c)
X	unsigned c;
X{
X	unsigned i;
X
X	/* output upper 6bit from table */
X	i = c >> 6;
X	Putcode((int)(p_len[i]), (unsigned int)(p_code[i]) << 8);
X
X	/* output lower 6 bit */
X	Putcode(6, (unsigned int)(c & 0x3f) << 10);
X}
X
XEncodeEnd ()
X{
X	if (putlen) {
X		putc(putbuf >> 8, outfile);
X		codesize++;
X	}
X}
X
Xint DecodeChar ()
X{
X	register unsigned c;
X
X	c = son[R];
X
X	/* trace from root to leaf,
X	   got bit is 0 to small(son[]), 1 to large (son[]+1) son node */
X	while (c < T) {
X		c += GetBit();
X		c = son[c];
X	}
X	c -= T;
X	update(c);
X	return c;
X}
X
Xint DecodePosition ()
X{
X	unsigned i, j, c;
X
X	/* decode upper 6bit from table */
X	i = GetByte();
X	c = (unsigned)d_code[i] << 6;
X	j = d_len[i];
X
X	/* get lower 6bit */
X	j -= 2;
X	return c | (((i << j) | GetNBits (j)) & 0x3f);
X}
X
X
XEncode ()
X{
X	register int  i, c, len, r, s, last_match_length;
X
X	if (textsize == 0)
X		return;
X
X	textsize = 0;
X	StartHuff();
X	InitTree();
X	s = 0;
X	r = N - F;
X	for (i = s; i < r; i++)
X		text_buf[i] = ' ';
X	for (len = 0; len < F && (c = GETC_CRC()) != EOF; len++)
X		text_buf[r + len] = c;
X	textsize = len;
X	for (i = 1; i <= F; i++)
X		InsertNode(r - i);
X	InsertNode(r);
X	do {
X		if (match_length > len)
X			match_length = len;
X		if (match_length <= THRESHOLD) {
X			match_length = 1;
X			EncodeChar(text_buf[r]);
X		} else {
X			EncodeChar(255 - THRESHOLD + match_length);
X			EncodePosition(match_position);
X		}
X		last_match_length = match_length;
X		for (i = 0; i < last_match_length &&
X				(c = GETC_CRC()) != EOF; i++) {
X			DeleteNode(s);
X			text_buf[s] = c;
X			if (s < F - 1)
X				text_buf[s + N] = c;
X			s = (s + 1) & (N - 1);
X			r = (r + 1) & (N - 1);
X			InsertNode(r);
X		}
X
X		textsize += i;
X		if ((textsize > indicator_count) && !quiet) {
X			putchar (BALL);
X			fflush (stdout);
X			indicator_count += indicator_threshold;
X		}
X		while (i++ < last_match_length) {
X			DeleteNode(s);
X			s = (s + 1) & (N - 1);
X			r = (r + 1) & (N - 1);
X			if (--len) InsertNode(r);
X		}
X	} while (len > 0);
X	EncodeEnd();
X	END_GETC_CRC ();
X}
X
XDecode ()
X{
X	register int	i, j, k, r, c;
X	register long	count;
X
X#ifdef SELFMAIN
X	if (textsize == 0)
X		return;
X#endif
X	StartHuff();
X	for (i = 0; i < N - F; i++)
X		text_buf[i] = ' ';
X	r = N - F;
X	for (count = 0; count < textsize; ) {
X		c = DecodeChar();
X		if (c < 256) {
X			PUTC_CRC (c);
X			text_buf[r++] = c;
X			r &= (N - 1);
X			count++;
X		} else {
X			i = (r - DecodePosition() - 1) & (N - 1);
X			j = c - 255 + THRESHOLD;
X			for (k = 0; k < j; k++) {
X				c = text_buf[(i + k) & (N - 1)];
X				PUTC_CRC (c);
X				text_buf[r++] = c;
X				r &= (N - 1);
X				count++;
X			}
X		}
X
X		if (!quiet && (count > indicator_count)) {
X			putchar (BALL);
X			fflush (stdout);
X			indicator_count += indicator_threshold;
X		}
X	}
X	END_PUTC_CRC ();
X}
X
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*		LARC							*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
X#define F_OLD	18	/* look ahead buffer size for LArc */
X
X/* intialize buffer for LArc type 5 */
XInitBuf ()
X{
X	register unsigned char *p = text_buf;
X	register int i, j;
X	for (i = 0; i < 256; i ++)
X		for (j = 0; j < 13; j ++)
X			*p ++ = i;
X	for (i = 0; i < 256; i ++)
X		*p ++ = i;
X	for (i = 0; i < 256; i ++)
X		*p ++ = 255 - i;
X	for (i = 0; i < 128; i ++)
X		*p ++ = 0;
X	for (i = 0; i < 128; i ++)
X		*p ++ = 0x20;
X}
X
X/* Decode LArc type 5 */
XDecodeOld ()
X{
X	register int si, di;
X	register long count;
X	int	dl, dh, al, cx;
X	if (textsize == 0)
X		return;
X
X	InitBuf ();
X	di = N - F_OLD;
X	dl = 0x80;
X
X	for (count = 0; count < textsize; ) {
X		dl = ((dl << 1) | (dl >> 7)) & 0xff;
X		if (dl & 0x01)
X			dh = getc (infile);
X		al = getc (infile);
X		if ((dh & dl) != 0) {
X			PUTC_CRC (al);
X			text_buf[di] = al;
X			di = (di + 1) & (N - 1);
X			count ++;
X		} else {
X			cx = getc (infile);
X			si = (al & 0x00ff) | ((cx << 4) & 0x0f00);
X			cx = (cx & 0x000f) + 3;
X			count += cx;
X			do {
X				text_buf[di] = al = text_buf[si];
X				PUTC_CRC (al);
X				si = (si + 1) & (N - 1);
X				di = (di + 1) & (N - 1);
X			} while (--cx != 0) ;
X		}
X
X		if (!quiet && (count > indicator_count)) {
X			putchar (BALL);
X			fflush (stdout);
X			indicator_count += indicator_threshold;
X		}
X	}
X	END_PUTC_CRC ();
X}
X
X
X
X/*----------------------------------------------------------------------*/
X/*									*/
X/*		Global Entries for Archiver Driver			*/
X/*									*/
X/*----------------------------------------------------------------------*/
X
X
Xstart_indicator (name, size, msg)
X	char *name;
X	long size;
X	char *msg;
X{
X	long	i;
X	int	m;
X
X	if (quiet)
X		return;
X
X#ifdef ANSI
X	m = MAX_INDICATOR_COUNT;
X#else
X	m = MAX_INDICATOR_COUNT - strlen (name);
X#endif
X	if (m < 0)
X		m = 3;		/* (^_^) */
X
X#ifdef ANSI
X        printf ("\r%s - %s:\n", name, msg);
X#else
X        printf ("\r%s - %s :  ", name, msg);
X#endif
X
X	indicator_threshold =
X		((size  + (m * INDICATOR_THRESHOLD - 1)) /
X		 (m * INDICATOR_THRESHOLD) *
X		 INDICATOR_THRESHOLD);
X	i = ((size + (indicator_threshold - 1)) / indicator_threshold);
X	while (i--)
X		putchar (DOT);
X	indicator_count = 0;
X#ifdef ANSI
X        printf ("\r%s%s - %s:\n", CURSORUP, name, msg);
X#else
X        printf ("\r%s - %s :  ", name, msg);
X#endif
X	fflush (stdout);
X}
X
Xfinish_indicator2 (name, msg, pcnt)
X	char *name;
X	char *msg;
X	int pcnt;
X{
X	if (quiet)
X		return;
X
X	if (pcnt > 100) pcnt = 100;	/* (^_^) */
X#ifdef ANSI
X        printf ("\r%s%s - %s(%d%%)\n%s", CURSORUP, name, msg, pcnt, ERASEEOL);
X#else
X        printf ("\r%s - %s(%d%%)\n", name, msg, pcnt);
X#endif
X	fflush (stdout);
X}
X
Xfinish_indicator (name, msg)
X	char *name;
X	char *msg;
X{
X	if (quiet)
X		return;
X
X#ifdef ANSI
X        printf ("\r%s%s - %s\n%s", CURSORUP, name, msg, ERASEEOL);
X#else
X        printf ("\r%s - %s\n", name, msg);
X#endif
X	fflush (stdout);
X}
X
X
X#ifndef SELFMAIN
Xint encode_lzhuf (infp, outfp, size, original_size_var, packed_size_var, name)
X	FILE *infp;
X	FILE *outfp;
X	long size;
X	long *original_size_var;
X	long *packed_size_var;
X	char *name;
X{
X	infile = infp;
X	outfile = outfp;
X	SETUP_GETC_CRC(infp);
X	textsize = size;
X	codesize = 0;
X	init_crc ();
X	start_indicator (name, size, "Freezing");
X	Encode ();
X	finish_indicator2 (name, "Frozen",
X			   (int)((codesize * 100L) / crc_size));
X	*packed_size_var = codesize;
X	*original_size_var = crc_size;
X	return crc_value;
X}
X
Xint decode_lzhuf (infp, outfp, original_size, name)
X	FILE *infp;
X	FILE *outfp;
X	long original_size;
X	char *name;
X{
X	infile = infp;
X	outfile = outfp;
X	SETUP_PUTC_CRC(outfp);
X	textsize = original_size;
X	init_crc ();
X        start_indicator (name, original_size,
X                         (output_to_test ? "Testing" : "Melting"));
X	Decode ();
X        finish_indicator (name, (output_to_test ? "Tested  " : "Melted  "));
X	return crc_value;
X}
X
X
Xint decode_larc (infp, outfp, original_size, name)
X	FILE *infp, *outfp;
X	long original_size;
X	char *name;
X{
X	infile = infp;
X	outfile = outfp;
X	SETUP_PUTC_CRC(outfp);
X	textsize = original_size;
X	init_crc ();
X        start_indicator (name, original_size,
X                         (output_to_test ? "Testing" : "Melting"));
X	DecodeOld ();
X        finish_indicator (name, (output_to_test ? "Tested  " : "Melted  "));
X	return crc_value;
X}
X#endif
X
X#ifdef SELFMAIN
Xint main (argc, argv)
X	int argc;
X	char *argv[];
X{
X	char  *s;
X	int i;
X
X	indicator_count = 0;
X	indicator_threshold = 1024;
X	textsize = codesize = 0;
X	if (argc != 4) {
X		printf ("\
Xusage: lzhuf e in_file out_file (packing)\n\
X       lzhuf d in_file out_file (unpacking)\n");
X		return EXIT_FAILURE;
X	}
X	if ((s = argv[1], ((*s != 'e') && (*s != 'd')) || s[1] != '\0') ||
X	    (s = argv[2], (infile  = fopen(s, "rb")) == NULL) ||
X	    (s = argv[3], (outfile = fopen(s, "wb")) == NULL)) {
X		printf("??? %s\n", s);
X		return EXIT_FAILURE;
X	}
X	if (argv[1][0] == 'e') {
X		/* Get original text size and output it */
X		fseek(infile, 0L, 2);
X		textsize = ftell(infile);
X		rewind (infile);
X		if (fwrite(&textsize, sizeof textsize, 1, outfile) < 1)
X			Error("cannot write");
X
X		start_indicator (argv[2], textsize, "Freezing");
X		Encode();
X		finith_indicator2 (argv[2], "Frozen",
X				   (int)((codesize * 100L) / textsize));
X
X		printf("input : %ld bytes\n", textsize);
X		printf("output: %ld bytes\n", codesize);
X	} else {
X		/* Read original text size */
X		if (fread(&textsize, sizeof textsize, 1, infile) < 1)
X			Error("cannot read");
X
X		start_indicator (argv[2], textsize, "Melting");
X		Decode();
X		finish_indicator (argv[2], "Melted  ");
X	}
X	fclose(infile);
X	fclose(outfile);
X	return EXIT_SUCCESS;
X}
X#endif
X
X
X/* These lines are used in GNU-Emacs */
X/* Local Variables: */
X/* comment-column:40 */
X/* tab-width:8 */
X/* c-indent-level:8 */
X/* c-continued-statement-offset:8 */
X/* c-argdecl-indent:8 */
X/* End: */
END_OF_lzhuf.c
if test 22465 -ne `wc -c <lzhuf.c`; then
    echo shar: \"lzhuf.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"makefile\"
else
echo shar: Extracting \"makefile\" \(1707 characters\)
sed "s/^X//" >makefile <<'END_OF_makefile'
X# Makefile for LHArc UNIX
X#	Copyright(C) MCMLXXXIX  Yooichi.Tagawa
X# V0.01  Alpha Version				1989.05.28  Y.Tagawa
X# V0.02  Alpha Version R2			1989.05.29  Y.Tagawa
X# V0.03  Release #3  Beta Version		1989.07.02  Y.Tagawa
X
X#-----------------------------------------------------------------------
X# DIRECTORY ACCESS DEPENDENDS...
X#  The default (no need swtich) is your machine has
X#  opendir(),readdir(),closedir() library and 'direct' structure used.
X#  If your machine has no opendir (), readdir (), closedir ()
X#	-DNONSYSTEM_DIR_LIBRARY
X#  and add lhdir.o into OBJS macro (see bellow)
X#  If your machine are 'dirent' (not 'direct') structure used,
X#	-DSYSV_SYSTEM_DIR
X#  Otherwise "Give up!"
X#	-DNODIRECTORY
X#
X#-----------------------------------------------------------------------
X# MEMORY ACCESS STUFF
X#  Your machine has no BSTRING library (bcmp,bcopy,bzero).
X#	-DNOBSTRING
X#
X#-----------------------------------------------------------------------
X# TIME STUFF
X#  Your include file '<sys/time.h>' has no 'struct tm',  define this.
X#	-DSYSTIME_HAS_NO_TM
X#
X
X# most of 4.[23]BSD
X#	- vax 4.[23]BSD, SONY NEWS 4.[23]BSD etc.
X#SWITCHIES	=
X#OBJS		= lharc.o lzhuf.o lhio.o
X
X# sample of System-V
X#	- NEC EWS4800
X#-DSYSTIME_HAS_NO_TM
XSWITCHIES	= -DNOBSTRING -DSYSV_SYSTEM_DIR
XOBJS		= lharc.o lzhuf.o lhio.o rename.o
X
XCC		= cc
XCFLAGS		= $(SWITCHIES)
XLDFLAGS		= -ldir -lx
X
X#	Xlharc is test binary.  Please rename to lharc at install.
X#	(see install target)
Xall:	xlharc
X
Xxlharc	: $(OBJS)
X	$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
X
X#	For Debugging LzHuff module.
Xlzhuf	: lzhuf.c
X	$(CC) $(CFLAGS) -DSELFMAIN -o $* $*.c
X
Xlzhuf.o	lhio.o	: lhio.h
X
Xclean:
X	rm -f core lharc.o lzhuf.o lhdir.o lhio.o lharc.tar lharc.tar.Z
END_OF_makefile
if test 1707 -ne `wc -c <makefile`; then
    echo shar: \"makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mktemp.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"mktemp.c\"
else
echo shar: Extracting \"mktemp.c\" \(412 characters\)
sed "s/^X//" >mktemp.c <<'END_OF_mktemp.c'
X/* MKTEMP.C using TMP environment variable */
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <io.h>
X
Xvoid Mktemp(char *file)
X{
X  char fname[32], *tmp;
X
X  tmp = getenv("TMP");
X
X  if ( tmp != NULL )
X  {
X    strcpy(fname, file);
X    strcpy(file, tmp);
X
X    if ( file[strlen(file) - 1] != '\\' )
X      strcat(file, "\\");
X
X    strcat(file, fname);
X  }
X
X  mktemp(file);
X}
X
X/* End of MKTEMP.C */
END_OF_mktemp.c
if test 412 -ne `wc -c <mktemp.c`; then
    echo shar: \"mktemp.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f pipes.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"pipes.c\"
else
echo shar: Extracting \"pipes.c\" \(1116 characters\)
sed "s/^X//" >pipes.c <<'END_OF_pipes.c'
X/* a simulation for the Unix popen() and pclose() calls on MS-DOS */
X/* only one pipe can be open at a time */
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X
Xstatic char pipename[128], command[128];
Xstatic int wrpipe;
X
Xextern void Mktemp(char *);
X
XFILE *popen(char *cmd, char *flags)
X{
X  wrpipe = (strchr(flags, 'w') != NULL);
X
X  if ( wrpipe )
X  {
X    strcpy(command, cmd);
X    strcpy(pipename, "~WXXXXXX");
X    Mktemp(pipename);
X    return fopen(pipename, flags);  /* ordinary file */
X  }
X  else
X  {
X    strcpy(pipename, "~RXXXXXX");
X    Mktemp(pipename);
X    strcpy(command, cmd);
X    strcat(command, ">");
X    strcat(command, pipename);
X    system(command);
X    return fopen(pipename, flags);  /* ordinary file */
X  }
X}
X
Xint pclose(FILE *pipe)
X{
X  int rc;
X
X  if ( fclose(pipe) == EOF )
X    return EOF;
X
X  if ( wrpipe )
X  {
X    if ( command[strlen(command) - 1] == '!' )
X      command[strlen(command) - 1] = 0;
X    else
X      strcat(command, "<");
X
X    strcat(command, pipename);
X    rc = system(command);
X    unlink(pipename);
X    return rc;
X  }
X  else
X  {
X    unlink(pipename);
X    return 0;
X  }
X}
END_OF_pipes.c
if test 1116 -ne `wc -c <pipes.c`; then
    echo shar: \"pipes.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f readme -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"readme\"
else
echo shar: Extracting \"readme\" \(1184 characters\)
sed "s/^X//" >readme <<'END_OF_readme'
X								-*- Text -*-
X
XLHarc UNIX V0.03 Release #3  Beta Version
X
X	This is FREEWARE.  But it's BETA-VERSION.
X
X	Please reply to me.
X
X	Sorry, lharc.doc file are written in JAPANESE (Shift-JIS KANJI)
X
X						Thank you.
X
X						Yooichi.Tagawa
X						Nikkei-MIX ID: y.tagawa
X------------------------------------------------------------------------
X
XHOW TO USE:
X	lharc {axevludmcp}[qnft] archive_file [files or directories...]
X
XCOMMAND:
X	KEY	MEANS				Like as (UNIX ar command)
X	--- ------------------------------	------------------------------
X	a    Append to archive.			  ar r AFILE files...
X	x,e  EXtract from archive.		  ar x AFILE [files...]
X	v,l  View/List archive contents.	  ar t AFILE [files...]
X	u    append newer files to archive.	  ar ru AFILE files...
X	d    Delete from archive.		  ar d AFILE files...
X	m    Move to archive.			  ar m AFILE files...
X	c    re-construct new archive file.	  rm AFILE; ar r AFILE files...
X	p    Print to STANDARD-OUTPUT		  ar p AFILE [files...]
X
X
XOPTIONS:
X	q	quiet
X	n	no execute (debugging option)
X	f	force (over write at extract)
X	t	text-mode (this is provisional option)
X
X------------------------------------------------------------------------------
END_OF_readme
if test 1184 -ne `wc -c <readme`; then
    echo shar: \"readme\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f rename.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"rename.c\"
else
echo shar: Extracting \"rename.c\" \(1793 characters\)
sed "s/^X//" >rename.c <<'END_OF_rename.c'
X/*
X * $Author: chip $ $Date: 89/06/29 13:02:31 $
X * $Header: rename.c,v 1.1 89/06/29 13:02:31 chip Exp $
X * $Revision: 1.1 $
X */
X
X/*
X * Rename system call -- Replacement for Berzerkeley 4.2 rename system
X * call that is missing in Xenix.
X *
X * By Marc Frajola and Chris Paris.
X * Directory hack by Chip Salzenberg.
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <signal.h>
X#include <errno.h>
X
Xrename(src,dest)
X    char *src;			/* Source file to rename */
X    char *dest;			/* Name for renamed file */
X{
X    int status;			/* Status returned from link system call */
X    struct stat stbuf;		/* Buffer for statting destination file */
X
X    /* Find out what the destination is: */
X    status = stat(dest,&stbuf);
X    if (status >= 0) {
X	/* See if the file is a regular file; if not, return error: */
X	if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
X	    return(-1);
X	}
X    }
X
X    /* Unlink destination since it is a file: */
X    unlink(dest);
X
X    /* Find out what the source is: */
X    status = stat(src,&stbuf);
X    if (status < 0)
X	return -1;
X    if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
X    {
X	/* Directory hack for SCO Xenix */
X
X	static char mvdir[] = "/usr/lib/mv_dir";
X	void (*oldsigcld)();
X	int pid;
X
X	oldsigcld = signal(SIGCLD, SIG_DFL);
X	while ((pid = fork()) == -1)
X	{
X	    if (errno != EAGAIN)
X		return -1;
X	    sleep(5);
X	}
X	if (pid == 0)
X	{
X	    execl(mvdir, mvdir, src, dest, (char *) 0);
X	    perror(mvdir);
X	    exit(1);
X	}
X	if (wait(&status) != pid)
X	{
X	    fprintf(stderr, "rename: wait failure\n");
X	    status = -1;
X	}
X	(void) signal(SIGCLD, oldsigcld);
X    }
X    else
X    {
X	/* Link source to destination file: */
X	status = link(src,dest);
X	if (status != 0) {
X	    return(-1);
X	}
X	status = unlink(src);
X    }
X    return((status == 0) ? 0 : (-1));
X}
END_OF_rename.c
if test 1793 -ne `wc -c <rename.c`; then
    echo shar: \"rename.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0

ron@mlfarm.uucp (Ronald Florence) (03/29/90)

In article <868@stsim.ocs.com> glenn@stsim.ocs.com (glenn ford) writes:
 > Here it is, I have tried posting to alt.sources and comp.sources.misc
 > and have failed, so since this is for SCO XENIX people only, grab it!
 > It should work under 386 Xenix as is, just type 'make'

As far as I can see, the only changes from the original source are a
couple of #ifdefs which effectively eliminate the calls to rename().
Since the source to LHARC and the source to rename (which seems not to
be used in your code) have both been posted and are available in
archive sites, why waste the bandwith for this re-posting?  A short
patch file would have sufficed.

Some of us have to pay the phone bill for news.
--

Ronald Florence			{yale,uunet}!hsi!mlfarm!ron