#ifndef LINT
/* @(#) portable.c 2.24 88/08/24 01:22:06 */
static char sccsid[]="@(#) portable.c 2.24 88/08/24 01:22:06";
#endif /* LINT */

#include "options.h"
/*
Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
(C) Copyright 1988 Rahul Dhesi -- All rights reserved
*/
/**********************
portable.c contains functions needed to make Zoo portable to various
implementations of C.

Note:  Provided a 2's complement machine is used, all functions in
this file are themselves machine-independent and need not be changed
when implementing Zoo on a different machine.  Some code will choke
on 1's complement machines--I think.

For machine-dependent declarations see files "machine.h" and "options.h".

For machine-dependent functions see file "machine.c"
*/

#include "zoo.h"
#include "zooio.h"

#include "various.h"
#include "zoofns.h"

#include "machine.h"
#include "debug.h"
#include "assert.h"

#ifdef NEEDCTYP
#include <ctype.h>				  /* for tolower() */
#endif

#include "portable.h"

#ifdef TRACE_IO
extern int verbose;
#endif

/* Functions defined for use within this file only.  */
long to_long PARMS((BYTE[]));
int to_int PARMS((BYTE[]));
void b_to_zooh PARMS((struct zoo_header *, BYTE[]));
void b_to_dir PARMS((struct direntry *, BYTE[]));
int dir_to_b PARMS((BYTE[], struct direntry *));
void zooh_to_b PARMS((BYTE[], struct zoo_header *));
void splitlong PARMS((BYTE[], long));
void splitint PARMS((BYTE[], int));

#ifdef TRACE_IO
void show_h PARMS ((struct zoo_header *));
void show_dir PARMS ((struct direntry *));
#endif /* TRACE_IO */

extern unsigned int crccode;

/************************************************************************/
/* I/O functions */
/************************************************************************/

/* some functions get defined only if they aren't already macros */

#ifndef zooread
int zooread (file, buffer, count)
ZOOFILE file; char *buffer; int count;
{ return (fread (buffer, 1, count, file)); }
#endif /* zooread */

#ifndef FIZ
#ifndef zoowrite
int zoowrite (file, buffer, count)
ZOOFILE file; char *buffer; int count;
{
	if (file == NULLFILE)
		return (count);
	else
		return (fwrite (buffer, 1, count, file));
}
#endif /* zoowrite */

ZOOFILE zoocreate (fname)
char *fname;
{ return ((ZOOFILE) fopen (fname, Z_NEW)); }

#endif /* FIZ */

#ifndef zooseek
long zooseek (file, offset, whence)
ZOOFILE file; long offset; int whence;
{ return (fseek (file, offset, whence)); }
#endif /* zooseek */

ZOOFILE zooopen (fname, option)
char *fname; char *option;
{ return ((ZOOFILE) fopen (fname, option)); }

#ifndef zootell
long zootell (file)
ZOOFILE file;
{ return ftell (file); }
#endif /* zootell */

int zooclose (file)
ZOOFILE file;
{ return fclose (file); }

/**********************
low_ch() is a macro that returns a lowercased char; it may be
used with any char, whether or not it is uppercase.	It will
be used below by one or two functions.
*/

#define low_ch(c)    (isupper(c) ? tolower(c) : c)
#ifndef toascii
#define toascii(c)   (c)
#endif

/************************************************************************/
/*** Following are functions that make up for various implementations ***/
/*** of C not having certain library routines.								 ***/
/************************************************************************/

#ifndef FIZ
/**********************
str_lwr() converts a string to lowercase and returns a pointer to the string
*/
char *str_lwr (str)
char *str;
{
	register char *s;
	s = str;
	while (*s != '\0') {
		*s = toascii(*s);
		*s = low_ch(*s);
		s++;
	}
	return (str);
}

/**********************
str_icmp() compares strings just like strcmp() but it does it without regard to
case.
*/
int str_icmp (s1, s2)
register char *s1, *s2;
{
	for ( ; low_ch(*s1) == low_ch(*s2);  s1++, s2++)
		if (*s1 == '\0')
			return(0);
	return(low_ch(*s1) - low_ch(*s2));
}

#ifdef NEED_MEMSET
/**********************
memset() it sets the first "count" bytes of "dest" to the character
"c" and returns a pointer to "dest".
*/
char *memset (dest, c, count)
register char *dest;
int c;
unsigned count;
{
	register unsigned i;
	for (i = 0; i < count; i++) {
		*((char *) (dest + i)) = c;
	}
	return dest;
}
#endif /* NEED_MEMSET */

#ifdef NEED_MEMCPY
/**********************
memcpy() copies "count" bytes from "src" to "dest" and returns
a pointer to "dest".  Not necessarily safe for overlapping moves. */

char *memcpy(dest, src, count)
register char *dest;
register char *src;
unsigned count;
{
	VOIDPTR savedest = dest;
	while (count > 0) {
		*((char *) dest++) = *((char *) src++);
		count--;
	}
}
#endif /* NEED_MEMCPY */

#ifndef FPUTCHAR
/**********************
fputchar() writes a character to stdout.  It is identical to putchar
but is a function, not a macro.
*/
int fputchar (c)
int c;
{
	return (fputc(c, stdout));
}
#endif /* FPUTCHAR */
#endif /* FIZ */

/***********************************************************************/
/*** Following are declarations and functions that are written in a	***/
/*** machine-independent way but they implement machine-dependent 	***/
/*** activities																		***/
/***********************************************************************/

#ifndef DIRECT_CONVERT
/**********************
to_long() converts four consecutive bytes, in order of increasing
significance, to a long integer.  It is used to make Zoo independent of the
byte order of the system.
*/
long to_long(data)
BYTE data[];
{
	return (long) ((unsigned long) data[0] | ((unsigned long) data[1] << 8) |
			((unsigned long) data[2] << 16) | ((unsigned long) data[3] << 24));
}

#ifndef FIZ
/********************
splitlong() converts a long integer to four consecutive BYTEs in order
of increasing significance.
*/
void splitlong(bytes, bigword)
BYTE bytes[];
long bigword;
{
	int i;
	for (i = 0; i < 4; i++) {
		bytes[i] = bigword & 0xff;
		bigword = (unsigned long) bigword >> 8;
	}
}
#endif /* FIZ */

/*******************
splitint() converts an integer to two consecutive BYTEs in order
of increasing significance.
*/
void splitint(bytes, word)
BYTE bytes[];
int word;
{
	bytes[0] = word & 0xff;
	word = (unsigned int) word >> 8;
	bytes[1] = word & 0xff;
}

/**********************
to_int() converts two consecutive bytes, in order of increasing
significance, to an integer, in a machine-independent manner
*/
int to_int(data)
BYTE data[];
{
	return (int) ((unsigned int) data[0] | ((unsigned int) data[1] << 8));
}

#else /* else of ifndef DIRECT_CONVERT */

long to_long(data)
BYTE data[];
{
	return ( * (long *) data );
}

#ifndef FIZ
/********************
splitlong() converts a long integer to four consecutive BYTEs in order
of increasing significance.
*/
void splitlong(bytes, bigword)
BYTE bytes[];
long bigword;
{
	* (long *) bytes = bigword;
}
#endif /* FIZ */

/*******************
splitint() converts an integer to two consecutive BYTEs in order
of increasing significance.
*/
void splitint(bytes, word)
BYTE bytes[];
int word;
{
	* (int *) bytes = word;
}

/**********************
to_int() converts two consecutive bytes, in order of increasing
significance, to an integer.
*/
int to_int(data)
BYTE data[];
{
	return (*(int *) data);
}

#endif /* ifndef DIRECT_CONVERT .. else ... */

#ifndef FIZ
/**********************
Function frd_zooh() reads the header of a Zoo archive in a machine-
independent manner, from a ZOOFILE.
*/
int frd_zooh(zoo_header, zoo_file)
struct zoo_header *zoo_header;
ZOOFILE zoo_file;
{
	int status;
	BYTE bytes[SIZ_ZOOH];			/* canonical header representation */
#ifdef TRACE_IO
	if (verbose) {
		printf("At file position [%8lx] ", ftell(zoo_file));
	}
#endif
	status = zooread (zoo_file, (char *) bytes, SIZ_ZOOH);
	b_to_zooh (zoo_header, bytes);   /* convert array to structure */
#ifdef TRACE_IO
	if (verbose) {
		printf("frd_zooh: reading\n");
		show_h(zoo_header);
	}
#endif
	if (status < MINZOOHSIZ)
		return (-1);
	else
		return (0);
}
#endif /* FIZ */

/**********************
Function frd_dir() reads a directory entry in a machine-independent manner,
from a ZOOFILE.
*/
int frd_dir(direntry, zoo_file)
struct direntry *direntry;
ZOOFILE zoo_file;
{
	int status;
	BYTE bytes[MAXDIRSIZE]; 	/* big enough to hold variable part too */

	/* To simplify things, we read the maximum possible size of the
	directory entry including the variable size and discard what is not
	needed */
#ifdef TRACE_IO
	if (verbose) {
		printf("At file position [%8lx] ", ftell(zoo_file));
	}
#endif
	status = zooread (zoo_file, (char *) bytes, MAXDIRSIZE);
	if (status < SIZ_DIR)
		return (-1);
	b_to_dir (direntry, bytes);
#ifdef TRACE_IO
	if (verbose) {
		printf("frd_dir: reading\n");
		show_dir(direntry);
	}
#endif
	return (0);
}

#ifndef FIZ
/***********************
Function fwr_dir() writes a directory entry in a machine-independent manner
to a ZOOFILE.	Return value is -1 on error, else 0.
*/
int fwr_dir(direntry, zoo_file)
struct direntry *direntry;
ZOOFILE zoo_file;
{
	int size;
	BYTE bytes[MAXDIRSIZE];
	assert (direntry->type <= 2);
	size = dir_to_b (bytes, direntry);
#ifdef TRACE_IO
	if (verbose) {
		printf("At file position [%8lx] ", ftell(zoo_file));
		printf("fwr_dir: writing\n");
		show_dir(direntry);
	}
#endif

	if (zoowrite (zoo_file, (char *) bytes, size) != size)
		return (-1);
	else
		return (0);
}

/***********************
Function fwr_zooh() writes an archive header in a machine-independent manner
to a ZOOFILE.	Return value is -1 if error else 0.
*/
int fwr_zooh(zoo_header, zoo_file)
struct zoo_header *zoo_header;
ZOOFILE zoo_file;
{
	BYTE bytes[SIZ_ZOOH];	/* was SIZ_DIR -- probably a typo */
	int hsize;					/* how much to write -- depends on header type */
	hsize = MINZOOHSIZ;				/* in case it's an old type 0 header */
	if (zoo_header->type > 0)     /* but if it's a newer header... */
		hsize = SIZ_ZOOH; 			/* ...size of new type 1 header */
	zooh_to_b (bytes, zoo_header);
	if (zoowrite (zoo_file, (char *) bytes, hsize) != hsize)
		return (-1);
	else
		return (0);
}

/***********************
b_to_zooh() converts an array of BYTE to a zoo_header structure.
*/
void b_to_zooh (zoo_header, bytes)
struct zoo_header *zoo_header;
BYTE bytes[];
{
	int i;
	for (i = 0; i < SIZ_TEXT; i++)                     /* copy text */
		zoo_header->text[i] = bytes[TEXT_I + i];
	zoo_header->zoo_tag = to_long(&bytes[ZTAG_I]);     /* copy zoo_tag */
	zoo_header->zoo_start = to_long(&bytes[ZST_I]);    /* copy zoo_start */
	zoo_header->zoo_minus = to_long(&bytes[ZSTM_I]);
	zoo_header->major_ver = bytes[MAJV_I]; 			/* copy versions */
	zoo_header->minor_ver = bytes[MINV_I];
	/* default is no archive comment and a header type of 0 */
	zoo_header->type = 0;
	zoo_header->acmt_pos = 0L;
	zoo_header->acmt_len = 0;
	zoo_header->vdata 	= 0;
	if (zoo_header->zoo_start != FIXED_OFFSET) {       /* if newer header */
		zoo_header->type = bytes[HTYPE_I];
		zoo_header->acmt_pos = to_long(&bytes[ACMTPOS_I]);
		zoo_header->acmt_len = to_int(&bytes[ACMTLEN_I]);
		zoo_header->vdata 	= bytes[HVDATA_I];
	}
}

/***********************
zooh_to_b() converts a zoo_header structure to an array of BYTE.
*/
void zooh_to_b (bytes, zoo_header)
struct zoo_header *zoo_header;
BYTE bytes[];
{
	int i;
	for (i = 0; i < SIZ_TEXT; i++)                     /* copy text */
		bytes[TEXT_I + i] = zoo_header->text[i];
	splitlong (&bytes[ZTAG_I], zoo_header->zoo_tag);
	splitlong (&bytes[ZST_I], zoo_header->zoo_start);
	splitlong (&bytes[ZSTM_I], zoo_header->zoo_minus);
	bytes[MAJV_I] =	zoo_header->major_ver;				/* copy versions */
	bytes[MINV_I] =	zoo_header->minor_ver;
	bytes[HTYPE_I] =	zoo_header->type; 					/* header type */
	if (zoo_header->type > 0) {
		splitlong (&bytes[ACMTPOS_I], zoo_header->acmt_pos);  /* comment posn */
		splitint (&bytes[ACMTLEN_I], zoo_header->acmt_len);   /* comment len */
		bytes[HVDATA_I] = zoo_header->vdata;					/* version data */
	}
} /* zooh_to_b() */

/************************
dir_to_b() converts a directory entry structure to an array of BYTE.
*/
int dir_to_b (bytes, direntry)
struct direntry *direntry;
BYTE bytes[];
{
	int i;
	int cursize;
	int fixsize;
	int totalsize;
	splitlong(&bytes[DTAG_I], direntry->zoo_tag);
	bytes[DTYP_I] = direntry->type ;
	bytes[PKM_I] = direntry->packing_method ;
	splitlong(&bytes[NXT_I], direntry->next);
	splitlong(&bytes[OFS_I], direntry->offset);
	splitint(&bytes[DAT_I], direntry->date);
	splitint(&bytes[TIM_I], direntry->time);
	splitint(&bytes[CRC_I], direntry->file_crc);
	splitlong(&bytes[ORGS_I], direntry->org_size);
	splitlong(&bytes[SIZNOW_I], direntry->size_now);
	bytes[DMAJ_I] = direntry->major_ver;
	bytes[DMIN_I] = direntry->minor_ver;
	bytes[DEL_I] = direntry->deleted;
	bytes[STRUC_I] = direntry->struc;
	splitlong(&bytes[CMT_I], direntry->comment);
	splitint(&bytes[CMTSIZ_I], direntry->cmt_size);
	for (i = 0; i < FNM_SIZ; i++)
		bytes[FNAME_I + i] = direntry->fname[i];
	bytes[TZ_I] = NO_TZ; 		/* assume unknown */
	bytes[NAMLEN_I] = 0;
	bytes[DIRLEN_I] = 0;

	cursize = SIZ_DIR;			/* to count size of directory */
	fixsize = SIZ_DIR;			/* size of fixed part */
	assert (direntry->type <= 2);
	if (direntry->type == 2) { /* handle stuff relevant to type 2 */
		cursize = SIZ_DIRL;
		fixsize = SIZ_DIRL;
		bytes[TZ_I] = direntry->tz;
		assert(direntry->namlen < 256 && direntry->namlen >= 0);
		cursize += 2;			/* space for namlen and dirlen */
		if (direntry->namlen != 0) {
			bytes[NAMLEN_I] = direntry->namlen;
			for (i = 0; i < direntry->namlen; i++)
				bytes[LFNAME_I+i] = direntry->lfname[i];
			cursize += direntry->namlen;
		}
		assert(direntry->dirlen < 256 && direntry->dirlen >= 0);
		if (direntry->dirlen != 0) {
			bytes[DIRLEN_I] = direntry->dirlen;
			for (i = 0; i < direntry->dirlen; i++)
				bytes[cursize+i] = direntry->dirname[i];
			cursize += direntry->dirlen;
		}
		/* Can't store system id if no namlen & dirlen...BUG!...now fixed.
			Fortunately, system_id was always 0 so far so it probably
			got interpreted as namlen=0 and dirlen=0 (2 bytes) */
		splitint(&bytes[cursize], direntry->system_id);
		cursize += 2;
		bytes[cursize] = direntry->fattr & 0xff;							/* byte 0 */
		splitint(&bytes[cursize+1], (int) (direntry->fattr >> 8));  /* 1 & 2 */
		cursize += 3;
		bytes[cursize] = (direntry->vflag & 0xff);         /* version flag */
		splitint(&bytes[cursize+1], direntry->version_no); /* version number */
		cursize += 3;
	}

	splitint(&bytes[VARDIRLEN_I], direntry->var_dir_len);
	assert(cursize ==
				((bytes[DIRLEN_I] > 0 || bytes[NAMLEN_I] > 0) ? 2 : 0) +
				fixsize + bytes[DIRLEN_I] + bytes[NAMLEN_I]
			);

	/* total size of dir entry is size of fixed part + size of var. part */
	totalsize = fixsize + direntry->var_dir_len;

	/* Do CRC assuming CRC field is zero, and stuff CRC into field. */
	splitint(&bytes[DCRC_I], 0);           /* fill with zeroes */
	crccode = 0;
	/* avoid mixing pointers to signed and unsigned char */
	addbfcrc((char *) bytes, totalsize);      /* update CRC */
	splitint(&bytes[DCRC_I], crccode);

	/* return total length of directory entry */
	return (totalsize);

} /* dir_to_b() */
#endif /* FIZ */

/* b_to_dir() converts bytes to directory entry structure.  The CRC of the
directory bytes, if any, is checked and a zero or nonzero value is returned
in direntry->dir_crc according as the check is good or bad */

void b_to_dir(direntry, bytes)
struct direntry *direntry;
BYTE bytes[];
{
	int i;
	int sysid_offs;			/* temp variable */
	unsigned int savecrc;
	direntry->zoo_tag = to_long(&bytes[DTAG_I]);
	direntry->type = bytes[DTYP_I];
	direntry->packing_method = bytes[PKM_I];
	direntry->next = to_long(&bytes[NXT_I]);
	direntry->offset = to_long(&bytes[OFS_I]);
	direntry->date = to_int(&bytes[DAT_I]);
	direntry->time = to_int(&bytes[TIM_I]);
	direntry->file_crc = to_int(&bytes[CRC_I]);
	direntry->org_size = to_long(&bytes[ORGS_I]);
	direntry->size_now = to_long(&bytes[SIZNOW_I]);
	direntry->major_ver = bytes[DMAJ_I];
	direntry->minor_ver = bytes[DMIN_I];
	direntry->deleted = bytes[DEL_I];
	direntry->struc = bytes[STRUC_I];
	direntry->comment = to_long(&bytes[CMT_I]);
	direntry->cmt_size = to_int(&bytes[CMTSIZ_I]);
	/* for now, versions not implemented */
	direntry->vflag = 0;
	direntry->version_no = 0;
	for (i = 0; i < FNM_SIZ; i++)
		direntry->fname[i] = bytes[FNAME_I + i];

	/* start by assuming variable part is zero bytes */
	direntry->var_dir_len = direntry->dir_crc 	= 0;
	direntry->namlen		 = direntry->dirlen		= 0;
	direntry->lfname[0]	 = direntry->dirname[0] = '\0';
	direntry->tz = NO_TZ;					/* assume unknown */
	direntry->system_id = SYSID_NIX; 	/* default system_id if not present */
	direntry->fattr = NO_FATTR;			/* assume none */

	assert (direntry->type <= 2);
	if (direntry->type == 2) {
		direntry->var_dir_len = to_int(&bytes[VARDIRLEN_I]);
		assert(direntry->var_dir_len <= MAXDIRSIZE);
		if (direntry->var_dir_len > MAXDIRSIZE)
			direntry->var_dir_len = MAXDIRSIZE;
		direntry->tz = bytes[TZ_I];
		if (direntry->var_dir_len > 0)
			direntry->namlen = bytes[NAMLEN_I];
		if (direntry->var_dir_len > 1)
			direntry->dirlen = bytes[DIRLEN_I];
		for (i = 0; i < direntry->namlen; i++)
			direntry->lfname[i] = bytes[LFNAME_I + i];
		for (i = 0; i < direntry->dirlen; i++)
			direntry->dirname[i] = bytes[DIRNAME_I + direntry->namlen + i];
		sysid_offs = DIRNAME_I + direntry->namlen + i;	/* offset of system id */
		if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 2) {
			direntry->system_id = to_int(&bytes[sysid_offs]);
		}
		if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 4) {
			direntry->fattr = ((unsigned long) bytes[sysid_offs + 2]) |
									((unsigned long) bytes[sysid_offs + 3] << 8) |
									((unsigned long) bytes[sysid_offs + 4] << 16);
		}
		if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 7) {
			direntry->vflag = bytes[sysid_offs + 5];
			direntry->version_no = to_int(&bytes[sysid_offs + 6]);
		}
		/* do CRC calculation */
		savecrc = (unsigned int) to_int(&bytes[DCRC_I]);
		crccode = 0;
		splitint(&bytes[DCRC_I], 0);
		addbfcrc((char *) bytes, SIZ_DIRL + direntry->var_dir_len);
		direntry->dir_crc = crccode - savecrc;
	}
}

#ifdef FILTER
#define TWOBYTES	2	/* better than literal 2;	figure out why */

/* rdint() reads two bytes from standard input in archive order */
int rdint (val)
unsigned int *val;
{
	BYTE bytes[TWOBYTES];
	if (zooread (STDIN, bytes, TWOBYTES) == TWOBYTES) {
		*val = to_int(bytes);
		return (0);
	} else
		return (1);
}

/* wrint() writes an unsigned int to standard output in archive order */
int wrint (val)
unsigned int val;
{
	BYTE bytes[TWOBYTES];
	splitint (bytes, val);
	if (zoowrite (STDOUT, bytes, TWOBYTES) == TWOBYTES)
		return (0);
	else
		return (1);
}
#endif /* FILTER */

#ifdef TRACE_IO
/* dump contents of archive header */
void show_h (zoo_header)
struct zoo_header *zoo_header;
{
	int i;
	printf ("Header text:\n");
	for (i = 0; i < SIZ_TEXT;  i++) {      /* ASSUMES ASCII TEXT */
		int c;
		c = zoo_header->text[i];
		if (c >= ' ' && c < 0x7f)
			putchar (c);
		else {
			putchar ('^');
			putchar (i & 0x40);
		}
	}
	putchar('\n');
	printf ("zoo_tag = [%8lx] zoo_start = [%8lx] zoo_minus = [%8lx]\n",
				zoo_header->zoo_tag, zoo_header->zoo_start,
				zoo_header->zoo_minus);
	printf ("major_ver.minor_ver = [%d.%d]\n",
				zoo_header->major_ver, zoo_header->minor_ver);
	if (zoo_header->zoo_start != FIXED_OFFSET) {
		printf ("type = [%d] ", zoo_header->type);
		printf ("acmt_pos = [%8lx] acmt_len = [%4x] vdata = [%2x]",
					zoo_header->acmt_pos, zoo_header->acmt_len, zoo_header->vdata);
		printf ("\n");
	}
	printf ("---------\n");
}

/* dump contents of directory entry */
void show_dir (direntry)
struct direntry *direntry;
{
	printf ("Directory entry for file [%s][%s]:\n",
				direntry->fname, direntry->lfname);
	printf ("tag = [%8lx] type = [%d] PM = [%d] Next = [%8lx] Offset = [%8lx]\n",
				direntry->zoo_tag, (int) direntry->type,
				(int) direntry->packing_method, direntry->next,
				direntry->offset);
	printf ("Orig size = [%ld] Size now = [%ld] dmaj_v.dmin_v = [%d.%d]\n",
			direntry->org_size, direntry->size_now,
			(int) direntry->major_ver, (int) direntry->minor_ver);
	printf ("Struc = [%d] DEL = [%d] comment_offset = [%8lx] cmt_size = [%d]\n",
			(int) direntry->struc, (int) direntry->deleted, direntry->comment,
			direntry->cmt_size);
	printf ("var_dir_len = [%d] TZ = [%d] dir_crc = [%4x]\n",
				direntry->var_dir_len, (int) direntry->tz, direntry->dir_crc);
	printf ("system_id = [%d]  dirlen = [%d]  namlen = [%d] fattr=[%24lx]\n",
		direntry->system_id, direntry->dirlen, direntry->namlen, direntry->fattr);
	printf ("vflag = [%4x] version_no = [%4x]\n",
				direntry->vflag, direntry->version_no);
	if (direntry->dirlen > 0)
		printf ("dirname = [%s]\n", direntry->dirname);
	printf ("---------\n");
}
#endif	/* TRACE_IO */
