/* Find the file whose name matches that passed as first argument.
 * Print the filename and its volume:path to the screen
 * Some cosmetic modifications made to this code to report the
 * size and last change date/time of the file as it is listed.
 * Changes marked with KDP (very minor changes) - Ken Presser.
 */
#include <exec/types.h>
#include <devices/keymap.h>
#include <intuition/intuition.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include <ctype.h>

#define BELL 0x07
/*
 *                 F U N C T I O N     D E C L A R A T I O N S
 */
extern struct FileLock * Lock();

BOOL ifoundit;
/* home grown subrs: */
void close_things();

/*
 *                  M A I N     P R O G R A M     M O D U L E
 */
void
main( argc,argv)
int argc;
char * argv[];
{
	void scan_directory ();
	struct FileLock * Lock ();
	void UnLock ();
	char * strcpy ();

	struct FileLock * dir;
	char path[130];			/* hold volume name */
	char devname[32];
	char searchfile[32];
	char * ch;
	UBYTE i;

	if ((argc > 3) || (argc == 1))
		printf ("usage: whereis <filename> <devname>\n");
	else
		{
		ifoundit = FALSE;
		/* devname not specified */
		if (argc == 2)
			strcpy(devname,":");				/*KDP*/
		else
			{
			for (i=0;i<32;i++)
				devname[i] = '\0';
			strncpy (devname,argv[2],31);
			}
		strcpy (searchfile, argv[1]);
		/* upcase input string, simplify matching process */
		for (ch=searchfile; *ch != '\0'; ch++)
			*ch = toupper (*ch);
		/* Get Lock on disk */
		if ( (dir = Lock (devname,ACCESS_READ)) == NULL)
			{
			printf ("Could not obtain lock on device %s\n",
				devname);
			printf ("Then Die Ceasar\n");
			close_things ();
			exit (5);
			}
		else
			strcpy (path, devname);
		/* DO IT TO IT! */
		scan_directory (searchfile,path);
		}
	close_things ();
} /* end main */

/*
.page.index close_index
Do whatever final clean up is needed to leave the program.
 */
void
close_things()
{
	if (!ifoundit)
		printf ("Sorry, couldn't find it.\n");
	return;
} /* end close_things */


/*
.page.index scan_directory
 */
void
scan_directory (searchfile,path)
char * searchfile;
char * path;
	{
	char * strcpy ();
	void UnLock ();
	struct FileLock * dir;
	struct FileInfoBlock * fb;
	char * adddir ();

	/* WE GOTTA BE STINGY WITH LOCAL STORAGE, THIS IS RECURSING!
	 * CAN'T EAT TOO MUCH STACK.
	 */
#	define MAXSUB 100
	char * subdir [MAXSUB];	/* Pointer area for Sub-Directories */
	char pathname[130];	/* Pointers to AmigaDOS sub-directories */
	UBYTE countdir,indexdir,i;
	char testname[32],prntname[32];				/*KDP*/

	/* Get Lock on this directory */
	if ( (dir = Lock (path,ACCESS_READ)) == NULL)
		{
		printf ("%cCould not obtain lock on directory %s\n",
			BELL, path);
		printf ("Then Die Ceasar\n");
		close_things ();
		exit (4);
		}

	/* Examine lock and obtain FileInfoBlock */
	fb=(struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock),0);
	if (!Examine (dir,fb))
		{
		printf ("%cCouldn't Examine files assoc with lock\n",BELL);
		printf ("Then Die Ceasar\n");
		UnLock (dir);
		FreeMem ((char *)fb, sizeof (struct FileInfoBlock));
		close_things ();
		exit (4);
		}
	/* we now have dir and fb set up, 
	 * scan all files at this level 
	 * (remembering subdirectories)
	 */
	countdir = 0;
	while ((ExNext(dir,fb),IoErr() != ERROR_NO_MORE_ENTRIES) 
		&& (countdir <= MAXSUB)
		) 
		{
		if (fb->fib_DirEntryType > 0)
			{
			/* we have a subdirectory here... */
			if (countdir < MAXSUB)
				subdir[countdir] = 
					adddir (fb->fib_FileName);
			else
				printf ("%cToo few subdirectory slots\n",
					BELL);
			countdir++;
			}
		else
			{
			/* compare fb->filename with searchfile */
			for (i=0;i<32;i++)
				testname[i] = prntname[i] = '\0';		/*KDP*/
			strncpy (prntname,fb->fib_FileName, 32);	/*KDP*/
			testname[31] = prntname[31] = '\0';			/*KDP*/
			for (i = 0; (prntname[i] != '\0')&&(i<32); ++i)		/*KDP*/
				testname[i] = toupper (prntname[i]);	/*KDP*/
#			if 0
			printf ("%s =?= %s\n",testname, searchfile);
#			endif
			if (strcmp (testname,searchfile)==0)
				{
				printf ("%s/%s\tSize=%ld\t",			/*KDP*/
					path,prntname,fb->fib_Size);		/*KDP*/
				datetime(fb->fib_Date.ds_Days,			/*KDP*/
					fb->fib_Date.ds_Minute);			/*KDP*/
				printf("\n");							/*KDP*/
				ifoundit = TRUE;
				}
			}
		} /* end while */
	/* return these now, we're done, thank you. */
	UnLock (dir);
	FreeMem ((char *)fb, sizeof (struct FileInfoBlock));

	/* finished with this level, try one level down */
	indexdir = 0;
	while (indexdir < countdir)
		{
		strcpy (pathname,path);
		/* if no path delimiter, add one */
		if (       (path[strlen(path)-1] != ':') 
			&& (path[strlen(path)-1] != '/') 
			&& (strlen(path) > 0))
          		strcat (pathname,"/");
		strcat (pathname,subdir[indexdir]);

		scan_directory (searchfile,pathname);

		/* and pick up litter left by adddir() */
		FreeMem ((char *)subdir[indexdir],
			strlen(subdir[indexdir])+1);
		subdir[indexdir] = NULL;
		indexdir++;
		}

	return;
}	/* end scan_directory */

/*
.page.index adddir
 ----------------------------------------------------------------------------
	Allocate some memory and then copy string into it.
 */
char * adddir (string)
char * string;
{
	char * nameadd;    /* Address of the directory name */

	nameadd = (char *) AllocMem (strlen(string)+1,0);
	if (nameadd == NULL)
		{
		printf ("Not Enough Memory for Directories!!!\n");
		/* run away! run away! */
		close_things ();
		exit (7);
		}
	strcpy (nameadd, string);

	/* return address of string you just alloated. */
	return (nameadd);

}	/*end adddir*/

/*
** The following slightly modified to act as a subroutine and
** to be less verbose - KDP
*/

/* A non-recursive date calculator for the Amiga by John A. Hodgson.
                      May be distribute freely
   The algorithm requires a correction for multiples of 59 years from
   the base date (1978), non - leap years falling on a new century and
   dates more than 365 years from the base date. As much as I like the
   Amiga, I didn't think it would be around (functionally) by then, so
   didn't put these in.          --- Enjoy ---                         */

int dpm[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

datetime(ddate,minutes)
long	ddate,minutes;
{
	int		i, years, lpyears, leaprem, days, hour, minute;

	years =  ddate / 365;           /* approx number of years past  */
	lpyears  =  (years+2) / 4;      /* approx number of leap years  */
	leaprem  =  (years+2) % 4;
	if (!(leaprem)) {               /* if we are in a leap year     */
		lpyears  =  lpyears - 1;    /* don't correct days           */
		dpm[1]   =  29;             /* but fix February             */
	}
	days  =    1 + ddate % 365 - lpyears;  /* 1 + for Jan 1, 1978    */
                                     /* approx correction to days    */
	if (days <= 0) {                 /* check if we overflowed a year*/
		years =  years - 1;          /* and correct years            */
		days  =  days + 365;         /* and days                     */
		if (!(leaprem)) {            /* if we backed off a leap year */
			days = days - 1;         /* we lose the extra day        */
		}
		dpm[1]   =  28;              /* restore February             */
		if (leaprem == 1) {          /* if overflowed to a leap year */
			dpm[1]   =  29;          /* fix February                 */
		}
		days  =  days + 1;           /* and days                     */
	}

	years =  years + 1978;

	i  =  0;
	while (days > 0) {
		days = days - dpm[i++];      /* figure which month           */
	}
	days  =  days + dpm[--i];        /* and day                      */

	hour = minutes / 60;
	minute = minutes % 60;

	printf ("%2d/%02d/%04d at %2d:%02d",(i+1),days,years,hour,minute);

	return 0;
}
