
#define                                BSTRADDR(bstr)       ((char *)((((ULONG)bstr)<<2)+1))


/**********************************************************************/
/*                    Get device and volume lists                     */
/**********************************************************************/
static BOOL GetDevVolList(struct List *VolList)
{
	NewList(VolList);
	VolList->lh_Type = 0;

	if(GetDosEntries(VolList, LDF_DEVICES))
	{
		if(GetDosEntries(VolList, LDF_VOLUMES))
		{
			SortList(VolList, FALSE);
			return(TRUE);
		}
	}

	return(FALSE);
}



/**********************************************************************/
/*                     Collect available volumes                      */
/**********************************************************************/
static BOOL GetDosEntries(struct List *VolList, ULONG Mode)
{
	struct	DosList		*DList;
	struct	VolEntry	*NewEntry;
	BOOL			RetVal		= TRUE;

		// Lock DOS-List of Volumes

	if((DList = LockDosList(Mode|LDF_READ)))
	{
			// Loop for all entries

		while(RetVal && (DList = NextDosEntry(DList, Mode|LDF_READ)))
		{
				// Alloc memory for new entry

			if((NewEntry = AllocVecPool(FIconSema, sizeof(struct VolEntry))))
			{
					// Add to list

				AddTail(VolList, (struct Node *)NewEntry);
				NewEntry->Link.ln_Name	= NewEntry->VolName;
				NewEntry->Link.ln_Type	= Mode;
				NewEntry->DriverTask	= DList->dol_Task;
				VolList->lh_Type++;

				strcpy(NewEntry->VolName, ((char *)BADDR(DList->dol_Name) + 1));
			}
			else
				RetVal	= FALSE;
		}

			// Unlock DOS-List again

		UnLockDosList(Mode|LDF_READ);
	}

		// Now remove devices not being of block mounted type

	if(!IsListEmpty(VolList))
	{
		struct	Process		*MyProc	= (struct Process *)FindTask(NULL);
		struct	VolEntry	*DelEntry;
		char			DevName[134];
		APTR			OldPtr;
		BPTR			TestLock;
		BOOL			RemoveEntry;

		Forbid();
		OldPtr			= MyProc->pr_WindowPtr;
		MyProc->pr_WindowPtr	= (void *)-1;
		Permit();

		NewEntry		= (struct VolEntry *)VolList->lh_Head;

		do
		{
			DelEntry	= NewEntry;
			NewEntry	= (struct VolEntry *)NewEntry->Link.ln_Succ;

			RemoveEntry	= FALSE;

			if(DelEntry->Link.ln_Type == LDF_DEVICES)
			{
				RemoveEntry	= TRUE;

				if(DelEntry->DriverTask)
				{
					strcpy(DevName, DelEntry->VolName);
					strcat(DevName, ":");

					if((TestLock = Lock(DevName, ACCESS_READ)))
					{
						RemoveEntry	= FALSE;
						UnLock(TestLock);
					}
					else if(IoErr() != 209)
						RemoveEntry	= FALSE;
				}

			}

			if(RemoveEntry)
			{
				Remove(DelEntry);
				FreeVecPool(FIconSema, DelEntry);
				VolList->lh_Type--;
			}

		} while(NewEntry->Link.ln_Succ);

		Forbid();
		MyProc->pr_WindowPtr	= OldPtr;
		Permit();
	}


	if(!RetVal)
		DisplayError(ERR_NOTALL, NULL);

	return(RetVal);
}




/**********************************************************************/
/*                        Release Volume-Nodes                        */
/**********************************************************************/
static void FreeDevVolList(struct List *VolList)
{
	struct	Node	*DelNode;

	while((DelNode = RemHead(VolList)))
		FreeVecPool(FIconSema, DelNode);
}






/**********************************************************************/
/*             Sort the complete list of devices/volumes              */
/**********************************************************************/
static void SortList(struct List *VolList, BOOL DisplayType)
{
	UWORD	First, Last;

	if(DisplayType)
	{
		First	= LDF_VOLUMES;
		Last	= LDF_DEVICES;
	}
	else
	{
		First	= LDF_DEVICES;
		Last	= LDF_VOLUMES;
	}

		// Sort partial lists within one list

	if(!IsListEmpty(VolList))
	{
		struct	VolEntry	*ThisEntry	= (struct VolEntry *)VolList->lh_Head;
		UWORD	NumEntries			= VolList->lh_Type;
		UWORD	Left = 0, Right = 0;

			// Find boundaries of first type of entries

		while(ThisEntry->Link.ln_Type == First && NumEntries)
		{
			Right++;
			NumEntries--;
			ThisEntry = (struct VolEntry *)ThisEntry->Link.ln_Succ;
		}

			// Sort`em

		if(Left < Right)
		{
			SortPartialList(VolList, Left, Right);
			Left = Right;
		}

			// Look for second type of entries

		while(ThisEntry->Link.ln_Type == Last && NumEntries)
		{
			Right++;
			NumEntries--;
			ThisEntry = (struct VolEntry *)ThisEntry->Link.ln_Succ;
		}

			// Sort`em

		if(Left < Right)
			SortPartialList(VolList, Left, Right);
	}
}



/**********************************************************************/
/*            Sort partial list, either devices or volumes            */
/**********************************************************************/
static void SortPartialList(struct List *VolList, UWORD Left, UWORD Right)
{
	UWORD	i, j;

		// This is a simply Insertion Sort
		// I don`t think that there will be too many entries,
		// so this algorithm will do it. (IMHO)

	for(i = Left + 1; i < Right; i++)
	{
		struct	VolEntry	Spare, *CheckEntry;

			j = i;

			Spare		= *((struct VolEntry *)GetListEntry(VolList, i));
			CheckEntry	= (struct VolEntry *)GetListEntry(VolList, j - 1);

			while(j > Left && stricmp(CheckEntry->VolName, Spare.VolName) > 0)
			{
				struct	VolEntry	*RightEntry = (struct VolEntry *)CheckEntry->Link.ln_Succ;

				strcpy(RightEntry->VolName, CheckEntry->VolName);
				strcpy(RightEntry->IconName, CheckEntry->IconName);
				RightEntry->Left	= CheckEntry->Left;
				RightEntry->Top		= CheckEntry->Top;
				RightEntry->UseAlt	= CheckEntry->UseAlt;
				RightEntry->IconPos	= CheckEntry->IconPos;
				RightEntry->UseWin	= CheckEntry->UseWin;
				RightEntry->WinX	= CheckEntry->WinX;
				RightEntry->WinY	= CheckEntry->WinY;
				RightEntry->WinWidth	= CheckEntry->WinWidth;
				RightEntry->WinHeight	= CheckEntry->WinHeight;
				RightEntry->UseFlags	= CheckEntry->UseFlags;
				RightEntry->WinFlags	= CheckEntry->WinFlags;


				j--;
				CheckEntry = (struct VolEntry *)CheckEntry->Link.ln_Pred;
			}

			CheckEntry = (struct VolEntry *)GetListEntry(VolList, j);
			strcpy(CheckEntry->VolName, Spare.VolName);
			strcpy(CheckEntry->IconName, Spare.IconName);
			CheckEntry->Left	= Spare.Left;
			CheckEntry->Top		= Spare.Top;
			CheckEntry->UseAlt	= Spare.UseAlt;
			CheckEntry->IconPos	= Spare.IconPos;
			CheckEntry->UseWin	= Spare.UseWin;
			CheckEntry->WinX	= Spare.WinX;
			CheckEntry->WinY	= Spare.WinY;
			CheckEntry->WinWidth	= Spare.WinWidth;
			CheckEntry->WinHeight	= Spare.WinHeight;
			CheckEntry->UseFlags	= Spare.UseFlags;
			CheckEntry->WinFlags	= Spare.WinFlags;
	}
}



/**********************************************************************/
/*                      Get an entry from a list                      */
/**********************************************************************/
static APTR GetListEntry(struct List *List, WORD EntryNum)
{
	struct	Node	*ThisEntry = NULL, *CheckEntry;

		// Search list for entry

	if(!IsListEmpty((struct List *)List) && EntryNum >= 0)
	{
		CheckEntry = List->lh_Head;

		while(CheckEntry->ln_Succ && EntryNum)
		{
			CheckEntry	= CheckEntry->ln_Succ;
			EntryNum--;
		}

		if(!EntryNum)
			ThisEntry	= CheckEntry;
	}

	return(ThisEntry);
}






/**********************************************************************/
/*                Simple pattern match StrCmp function                */
/**********************************************************************/
static BOOL MyStrCmp(char *FromName, char *ToName)
{
	char	UpperFrom[132];
	char	Pattern[270];

	strcpy(UpperFrom, FromName);
	strupr(UpperFrom);

	if(ParsePatternNoCase(UpperFrom, Pattern, 270) != -1)
		return((BOOL)(!MatchPatternNoCase(Pattern, ToName)));

	return((BOOL)(stricmp(FromName, ToName) != 0));
}
