/*  :ts=8 bk=0
 * Filesystem routines (or, How To Find A File The Hard Way)
 */
#include <exec/types.h>
#include <devices/trackdisk.h>
#include "things.h"

extern struct IOExtTD	*diskreq;
extern ULONG		diskchangecount, *diskbuffer;


findfile (name)		/*  Traverse the filesystem the hard way  */
char *name;
{
	register int err;
	register char *b, *e;
	char str[80];

	strcpy (str, name);
	if (b = index (str, ':'))	/*  Ignore device names  */
		b++;
	else
		b = str;

	while (*b == '/')	/*  Ignore leading slashes  */
		b++;
	if (!*b) {		/*  Don't do anything if string is empty  */
		notice ("Badly formed filename.");
		return (0);
	}

	e = b;
	MotorOn ();
	GetSector (ROOTBLOCK);	/*  All paths are relative to the root  */
	while (e) {
		if (!*b) {
			notice ("Badly formed filename.");
			return (0);
		}

		if (e = index (b, '/'))
			*e = '\0';

		if ((err = traverse (b, hash (b))) < 0) {
			switch (err) {
			case -1:
				notice ("Badly formed path.");
				break;
			case -2:
				notice ("File not found.");
				break;
			}
			return (0);
		}

		if (e) {
skip:			b = e+1;
			while (*b == '/')
				b++;
		}
	}
	drawfile ();
	MotorOff ();
	return (1);
}

traverse (str, hash)	/*  Indirect through the disk blocks  */
char *str;
int hash;
{
	register int block;
	register char *file = (char *) &diskbuffer [NAME];

	if (diskbuffer [TYPE] == T_SHORT &&
	    diskbuffer [SECONDARY_TYPE] == ST_FILE)
		/*  Can't indirect out of a file  */
		return (-1);

	strupper (str);
	block = diskbuffer [hash];
	for ever {
		if (!block)
			return (-2);	/*  No such file  */
		GetSector ((long) block);
		/*  Force null termination in case BCPL doesn't do it  */
		file [*file + 1] = '\0';
		strupper (file+1);	/*  Force to all upper case  */
		if (!strcmp (str, file+1))	/*  Is this it?  */
			break;
		/*  This ain't it; traverse hash chain  */
		block = diskbuffer [HASHCHAIN];
	}
	return (1);
}

drawfile ()	/*  Draw file's allocated sectors  */
{
	register int i;

	/*
	 * File control blocks are marked with pen 1, data blocks with pen 2.
	 */
	marksector (diskbuffer [HEADER_KEY], 1);

	if (diskbuffer [TYPE] == T_SHORT &&
	    diskbuffer [SECONDARY_TYPE] == ST_FILE)
		for ever {
			for (i=FH_BLOCKLIST; i>=FH_ENDLIST; i--)
				if (diskbuffer [i])
					marksector (diskbuffer [i], 2);
			if (diskbuffer [EXTENSION]) {
				marksector (diskbuffer [EXTENSION], 1);
				GetSector (diskbuffer [EXTENSION]);
			} else
				break;
		}
}

strupper (str)
register char *str;
{
	while (*str) {
		*str = toupper (*str);
		str++;
	}
}


/*
 * The following routines were stolen from an RKM example by Bob Peck and
 * hacked up a bit.
 */

GetSector (sector)
long sector;
{
	LONG offset = sector * BLOCKSIZE;

	diskreq -> iotd_Req.io_Length = BLOCKSIZE;      
	diskreq -> iotd_Req.io_Data = (APTR) diskbuffer;	
		/* show where to put the data when read */
	diskreq -> iotd_Req.io_Command = ETD_READ;
		/* check that disk not changed before reading */
	diskreq -> iotd_Count = diskchangecount;
	
	/* convert from cylinder, head, sector to byte-offset value to get
   	 * right one (as dos and everyone else sees it)...*/
	
	/* driver reads one CYLINDER at a time (head does not move for
	 * 22 sequential sector reads, or better-put, head doesnt move for
	 * 2 sequential full track reads.)
	 */
	
	diskreq -> iotd_Req.io_Offset = offset;
	DoIO (diskreq);
	return (0);
}

MotorOn()
{
	/* TURN ON DISK MOTOR ... old motor state is returned in io_Actual */
	diskreq -> iotd_Req.io_Length = 1;
	/* this says motor is to be turned on */
	diskreq -> iotd_Req.io_Command = TD_MOTOR;
	/* do something with the motor */
	DoIO (diskreq);
	return (0);
}

MotorOff()
{
	diskreq -> iotd_Req.io_Length = 0;	
	/* says that motor is to be turned on */
	diskreq -> iotd_Req.io_Command = TD_MOTOR;	
	/* do something with the motor */
	DoIO (diskreq);
	return (0);
}


/*
 * The following code segment was thrown at the USENET by Neil Katin.
 * Thanks, Neil.
 */

hash (str)
unsigned char *str;
{
	int res;
	unsigned char *sp;
	unsigned c;

	res = strlen (str);

	for (sp = str; *sp; sp++) {
		c = *sp;
		if (c >= 'a' && c <= 'z')
			c = c - 'a' + 'A';
		res = ((res * 13 + c) & 0x7ff);
	}
	return (res % 72 + DIR_HASHTAB);
}
