/*
**	Command & Conquer Red Alert(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***************************************************************************
 **   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
 ***************************************************************************
 *                                                                         *
 *                 Project Name : Westwood Library                         *
 *                                                                         *
 *                    File Name : FINDFILE.C                               *
 *                                                                         *
 *                   Programmer : Joe L. Bostic                            *
 *                                                                         *
 *                   Start Date : August 21, 1991                          *
 *                                                                         *
 *                  Last Update : September 29, 1993   [SKB]               *
 *                                                                         *
 *-------------------------------------------------------------------------*
 * Functions:                                                              *
 *   Find_File_Index -- Finds the FileTable index number for a given file. *
 *   Find_File -- Checks if a file is immediatly available.                *
 *   Get_FileData -- Gets a pointer back to the correct file.              *
 *   Find_File -- Checks if a file is immediatly available.                *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

/*=========================================================================*/
/* The following PRIVATE functions are in this file:                       */
/*=========================================================================*/



/*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/

#ifndef WWSTD_H
#include "wwstd.h"
#endif	   

#ifndef _FILE_H
#include "_file.h"
#endif

#include <direct.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
#include <sys\stat.h>



/***************************************************************************
 * FIND_FILE -- Checks if a file is immediatly available.                  *
 *                                                                         *
 *    Use this function to determine if a file is immediatly available.    *
 *    This routine will NOT request for the proper disk to be inserted     *
 *    if the file could not be found.  Use File_Exists for that feature.   *
 *    The Westwood file I/O system does NOT have to be initialized as      *
 *    a prerequisit to using this function.                                *
 *                                                                         *
 * INPUT:   file_name   -- Name of the file to check.                      *
 *                                                                         *
 * OUTPUT:  Returns the disk number that the file exits on (A=1, B=2, etc) *
 *                                                                         *
 * WARNINGS:   This sets the current drive to the drive that contains the  *
 *             specified file (if it is found).                            *
 *                                                                         *
 * HISTORY:                                                                *
 *   11/14/1991 JLB : Created.                                             *
 *   03/14/1992 JLB : Modified for Amiga compatability.                    *
 *   01/11/1993 SKB : Modified for CD-ROM searches.                        *
 *=========================================================================*/
int cdecl Find_File(char const *file_name)
{
	FileDataType	*filedata = NULL;
	WORD				index;					// File index (if any).
	WORD				disk;						// Disk number of file (if in filetable).
	
	/*
	**	If the filename is invalid then it errors out as if the file wasn't
	**	found (naturally).
	*/
	if (!file_name) return(FALSE);

	/*
	**	Determine if the file has a file table entry.  If it does, then
	**	special checks and processing must occur.
	** Also, if it is in memory, return with it.
	*/
	index = Find_File_Index(file_name);
	filedata = &FileDataPtr[index];

	if (index != ERROR) {

		// If the file is currently cached, return TRUE that it was found.
		if (filedata->Ptr) {
			return (TRUE);
		}
	}


	/*
	**	Always check the current directory for the file.  Only if it can't
	**	be found are furthur measures required.
	*/
	DiskNumber = ERROR;		// This indicates file exists in current directory.

		
 	#if (LIB_CDROM)
		ibm_setdisk(*StartPath - 'A');
 	#endif

	/*
	**	Check the current directory by attempting to open with READ access.
	*/
	{
		WORD	handle;
		
		CallingDOSInt++;
		handle = open(file_name, O_RDONLY | O_BINARY, S_IREAD);
		CallingDOSInt--;
		if (handle != ERROR) 
		{
		   //	WORD	d;
			unsigned d ;

			CallingDOSInt++;
			close(handle);
			// d = getdisk();
			_dos_getdrive ( & d) ;
			CallingDOSInt--;
			return(d);
		}
	}
	
		
	if (index != ERROR) {

		disk = filedata->Disk;
		/*
		**	If the file is in a packed file, then search for the packed file
		**	instead of the specified one.
		*/
		if (index != ERROR && (filedata->Flag & FILEF_PACKED)) {
			filedata = &FileDataPtr[disk];
			return (Find_File(filedata->Name));
		}

	}

	/*
	**	It could not be found on the current drive, so search the other
	**	drives if allowed to do so.
	*/
	if (!MultiDriveSearch) {
		return(FALSE);
	}

#if (LIB_CDROM)
	// If we were unable to find the file on the hard drive, change
	// drives to the CD rom drive and see if it is there.
	ibm_setdisk(*DataPath - 'A');
 
	{
		WORD	handle;
		
		Hard_Error_Occured = 0;

	  	handle = Open_File_With_Recovery( file_name, MODE_OLDFILE );

		if (handle != FILEOPENERROR) {
			FILECLOSE(handle);
			return(ibm_getdisk() + 1);
		}
	}

	ibm_setdisk(*StartPath - 'A');
	return (FALSE);
#else

	{
		WORD	start_drive;	// Original current drive number.

		/*
		**	Record the current drive for restoring later in case of failure.
		*/
		CallingDOSInt++;
		start_drive = getdisk();
		CallingDOSInt--;

		/*
		**	Sweep backward from the last real drive to the first, looking for the
		**	file on each in turn.
		*/
		for (index = MaxDevice; index != -1; index--) {
			if (Is_Device_Real(index)) {
				CallingDOSInt++;
			 	setdisk(index);
				CallingDOSInt--;

				{
					WORD	handle;

					CallingDOSInt++;
					handle = open(file_name, O_RDONLY | O_BINARY, S_IREAD);
					CallingDOSInt--;
					if (handle != ERROR) {
						CallingDOSInt++;
						close(handle);
						CallingDOSInt--;
						DiskNumber = index+1;
						return (DiskNumber);
					}
				}
			}
		}
		CallingDOSInt++;
		setdisk(start_drive);
		CallingDOSInt--;
	}
	
	return(FALSE);
#endif

}


/***************************************************************************
 * FIND_FILE_INDEX -- Finds the FileTable index number for a given file.   *
 *                                                                         *
 *    This function searches the FileTable and returns with the index of   *
 *    the matching file.  If the file doesn't exist in the table, then     *
 *    ERROR is returned.  It does not care about case.                     *
 *                                                                         *
 * INPUT:   filename -- Pointer to the filename to check.                  *
 *                                                                         *
 * OUTPUT:  Returns with the index into the FileTable.  If the file does   *
 *          not exist in the file table, then ERROR is returned.           *
 *                                                                         *
 * WARNINGS:   none                                                        *
 *                                                                         *
 * HISTORY:                                                                *
 *   11/09/1991 JLB : Created.                                             *
 *   06/11/1993 JLB : Sorts and binary searches the file table.            *
 *=========================================================================*/
PRIVATE int Comp_Func(const void *p1, const void *p2)
{
	return(strcmp((char *) ((FileDataType*)p1)->Name, (char *) ((FileDataType*)p2)->Name));
}
WORD cdecl Find_File_Index(BYTE const *filename)
{
	FileDataType	*filedata;			// File entry pointer.
	FileDataType	key;					// Working file data type var.

	/*
	**	Perform a binary search on the presorted filetable.
	*/
	if (filename) {

		filedata = NULL;
		key.Name = (BYTE *) strupr((char *)filename);
		if (strstr((char *)key.Name, (char *)".PAK")) {
			
			/*
			** If the FileData table was not loaded from the disk then the PAK files are
			** not sorted so Perform a linear search for the pak files.
			** Otherwise the files are sorted so speed things up by doing a bsearch.
			*/
			if (FileData == FileDataPtr) {
				filedata = (FileDataType *) lfind(&key, FileDataPtr, (size_t *) &NumPAKFiles, sizeof(FileDataType), Comp_Func);
			}
			else {
				filedata = (FileDataType *)bsearch(&key, FileDataPtr, NumPAKFiles, sizeof(FileDataType), Comp_Func);
			}

		} else {
				
			/*
			**	Perform a binary search for the regular files.
			*/
			filedata = (FileDataType *)bsearch(&key, &FileDataPtr[NumPAKFiles], NumFiles, sizeof(FileDataType), Comp_Func);
		}

		// Return the element in the array if file was found in table.
		if (filedata) {
			return (filedata - FileDataPtr);
			//return ((WORD)((((LONG)filedata) - ((LONG)FileDataPtr)) / sizeof(FileDataType)));
		}
	}
	return(ERROR);
}




