[net.sources] FASTDIR ... faster DIR command for the Amiga Personal Computer

robp@amiga.UUCP (Robert A. Peck) (05/14/86)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#       fastdir.doc
#       fastdir.c
#       tree.c
#       treeprint.c
#       filecurrent.c
# This archive created: Mon May 13, 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'fastdir.doc'" '(2008 characters (and then some))'
if test -f 'fastdir.doc'
then
        echo shar: will not over-write existing file "'fastdir.doc'"
else
cat << \SHAR_EOF > 'fastdir.doc'

This release made to V/internal/aug by Rob Peck 5/13/86.

/* fastdir.c */

/* *********************************************************************** */
/* Fastdir was designed to be a faster implementation of the "DIR" command
 * for directories that have a large number of items in them, such as c:
 *
 * It is implemented as follows:
 * 
 * 	command:  FASTDIR 
 *	or	  FASTDIR <pathname>
 *
 * If there is a file by the name ".dir" in the selected or current path
 * name, fastdir checks the creation date of this .dir file (stored as the
 * first line in the file itself) against the modification date of its 
 * parent directory.  If they match exactly, it means that ".dir" contains 
 * the (near) equivalent of somebody doing a command "DIR > .dir" within this
 * directory.  If the creation/modification dates don't match, fastdir
 * attempts to create such a file.  After either finding or creating
 * this file, it copies ".dir" to the standard output.
 * 
 * Fastdir handles most known error conditions, such as: 
 *
 * write-protected disk 
 *     (outputs the generated listing equivalent to DIR without writing
 * 	or rewriting the .dir file).
 * trying to get a directory of a nonexistent file
 * 	(responds "can't find <pathname>")
 * trying to generate a directory listing of a file
 * 	(responds "<pathname> is not a directory")
 * trying to generate a listing of an empty directory
 * 	(responds "Directory '<pathname>' is empty.)
 *
 * Could use some error checking around the Write commands to handle
 * too-full disks, or a write error while generating ".dir".  Anybody
 * out there want to add these?  
 *
 * Fastdir does not implement DIR's "OPT" option. (OPT A, OPT I)
 * 
 * Fastdir modifies the DIR output slightly in that directories are NOT
 * listed separately, but are merged alphabetically into the normal
 * sorted alpha listing, still marked " (dir)" as they should be marked. 
 *
 * Author:  Rob Peck 5/13/86
 *
 * Lattice/Amiga C (3.03) linking information:
 *
 * 	compile with stack checking code disabled in pass 2 (lc2 -v file.q)
 * 
 * FROM lib:Astartup.obj fastdir.o filecurrent.o tree.o treeprint.o
 * TO fastdir
 * LIBRARY lib:amiga.lib, lib:lc.lib 
 *
 */


SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'fastdir.c'" '(11003 characters)'
if test -f 'fastdir.c'
then
        echo shar: will not over-write existing file "'fastdir.c'"
else
cat << \SHAR_EOF > 'fastdir.c'

/* fastdir.c */

/*
 * Author:  Rob Peck 5/13/86
 */

#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "exec/memory.h"

#define ABS(x) (x > 0 ? x : -x)
#define MAX(x,y) (x > y ? x : y)

extern struct FileHandle *stdout;

extern struct FileLock *Lock(),*DupLock();
extern struct FileLock *CurrentDir(), *ParentDir();
extern struct FileHandle *stdout, *Open();
char *blanks = "                                   ";	/* 35 blank spaces */
char linebuffer[80];			/* workspace for output formatting */
int leftright=0;			/* start at left column  */

struct tnode	/* for quick alphabetizing */
{
	struct tnode *left;
	struct tnode *right;
	char name[36];	/* space to store the name (30 + ' (dir)') max */
	char dirflag;	/* nonzero if it is a directory */
};

extern struct tnode *tree();
struct tnode *root;	   /* Pointer to the first one so we can deallocate */
struct FileInfoBlock *m;   /* for getting write-protect information */
struct FileLock *newlock;  /* Lock on current (or requested) dir    */
struct FileLock *dirlock;  /* Lock on the .dir file 	 	     */
int    maxlen=0;	   /* Maximum length of any string, provided 
			    * for later change in formatting (more
			    * entries per line
		            */

#define PROTECTED 1
#define WRITEABLE 0    

main(argc, argv)
	int argc;
	char *argv[];
{
	LONG myerror;		    /* place for error return filecurrent */
	LONG success;	    	    /* work variables			  */
	char *whichdir;		    /* which directory to get a lock on?  */
	struct FileLock *startlock; /* lock on the current directory      */
	struct FileLock *ignorlock; /* going back to original dir.        */
	struct InfoData *id;	    /* see if disk is write-protected     */
	struct FileLock *originallock; /* for "going home" again */

	/* Save a lock to original directory so that before we exit, we
	 * can move the CLI back to where it started
	 */
	originallock = Lock("",ACCESS_READ);	

	id = NULL;

	if(argc == 1) 
	{
	    /* No directory specified, use current one! */
	    /* Null string means use current dir */
	    whichdir = "";	
	}
	else
	{
	    whichdir = argv[1];
	} 
	/* Get a lock on the user-specified directory */

   	newlock = Lock(whichdir,ACCESS_READ);

	if(newlock == 0)
	{
	  if(argc == 1)
	    printf("Can't get a lock on current dir!\n");
	  else
	    printf("Can't find %ls\n",argv[1]);
	  exit(100);
	}
	else
	{
	    /* Move into this user selected directory */
	
	    startlock = CurrentDir(newlock);
	}
	/* Now see if there is a current copy of the ".dir" file here */

	if(filecurrent(".dir",&myerror))
	{
	    /* If its there and current, then output it */

	    output_dirfile(newlock);
	}
	else
	{ 
	    /* If its not current, attempt to create or overwrite it */

	    /* InfoData MUST BE LONGWORD ALIGNED, so allocate it     */

	    id = (struct InfoData *)
		AllocMem(sizeof(struct InfoData),MEMF_CLEAR);

	    if(id)
	    {
		/* Get info to see if disk is write protected */

	        success = Info(newlock, id);  
	        if(success)
	        {
		    if(id->id_DiskState == ID_WRITE_PROTECTED)
		    {
		        DirList(newlock, PROTECTED, whichdir);
			goto finish;
		    }
	        } 
		else
		{
		    printf("Can't get Info about current directory\n");
		    goto finish;	/* Info command failed */
		}
	        if(DirList(newlock, WRITEABLE, whichdir))
	        {
		    /* If DirList returns nonzero, means the file
		     * got created (there was at least one entry
		     * in the directory and the disk wasn't write
		     * protected.)
		     */ 
	             output_dirfile(newlock);  /* copy ".dir" to stdout */
	        }
	        goto finish;
	    }
	    else
	    {
	        printf("Not enough memory for InfoData\n");
		/* If this happens, there certainly isn't enough
		 * to generate a DirList either! 
		 */
	    }
    finish:		
	}
	if(id) FreeMem(id, sizeof(struct InfoData));
    cleanup:
	if(newlock) UnLock(newlock);
	/* move into the original directory from whence you came */
	ignorlock = CurrentDir(originallock);
/* 	if(originallock) UnLock(originallock);   */
}


/* output_dirfile -- copy ".dir" to stdout  	        	*/

output_dirfile(lock)
struct FileLock *lock;	/* shows the current directory to use */
{
    struct FileHandle *fh;
    struct FileLock *ignoredlock;
    UBYTE buffer[300];
    int actualcount, outcount;

    ignoredlock = CurrentDir(lock);	/* make sure are in correct place */
    fh = Open(".dir",MODE_OLDFILE);   
    if(fh)
    {
      while(1)				     /* forever, till EOF */
      {

        actualcount = Read(fh, buffer, 255); /* decent block size */
	if(actualcount == 255)
	{
	    /* ======================++++++++======================= */
	    /* NOTE: This assumes an AmigaDOS file handle for stdout */
	    /* ======================++++++++======================= */
	    outcount = Write(stdout, buffer, actualcount); 
	}
	if(actualcount < 255)
	{
	    outcount = Write(stdout, buffer, actualcount); 
	    break;
	}
	if(actualcount == -1)
	{
	    printf("Error ( %ld ) copying .dir to output\n",IoErr());
	    break;
	}
      }
    Close(fh);	/* close the file */
    }
    else
    {
	printf("'.dir' won't open!  IoErr() = %ld\n", IoErr());
    }
} 

/* DirList -- Look through the binary tree listing that tree() produced
 * 	      and output the names in that tree in alphabetical order.
 *	      If selected directory is writeable, create a file named
 * 	      .dir there, containing the formatted output.  Current
 * 	      implementation puts two names on each line, just like DIR.
 */


DirList(lock, protectstatus, pathname)   
struct FileLock *lock;
int protectstatus;
char *pathname;			/* Pathname that user gave us. */
{
    struct FileHandle *tfh;
    LONG success;
    struct tnode *allocated;
    struct tnode *t;
    LONG *ds;

    /* if at the end of the road, don't print anything */
    if(!lock) return(0);   

    root = (struct tnode *)
		AllocMem(sizeof(struct tnode),MEMF_CLEAR);

    if(!root) return(0);

    /* allocate space for a FileInfoBlock */

    m = (struct FileInfoBlock *)
    	AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR);

    if(!m) goto noentries;

    success = Examine(lock,m);

    if(!success) 
    {
	printf("Can't examine directory for '%ls'\n",pathname);
	goto noentries;
    }	
  	 
   /* The first call to examine fills the FileInfoBlock with 
    * INFORMATION ABOUT THE DIRECTORY.  If it is called at the 
    * root level, it contains the volume name of the disk.  If 
    * we're building a directory listing, we won't want this 
    * entry to be in it, so we call ExNext before starting the
    * listing itself.
    */

    /* Three conditions to consider here... 
     * a.  is NOT a directory.
     * b.  is an empty directory.
     * c.  has at least one entry.
     */

    /* NOT A DIRECTORY */

    if(m->fib_DirEntryType <= 0)
    {
	/* If this is true, we're dealing with a plain file.
	 * It should exit saying this is NOT a directory 
	 */
	printf("'%ls' is not a directory.\n",pathname);

  noentries:

	if(root) FreeMem(root, sizeof(struct tnode));
	/* treeprint normally frees all entries, including root, but
	 * we never get there so we have to free the memory here instead
	 */
	if(m) FreeMem(m, sizeof(struct FileInfoBlock));
	return(0);	/* didn't create a file, so don't print it. */
    }	
    success = ExNext(lock,m);

    /* EMPTY DIRECTORY */

    if(!(success)) 
    {
	printf("Directory '%ls' is empty.\n", pathname);
	goto noentries;
    }

    /* AT LEAST ONE ENTRY */
   
    /* Initialize the very first node */
	
    t = root;		
    strcpy(  &(t->name[0]), &(m->fib_FileName[0]) );
    if (m->fib_DirEntryType > 0)
    {
	strcat( &(t->name[0]), " (dir)" );
    }
    maxlen = MAX(maxlen, strlen( &(t->name[0])));

    /* t->left and t->right pointers are already set to zero by AllocMem */

    success = ExNext(lock,m);
    while (success)		/* was (success != 0)  */
    {
	t = root;	/* begin the search at the root */

 	/* Install it into the chain, recursively.  Allocated is an
	 * indicator that there was still enough memory to build a
	 * new chain for this node.  If allocated == 0, have to
	 * terminate prematurely.
	 */
	allocated = tree(t, &(m->fib_FileName[0]));
	if(allocated == 0) break;	
      	success = ExNext(lock,m);
    }
    if(allocated == 0)	/* header for the premature termination */
    {
	printf("\nPARTIAL DIR LISTING ONLY....NOT ENOUGH MEMORY\n");
	goto showlist;
    }
     
    /* "KLUGE".... we are trying to create a file named '.dir', but we
     * don't have any (FileInfoBlock) info about it yet since the builder 
     * of the file hasn't yet even written it.  So we'll take the very 
     * last entry in the file info block and modify its name field to 
     * be '.dir' so that this file name will actually appear in the listing.
     * (this is ok since tree() is not using anything but the name field).
     */

    if(protectstatus == WRITEABLE)
    {
        strcpy( &(m->fib_FileName[0]), ".dir" );
        allocated = tree(root, ".dir");		/* install .dir */
    }
showlist:

    /* Now begin to build the output listing, two to a line */

    sprintf(&linebuffer[0], "%ls", blanks);	/* blank first 35 locations */
    sprintf(&linebuffer[35], "%ls", blanks);	/* blank next  35 locations */
    linebuffer[67] = '\0';	/* null terminator */

    tfh = 0;				/* start out with no file open    */
    if(protectstatus == WRITEABLE)	/* If seems to be unprotected ... */
    {
	tfh = Open(".dir",MODE_NEWFILE);  /* if fails, tfh = 0 */
    }
    /* When this file is FIRST opened, the time of its parent directory
     * modification is established.  If we want to know if the file we
     * have created is current, we have to store the change time of the
     * parent directory in this file itself.  Then no matter, with
     * multi-tasking, how long it takes to create this .dir file
     * (whose date is established when it CLOSES), we'll have the
     * correct numbers to compare, and be zero time-ticks off.
     * The .dir file will contain its parent's creation date and time as the
     * first line, so you'll be able to see whether DIR gets generated
     * fresh or if it came from the .dir file.
     */
    success = Examine(newlock,m);	/* Succeeded once already so it
					 * should also succeed here.
					 * Now the date has been changed
					 * to reflect the .dir file opened.
					 */
    ds = (LONG *)&(m->fib_Date); 	/* Pass along the address of the 
					 * datestamp of the parent directory
					 */
    dotreeprint(root, tfh, ds);

    if(tfh) Close(tfh);
    if(m) FreeMem(m,sizeof(struct FileInfoBlock));
    return(TRUE);	/* Created a file, so its ok to print it later */
}

strcat( to, from )
register char *to, *from;
{
    while( *to ) to++;	/* find the end of the current string */

    strcpy( to, from ); /* then overlay trailing null, with first char.
			 * of the string to be concatenated. */
}

strlen( s )
register char *s;
{
    register i = 0;

    while( *s++ ) i++;

    return( i );
}

SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'tree.c'" '(3821 characters)'
if test -f 'tree.c'
then
        echo shar: will not over-write existing file "'tree.c'"
else
cat << \SHAR_EOF > 'tree.c'


/* tree.c */

/* Author:  Rob Peck  5/13/86 */

/* part of "fastdir" command */



#include "exec/types.h"
#include "libraries/dos.h"
#include "exec/memory.h"


#define MAX(x,y) (x > y ? x : y)

#define FASTDIR 1

#ifdef FASTDIR
extern struct FileInfoBlock *m;
#endif FASTDIR

extern int maxlen;

struct tnode    /* for quick alphabetizing */
{
        struct tnode *left;
        struct tnode *right;
        char name[36];  /* space to store the name (30 + ' (dir)') max */
        char dirflag;   /* nonzero if it is a directory */
};


/* tolower(c) --  Convert characters to lower case              */

int tolower( b )
        int b;
{
        if( (b >= 'A') && (b <= 'Z') )
                return(b - 'A' + 'a');
        else
                return( b );
}

/* tree -- Install a new named node at or below the one now pointed to
 * 	   RECURSIVELY CALLS ITSELF.... be careful not to run out of
 * 	   stack space if the strings nest too deeply.			
 */

struct tnode *tree(t, name)
	struct tnode *t;
	char *name;
{
	int cond;	/* Condition code from return */
	struct tnode *allocated;

	if(t == NULL)	/* If prior invocation has reached a null pointer,
			 * a new node must be allocated.
			 */
	{
	    t = (struct tnode *)
                AllocMem(sizeof(struct tnode),MEMF_CLEAR);

	    if(t == 0)
	    {
		/* NOT ENOUGH MEMORY TO FINISH THE TREE */
		/* Make sure to STOP!			*/

		return(0);	
	    }
    	    strcpy(  &(t->name[0]), name );
#ifdef FASTDIR
    	    if (m->fib_DirEntryType > 0)
    	    {
	    	strcat( &(t->name[0]), " (dir)" );
    	    }
#endif FASTDIR
    	    maxlen = MAX(maxlen, strlen( &(t->name[0])));

	    return(t);
	}		
	/* compare two strings and decide where to install the new one */

	cond = compLC(&(t->name[0]), name );

	if(cond < 0)
	{
	    if (t->left != NULL) /* search for a NULL entry */
	    { 
		return(tree(t->left, name)); 
	    }
	    else		 /* try to install at the null entry found */
	    { 
		allocated = tree(0, name);  
		/* If allocated == 0, then it passes a NULL all the
		 * way back to the caller, telling him the system has
		 * just run out of memory trying to build the chains.
		 * So it should consider the chain complete and try
		 * to output it, thereby freeing the memory along the way.
		 */  
		t->left = allocated;
		return(allocated);
	    }
	}
	else if(cond > 0)
	{
	    if (t->right != NULL) /* search for a NULL entry */
	    { 
		return(tree(t->right, name)); 
	    }
	    else		 /* try to install at the null entry found */
	    { 
		allocated = tree(0, name);
		t->right = allocated;
		return(allocated);
	    }
	}
	else 
	{
	/* If it EVER gets here, means entry of a duplicate item into tree.
	 * Is treated as an error.  Upper and lower case are the same and only
	 * get listed once.  Original application was for 'fastdir' and  
	 * AmigaDOS cannot install duplicate file names into a single 
	 * directory.
	 */
	return(0);
	}
}
 
strcpy( to, from )
register char *to, *from;
{
    do { 
        *to++ = *from;
    } while( *from++ );
}


/* compLC --    Compare two strings, ignoring case.
 *              returns -1 if s<t, 1 if s>t, 0 if s=t.
 */

int compLC(s,t)
register char *s, *t;
{
register char test;
    while(1)
    {
        test = tolower(*s)-tolower(*t); /* compare two characters */

        if (test < 0)
        {
           return(-1);        /* first less than second */
        }
        else
        {
            if (test > 0)
            {
                return(1);   /* first greater than second */
            }
            else             /* first equals second, so far */
            {
                if( *s == '\0')  /* if nulls match also, strings are equal */
                {
                    return(0);
                }
            t++;
            s++;
            }
        }
    }
}


SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'treeprint.c'" '(3624 characters)'
if test -f 'treeprint.c'
then
        echo shar: will not over-write existing file "'treeprint.c'"
else
cat << \SHAR_EOF > 'treeprint.c'

/* treeprint.c */

/* author:  Rob Peck  5/13/86 */

/* part of "fastdir" command  */


#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "exec/memory.h"
#define SPRINTF 1
#define FPRINTF 0

extern int leftright;
extern char *blanks;
extern char linebuffer[];
extern int (*fprintf)();

struct tnode    /* for quick alphabetizing */
{
        struct tnode *left;
        struct tnode *right;
        char name[36];  /* space to store the name (30 + ' (dir)') max */
        char dirflag;   /* nonzero if it is a directory */
};
/* This SPECIAL VERSION of strcpy does NOT copy the trailing null */

mystrcpy( to, from )
register char *to, *from;
{
    char *leadingfrom;
    leadingfrom = from + 1;
    do {
        *to++ = *from++;
    } while( *leadingfrom++ );
}


/* treeprint -- recursive output, to stdout or to a file, from the 
 * 		linked node list that tree() creates.  tree() allocates
 * 		memory;  treeprint() deallocates it as it runs
 */

treeprint(t,tfh)		/* print the tree recursively */
struct tnode *t;
struct FileHandle *tfh; 	/* if theres a file open, use it */
{
	int actual;
	if(t->right != NULL) treeprint(t->right,tfh);
	if(leftright == 0)
	{
	    mystrcpy(&linebuffer[2], blanks);	/* blank the string */
	    mystrcpy(&linebuffer[2], &(t->name[0])); /* install the name */
 	    mystrcpy(&linebuffer[35],blanks);	/* blank out rest. */
	    leftright = 1;
	}
	else
	{
	    mystrcpy(&linebuffer[35], &(t->name[0])); /* install the name */
	    leftright = 0;
	    if(tfh == 0)
	    {
	        printf("%ls\n", linebuffer);
	    }
	    else
	    {
	        actual = Write(tfh, linebuffer, 66);
		actual = Write(tfh, "\n", 1);
	    }
	}
	if(t->left != NULL) treeprint(t->left,tfh);
	FreeMem(t, sizeof(struct tnode));
	return(0);
}

dotreeprint(root, tfh, ds)
    struct tnode *root;
    struct FileHandle *tfh;
    LONG *ds;			/* points to the datestamp */
{
    char dummy[50];		/* When call for FPRINTF, dummy is not used. */
    
    if(tfh)
    {
	DateToAscii(FPRINTF, dummy, ds, tfh);
    }	
    treeprint(root, tfh);    /* call does all except the final line */
    if(leftright == 1) 
    {
	if(tfh)	/* if there is a file open, thats where the output goes. */
	{
	    Write(tfh, linebuffer, 66);
	    Write(tfh, "\n", 1);
	}
	else	/* otherwise print it to stdout */
	{
	    printf("%ls\n",linebuffer);
	}
    }
}

/* This routine can accept either "FPRINTF", which expects whereto
 * to be a file handle, or "SPRINTF", which expects whereto to be the
 * address of a string.
 */

DateToAscii(routine, whereto, ds, tfh)
	LONG routine;		/* which routine to use   */
	char *whereto;
	struct FileHandle *tfh;

	LONG *ds;		/* pointer to a datestamp */
{
	char dateout[50];	/* only need about 41, but this is ok */
	int actual;
	LONG n ;	/* number of days past 1/1/78 */
   	int m, d, y ;	/* month, day, year */
	int h, mn, sec; /* hours, minutes, seconds */
	n = ds[0] - 2251 ;
   	y = (4 * n + 3) / 1461 ;
   	n -= 1461 * y / 4 ;
   	y += 84 ;		/* was 1984 */
   	m = (5 * n + 2) / 153 ;
   	d = n - (153 * m + 2) / 5 + 1 ;
   	m += 3 ;
   	if (m > 12) 
	{
      		y++ ;
      		m -= 12 ;
   	}
	h = ds[1] / 60;	/* 60 minutes per hour */
	mn = ds[1] - h * 60; /* remainder is the minutes */
	sec = ds[2] / TICKS_PER_SECOND;
	switch(routine)
	{
	   case SPRINTF:
		sprintf(whereto, 
	"<dir> Creation Date: %02ld/%02ld/%02ld %02ld:%02ld:%02ld.\n",m,d,y,h,mn,sec);
	   	break;
	   case FPRINTF:
		sprintf(dateout, 
	"<dir> Creation Date: %02ld/%02ld/%02ld %02ld:%02ld:%02ld.\n",m,d,y,h,mn,sec);
		actual = Write(tfh, dateout, 41);
	   	break;
	   default:
		break;
	}	
	return(0);
}


SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'filecurrent.c'" '(4296 characters)'
if test -f 'filecurrent.c'
then
        echo shar: will not over-write existing file "'filecurrent.c'"
else
cat << \SHAR_EOF > 'filecurrent.c'


/* filecurrent.c */

/* Author:  Rob Peck   5/13/86  */

/* part of "fastdir" */


#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "exec/memory.h"

#define ABS(x) (x > 0 ? x : -x)
#define SPRINTF 1
#define FPRINTF 0

extern struct FileLock *Lock(),*DupLock();
extern struct FileLock *CurrentDir(), *ParentDir();
extern struct FileHandle *stdout, *Open();

/* filecurrent -- See if there is a "current" copy of a specified file name
 *		  in the directory in which we now reside.  Return FALSE if
 *		  it is either nonexistent, or if it is non-current, based
 *		  on the minutes and seconds information passed to this
 *		  subroutine.  (When a file is opened into a directory
 *		  under AmigaDOS, both the file-written date and the 
 *		  directory-written date are modified.  The file date
 *		  itself gets written when it is closed.)  
 */

int 
filecurrent(name, error)

	char *name;	/* What is the name of the file to look for */
	int *error;	/* Where to put an error code, if and only if
			 * a value of FALSE is returned (TRUE is expected).
			 */
{
	LONG success, i; 
	LONG *parentdate;
	struct FileHandle *fh;
	char cbuffer[50];	    /* creation date buffer */
	char dbuffer[50];	    /* .dir file contents   */
	int actual, status;

	struct FileInfoBlock *fib;  /* for getting date information 	  */
	struct FileLock *filelock;  /* lock on the selected file          */
	struct FileLock *currentlock;  /* lock on the selected file       */
	struct FileHandle *dummyfh;

	dummyfh = NULL;		    /* not used anyhow */
	fib = NULL;
	currentlock = NULL;
	filelock = NULL;

	/* Try to lock this file, just to see if it exists */

	filelock = Lock(name, ACCESS_READ);

	if(!filelock)
	{
	    *error = ERROR_OBJECT_NOT_FOUND; 
	    return(FALSE);	/* If non-existent, it is not current! */
	}
	UnLock(filelock);
	filelock = NULL;

 	/* Once we get here, we know that the file exists, but we now
	 * have to determine whether it is current.  If it didn't exist,
	 * the above return(FALSE) would have happened.  Now read the 
	 * last modified date of the directory the file is in to get
	 * something against which to compare.  This particular date
	 * is stored as the first info within the file itself.
	 */

	/* FileInfoBlock MUST BE LONGWORD ALIGNED, so we have to 
	 * dynamically allocate it.
	 */

	fib = (struct FileInfoBlock *)
		AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR);

	if(fib == 0)	/* no memory for file info block? */
	{
	    *error = ERROR_NO_FREE_STORE;
	    return(FALSE);	/* Cannot allocate memory */
	}
	
	/* initialize the buffers */

	for(i=0; i<50; i++)
	{
	    cbuffer[i] = 0x20;  /* ascii blank */
	    dbuffer[i] = 0x20;
	}
	cbuffer[49] = 0;  dbuffer[49] = 0;	/* end of string nulls */
	
	/* (Passing a null-string asks for a lock on the current directory) */

	/* Look at the directory we've moved into, and check its mod date   */
	/* Start by getting a lock on the current directory		    */

	currentlock = Lock("",ACCESS_READ);
	if(!currentlock)
	{
	    *error = ERROR_DIR_NOT_FOUND;  /* Can't lock current directory */
	    status = FALSE;
	    goto cleanfinish;
	}

	/* Now using that lock, Examine current directory to get the date */

	success = Examine(currentlock,fib);
	if(success)
	{
	    parentdate = (LONG *)&(fib->fib_Date);
	    DateToAscii(SPRINTF, cbuffer, parentdate, dummyfh);
	}
	status = FALSE;	   /* Start out assuming it is not the same */
	*error = 0;	   /* A false return with 0 errors is valid....
			    * it means file found, but not up to date   
			    */
	
	fh = Open(name,MODE_OLDFILE);
	if(!fh) goto cleanfinish;

	actual = Read(fh, dbuffer, 40);	/* get the date from the file */
	if(actual != 40)
	{
	    printf("Error while reading %ls\n",name);
	    goto cleanfinish;
	}
	status = comparedates(cbuffer, dbuffer);

    cleanfinish:

	if(fh) Close(fh);
	if(fib) FreeMem(fib, sizeof(struct FileInfoBlock));
	if(currentlock) UnLock(currentlock);
	return(status);
}

comparedates(s,t)
	char *s, *t;
{
	while( *s == *t )
	{
	    if(*s == '.') 	/* both equal and reach a period, ok! */
	    {
		return(TRUE);
	    }
	    if(*s == '\0') return(FALSE);	/* error, hit end of string
						 * without finding '.' 
						 */
	s++; t++;
	}
	return(FALSE);	/* found an unequal character prior to the period */
}


SHAR_EOF
fi # end of overwriting check
#       End of shell archive
exit 0