/*
 *	$VER:RDBMount.c - (21.10.95) Copyright © 1991 by S.R. 13:59:49 14:43:45
 *
 *      Created: 28 Mar 1993
 *      Modified:	21 Oct 1995	14:43:45
 *
 * Make>> SC <file>.c
 * Make>> SLink Lib:Entry.o <file>.o LIB Lib:String.lib Lib:sc.lib MAP <file>.map F,H,L,O,S,X NOICON VERBOSE SmallCode SmallData BATCH
 * Ma ke>> SLink Lib:Entry.o <file>.o LIB Lib:Startup.lib Lib:String.lib MAP <file>.map F,H,L,O,S,X NOICON VERBOSE SmallCode SmallData BATCH
 *
 *	95.10.12:
 *		Add DosType keyword.
 */

#include <Main.h>
#include <StringLib.h>

#include <Libraries/HardBlocks.h>
/*#include <pragmas/HardBlocks_pragmas.h> */

#define MAXSTRINGLEN 255/2
#define MAXNUMARGS 64
#define MAXDEFAULTLEN 512/2

STRPTR Template = "DosDev/M/A,ExecDev,UnitNr/N,FS/K,DosType/K";

enum WORD { ARG_DosDevA = 0, ARG_ExecDev, ARG_UnitNr, ARG_FS, ARG_DosType, ARG_ENDARG};

STRPTR CliHelp = "RDBMount V1.2 [32m "__DATE__" © Sylvain ROUGIER.[31m\n\
Usage: RDBMount <DosDevName> [ExecDevName] [ExecUnitNr] [ FS FileSystemName] [DosType <DosType_in_hex>]\n\
Default: ExecDevName = scsi.device ExecUnitNr = 0 or read Env \"RDBMount.DefOpts\"\n\
Use to mount DOS Dev from the RigidDiskBlock information stored on (HD) drive\n";

const STRPTR VersTag = "$VER:RDBMount 1.1 (21.10.95) "__DATE__ " " __TIME__ " © Sylvain ROUGIER";

struct DosLibrary *DOSBase;
struct Library *UtilityBase;
struct Library *ExpansionBase;
struct Library *HardBlocksBase;

char * CStrToBStr( char CStr[])
{
	ULONG l;
	char *BStr;

	l = strlen( CStr);
	if ( BStr = AllocMem( l + 1 + 1, MEMF_PUBLIC))
		{
			strcpy( &BStr[ 1], CStr);
			BStr[ 0] = l;
			return BStr;
		}

	return NULL;
}

char *B2CStr(UBYTE * BStr, char Buff[])
{
	UBYTE i;

	for (i = 0; i < *BStr; i++)
	{
		Buff[i] = (BStr + 1)[i];
	}
	Buff[i] = '\0';

	return Buff;
}

BOOL IsMounted(char DosName[])
{
	struct DosList *DList;
	BOOL Found = FALSE;

	DList = LockDosList(LDF_DEVICES | LDF_READ);
	Found = (BOOL) FindDosEntry(DList, DosName, LDF_DEVICES);
	UnLockDosList(LDF_DEVICES | LDF_READ);

	return Found;
}

ULONG __asm Main(register __a0 APTR ArgV[], register __a1 struct WBStartup * WBenchMsg);
ULONG __asm __Main(register __d2 ULONG CmdLen, register __a2 STRPTR CmdPtr)
{
	struct Process *pp;
	ULONG RC = 1001;	/* assumle the worst */

	pp = (struct Process *)FindTask(0L);

	if (DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 34L))
	{
		if (DOSBase->dl_lib.lib_Version > 36)
		{
			APTR ArgV[MAXNUMARGS];
			struct RDArgs *RA;
			struct RDArgs *DefaultRDArgs;

			UtilityBase = DOSBase->dl_UtilityBase;
			if (RA = AllocDosObject(DOS_RDARGS, NULL))
			{
				memset(ArgV, 0, MAXNUMARGS * sizeof (APTR));
				RA->RDA_ExtHelp = CliHelp;
				/* first read default */
				/* getting the default string */
				if (DefaultRDArgs = AllocDosObject(DOS_RDARGS, NULL))
				{
					UBYTE Default[MAXDEFAULTLEN] = "DosDev Dummy ExecDev scsi.device UnitNr 0";

					if ((DefaultRDArgs->RDA_Source.CS_Length = GetVar("RDBMount.DefOpts", Default, MAXDEFAULTLEN - 1, 0L)) > 0)
						;
					else
						DefaultRDArgs->RDA_Source.CS_Length = strlen(Default);
					{
						/* let ReadArgs() allocate neccesary buffer sinc I use diferrent RDArgs for Default and CLI opts */

						/* Ok I succefuly read a Default Option string now parse it */
						Default[DefaultRDArgs->RDA_Source.CS_Length++] = '\n';	/* this is need by ReadArgs() */
						Default[DefaultRDArgs->RDA_Source.CS_Length] = '\0';	/* this is need by ReadArgs() */
						DefaultRDArgs->RDA_Source.CS_Buffer = Default;
						DefaultRDArgs->RDA_Source.CS_CurChr = 0;
						DefaultRDArgs->RDA_Flags = RDAF_NOPROMPT;
						if (!ReadArgs(Template, (long *)ArgV, DefaultRDArgs))
						{
							PutStr("Error in Default:");
							PrintFault(IoErr(), NULL);
							memset(ArgV, 0, MAXNUMARGS * sizeof (APTR));
						}
						DefaultRDArgs->RDA_Source.CS_Buffer = NULL;	/* Now ReadArgs() from Command line */
						/* the ArgV is leaving unchanged: the second ReadArgs() take actual value as default */
					}
				}
				/* Let ReadArgs() allocate necessay buffer rather using stack space */
				if (ReadArgs(Template, (long *)ArgV, RA))
				{
					RC = Main(ArgV, NULL);
				}
				else
				{
					PrintFault(IoErr(), NULL);
					RC = 20;
				}
				FreeDosObject(DOS_RDARGS, RA);
				/* Free RDargs now I don't need the option value */
				if (DefaultRDArgs)
					FreeDosObject(DOS_RDARGS, DefaultRDArgs);
			}
		}
		else
		{
			Write(pp->pr_COS, "You need KickStart 2.0+\n", 24L);
			RC = 1000;
		}
		CloseLibrary((struct Library *)DOSBase);
	}

	return RC;
}

struct FileSysEntry *GetFileSys( ULONG DosType)
{
	struct FileSysResource *FileSysResource;
	struct FileSysEntry *i;

	if ( FileSysResource = OpenResource( "FileSystem.resource"))
	{
		for ( i = ( struct FileSysEntry *)FileSysResource->fsr_FileSysEntries.lh_Head; i->fse_Node.ln_Succ; i = ( struct FileSysEntry *)i->fse_Node.ln_Succ)
		{
			if ( i->fse_DosType == DosType)
				return i;
		}
	}

	return NULL;
}

ULONG __asm Main(register __a0 APTR ArgV[], register __a1 struct WBStartup * WBenchMsg)
{
	ULONG RC = 20;		/* default :Don't find desired Partition */

	ExpansionBase = OpenLibrary("expansion.library", 37L);

	if (HardBlocksBase = OpenLibrary(HardBlocksName, HardBlocksVersion))
	{
		struct RigidDiskBlock rdb;

		if (!(RC = LoadHardBlocks(&rdb, ArgV[ARG_ExecDev], *((ULONG *) ArgV[ARG_UnitNr]))))
		{
			#define MAXMOUNT 10
			ULONG parmPkt[MAXMOUNT][21 + 10];	/* WARN: this is a lenthg which can change */
			char DevNames[MAXMOUNT][20];	/* mem string don't be lost until the mount */
			UBYTE MountCnt = 0;
			UBYTE i, j;
			char *Str;

			for (i = 0, Str = ((char **)ArgV[ARG_DosDevA])[0]; Str && (i < MAXMOUNT); i++, Str = ((char **)ArgV[ARG_DosDevA])[i])
			{
				BOOL Found = FALSE;
				struct PartitionBlock *PB;
				char Buff[MAXSTRINGLEN];
				char DosDevName[MAXSTRINGLEN];

				strcpy(DosDevName, Str);
				{
					UBYTE l;

					if (DosDevName[l = (strlen(DosDevName) - 1)] == ':')
						DosDevName[l] = '\0';
				}
				if (!IsMounted(DosDevName))
				{
					for (PB = (struct PartitionBlock *)rdb.rdb_PartitionList; PB && !Found; PB = (struct PartitionBlock *)PB->pb_Next)
					{
						B2CStr(PB->pb_DriveName, Buff);
						//Printf( "Dos Name:\"%s\"\n", Buff);
						//Printf("pb:%lx, next:%lx\n", PB, PB->pb_Next);
						if (!Strnicmp(DosDevName, Buff, MAXSTRINGLEN))
						{
							Found = TRUE;
							strcpy(DevNames[MountCnt], Buff);
							parmPkt[MountCnt][0] = (ULONG) DevNames[MountCnt];
							parmPkt[MountCnt][1] = (ULONG) ArgV[ARG_ExecDev];
							parmPkt[MountCnt][2] = *((ULONG *) ArgV[ARG_UnitNr]);	/* unit number */
							parmPkt[MountCnt][3] = 0;	/* OpenDevice flags */
							if ( ArgV[ ARG_DosType])
							{
								ULONG DosType= 0x00000000;

								if ( 8 == stch_l( ArgV[ ARG_DosType], (LONG *)&DosType))
									PB->pb_Environment[ DE_DOSTYPE] = DosType;
								else
								{
									Printf( "DosType:%s invalid (%l08x)\n", ArgV[ ARG_DosType], DosType);
									break;
								}
							}
							CopyMem(PB->pb_Environment, &parmPkt[MountCnt][4], sizeof (PB->pb_Environment));
							MountCnt++;
						}
					}
					if (!Found)
						Printf("\"%s:\" not found.\n", DosDevName);
				}
				else
				{
					Printf("\"%s:\" alredy mounted.\n", DosDevName);
				}
			}
			for (j = 0; j < MountCnt; j++)
			{
				struct DeviceNode *DeviceNode;

				if (DeviceNode = MakeDosNode(parmPkt[j]))
				{
					struct FileSysEntry *FileSysEntry;

					if ( FileSysEntry = GetFileSys( parmPkt[ j][ 3 +17]))
					{
						if ( FileSysEntry->fse_PatchFlags & 0x00000001)
							DeviceNode->dn_Type = FileSysEntry->fse_Type;
						if ( FileSysEntry->fse_PatchFlags & 0x00000002)
							DeviceNode->dn_Task = ( struct MsgPort *)FileSysEntry->fse_Task;
						if ( FileSysEntry->fse_PatchFlags & 0x00000004)
							DeviceNode->dn_Lock = FileSysEntry->fse_Lock;
						if ( FileSysEntry->fse_PatchFlags & 0x00000008)
							DeviceNode->dn_Handler = FileSysEntry->fse_Handler;
						if ( FileSysEntry->fse_PatchFlags & 0x00000010)
							DeviceNode->dn_StackSize = FileSysEntry->fse_StackSize;
						if ( FileSysEntry->fse_PatchFlags & 0x00000020)
							DeviceNode->dn_Priority = FileSysEntry->fse_Priority;
						if ( FileSysEntry->fse_PatchFlags & 0x00000040)
							DeviceNode->dn_Startup = FileSysEntry->fse_Startup;
						if ( FileSysEntry->fse_PatchFlags & 0x00000080)
							DeviceNode->dn_SegList = FileSysEntry->fse_SegList;
						if ( FileSysEntry->fse_PatchFlags & 0x00000100)
							DeviceNode->dn_GlobalVec = FileSysEntry->fse_GlobalVec;
						/*{
							struct FileSysStartupMsg *fssm;
							struct DosEnvec *de;
							fssm = BADDR( DeviceNode->dn_Startup);
							de = BADDR( fssm->fssm_Environ);
							Printf( "toto");
						}*/
					}
					else
						Printf( "Can't find Segment for DosType:%l08x in FileSystem.resource\n", parmPkt[ j][ 3 +17]); 
					if ( ArgV[ ARG_FS])
					{
						DeviceNode->dn_Handler = MKBADDR( CStrToBStr( ArgV[ ARG_FS]));
						DeviceNode->dn_SegList = NULL;
						DeviceNode->dn_GlobalVec = -1;
					}
					
					if (!AddDosNode(-128, ADNF_STARTPROC, DeviceNode))
					{
						Printf("\"%s\" can't be Mounted\n", parmPkt[j][0]);
					}

				}
			}
			FreeHardBlocks(&rdb);
		}
		else
			Printf("Unable to Load RDB from \"%s\" %ld\n", ArgV[ARG_ExecDev], *((ULONG *) ArgV[ARG_UnitNr]));
		CloseLibrary(HardBlocksBase);
	}
	else
		Printf("Unable to open hardblocks.library V1+\n");

	CloseLibrary(ExpansionBase);

	return RC;
}
