/******************************************************************************
* Procedures to get/set current working directory and get file names in a     *
* given directory.							      *
*									      *
*				Ver 0.1		Gershon Elber	      Oct. 89 *
******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <dir.h>
#include <dos.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <float.h>
#include "Program.h"
#include "Director.h"
#include "Ctrl-Brk.h"
#include "EERedraw.h"

#ifndef LINE_LEN
#define LINE_LEN 128
#endif

static void DosReleaseResources(void);
static void DosReclaimResources(void);

/******************************************************************************
* Procedure to create a file name list of the files in the given directory    *
* that match the given mask.						      *
* Returns an array of names allocated dynamically, or NULL if no match.	      *
******************************************************************************/
FileNameType *GetFileNamesDir(char *Mask, char *Directory, int *NumOfFiles)
{
    int FileNamesArraySize,
	FileNameCount = 0;
    char FullName[FULL_PATH_LEN];
    struct ffblk ffblk;
    FileNameType *FileNames, *TempFileNames;

    FileNamesArraySize = 10;	   /* Start with 10 and realloc as required. */
    FileNames = (FileNameType *)
	MyMalloc(sizeof(FileNameType) * FileNamesArraySize);

    if (Mask == NULL) Mask = DEFAULT_FILE_TO_DIR;
    if (Directory == NULL) Directory = DEFAULT_DIR_TO_DIR;
    sprintf(FullName, "%s\\%s", Directory, Mask);

    if (!findfirst(FullName, &ffblk, 0))
    {
	do {
	    if (FileNameCount >= FileNamesArraySize) {
		/* Need to realloc the array: */
		TempFileNames = (FileNameType *)
		    MyMalloc(sizeof(FileNameType) * (FileNamesArraySize << 1));
		GEN_COPY(TempFileNames, FileNames,
			 sizeof(FileNameType) * FileNamesArraySize);
		MyFree((VoidPtr) FileNames);
		FileNames = TempFileNames;
		FileNamesArraySize <<= 1;
	    }
	    strncpy(FileNames[FileNameCount++], ffblk.ff_name,
							FILE_NAME_LEN - 1);
	}
	while (!findnext(&ffblk));

	*NumOfFiles = FileNameCount;
	return FileNames;
    }
    else {
	MyFree((VoidPtr) FileNames);

	*NumOfFiles = 0;
	return NULL;
    }
}

/*****************************************************************************
*   Routine to get current directory					     *
*****************************************************************************/
char *GetDir(void)
{
    static char cwd[FULL_PATH_LEN];

    return getcwd(cwd, FULL_PATH_LEN - 1);
}

/*****************************************************************************
*   Routine to change current directory					     *
*****************************************************************************/
ChDirErrorType ChangeDir(char *Directory)
{
    char *cwd, *Path;

    if (Directory[1] == ':')
	Path = &Directory[2];			/* Path points on path only. */
    else
        Path = Directory;

    cwd = GetDir();

    if (strlen(Path) != 0 && chdir(Directory))
	return CD_NO_SUCH_DIR;
    else if (Directory[1] == ':') {
	if (islower(Directory[0])) Directory[0] = toupper(Directory[0]);
	setdisk(Directory[0] - 'A');		    /* Move to the new disk. */
	if (getdisk() != Directory[0] - 'A') return CD_NO_SUCH_DISK;
    }

    if (getcwd(Directory, LINE_LEN-1) == NULL) { /* Test if directory valid! */
	/* Restore old working directory: */
	if (strlen(&cwd[2]) != 0) chdir(cwd); /* If directory is not root... */
	if (islower(cwd[0])) cwd[0] = toupper(cwd[0]);
	setdisk(cwd[0] - 'A');		       /* Move to the original disk. */
	return CD_INVALID_DIR;
    }

    return CD_OK;
}

/******************************************************************************
* Procedure to execute the command processor as defined by COMSPEC	      *
* environment variable and enter it as a child process.			      *
******************************************************************************/
void DosSystem(void)
{
    char *FullPath,
        *Err = NULL;
    IntrCursorShapeStruct Cursor;

    Cursor.CursorType = INTR_CURSOR_ARROW;

    if ((FullPath = getenv("COMSPEC")) == NULL) {
	IntrQueryContinue("No COMSPEC environment variable, cannt escape to system",
                    	  EEPopUpFrameColor, EEPopUpBackColor,
                          EEPopUpForeColor, EEPopUpXorColor,
                          EEWindowsFrameWidth, &Cursor, INTR_WNDW_PLACE_CENTER);
	return;
    }

    DosReleaseResources();

    if (spawnl(P_WAIT, FullPath, FullPath, NULL) == -1) {	   /* Do it! */
	/* Error had occured - trace it: */
	switch (errno) {
	    case ENOENT:
		Err = "No command processor found in COMSPEC path specified.";
		break;
	    case ENOMEM:
		Err = "Not enough memory to escape to system.";
		break;
	    default:
		Err = "Undefined error in attempt to escape to system.";
	}
    }

    DosReclaimResources();

    if (Err != NULL) IntrQueryContinue(Err,
		                       EEPopUpFrameColor, EEPopUpBackColor,
		                       EEPopUpForeColor, EEPopUpXorColor,
                                       EEWindowsFrameWidth, &Cursor,
                                       INTR_WNDW_PLACE_CENTER);
}

/******************************************************************************
* Procedure to release all resources used by the program.		      *
******************************************************************************/
static void DosReleaseResources(void)
{
    IntrClose();				/* Close the graphic driver. */

    RestoreCtrlBrk();			      /* Restore ctrl-brk interrupt. */
}

/******************************************************************************
* Procedure to reclaim all resources used by the program.		      *
******************************************************************************/
static void DosReclaimResources(void)
{
    _fpreset();	       /* Reset the floating point package to a known state. */

    IntrInit(); 			     /* Initiate the graphic driver. */

    IntrWndwRedrawAll();
}
