/*************************************************************
This module contains subroutines for nead.c that specifically
deal with the Open file interface. Most of the routines were
taken from Charles Petzold's book "Programming the OS/2
Presentation Manager" and were slightly modified.
Procedures in this file:
OpenFile() Asks user for new file name and opens it
OpenFileProc() Dialog proc that prompts user for file name
FillDirListBox() Fills the directory list box
FillFileListBox() Fills the file list box
**************************************************************/
#include "nead.h"
/************ External GLOBALS *******************************/
extern CHAR szFileName[CCHMAXPATH];
extern CHAR szEAName[MAXEANAME+1];
extern USHORT usRetEAType;
extern BOOL FILE_ISOPEN;
extern BOOL FILE_CHANGED;
extern BOOL COMMAND_LINE_FILE;
extern HHEAP hhp;
extern CHAR *pAlloc,*szEditBuf,*szAscii,*szScratch;
extern HOLDFEA *pHoldFEA;
extern DELETELIST *pDelList;
extern EADATA ConvTable[EATABLESIZE];
/*************************************************************/
/*
* Function name: OpenFile()
*
* Parameters: hwnd which is the current window handle.
* usMode which will attempt to load the file from the command
* line iff usMode == ARGFILE which is set in main(). Otherwise,
* the selector box is brought up for the user to select from.
*
* Returns: TRUE iff a file is open upon exit.
*
* Purpose: This routine handles opening a new file. It will also query the
* user for the disposition of the current file if it has been
* modified before loading the new file.
*
* Usage/Warnings: Routine should be bullet proof as it does its own
* error checking. It assumes that hwnd points to the
* correct window with the name listbox in it.
*
* Calls: WriteEAs(), Free_FEAList()
*/
BOOL OpenFile(HWND hwnd,USHORT usMode)
{
CHAR szOldFile[CCHMAXPATH];
USHORT usRet;
strcpy(szOldFile,szFileName); /* Save name of the currently open file */
if(usMode != ARGFILE) /* It isn't the command line file */
{
if(!WinDlgBox(HWND_DESKTOP, /* Get the file name from the user */
hwnd,
OpenFileProc,
(HMODULE) NULL,
IDD_OPENBOX,
NULL))
{
strcpy(szFileName,szOldFile); /* They canceled, restore old file */
return(FILE_ISOPEN);
}
}
if(FILE_CHANGED) /* Give them a chance to save modifications */
{
usRet=WinMessageBox(HWND_DESKTOP,hwnd,
"The current file has been changed. Do you \
wish to save the changes before proceeding?",
"Warning",0,MB_YESNOCANCEL | MB_ICONQUESTION);
switch(usRet)
{
case MBID_YES:
WriteEAs(hwnd);
break;
case MBID_CANCEL:
return FILE_ISOPEN;
}
}
if(FILE_ISOPEN) /* Free up everything associated with the current file */
{
Free_FEAList(pHoldFEA,pDelList);
FILE_ISOPEN = FALSE;
}
if(QueryEAs(hwnd,szFileName)) /* We were successful */
{
HOLDFEA *pFEA=pHoldFEA;
FILE_ISOPEN = TRUE;
FILE_CHANGED = FALSE;
WinSendDlgItemMsg(hwnd, IDD_LBOX, LM_DELETEALL,0L,0L); /* Fill L-box */
while(pFEA)
{
WinSendDlgItemMsg(hwnd, IDD_LBOX, LM_INSERTITEM,
MPFROM2SHORT(LIT_END,0),
MPFROMP(pFEA->szName));
pFEA = pFEA->next;
}
}
else /* We couldn't query the EAs */
{
*szFileName = '\000';
WinSetDlgItemText(hwnd,IDD_FNAME,szFileName);
return(FILE_ISOPEN = FALSE);
}
WinSetDlgItemText(hwnd,IDD_FNAME,szFileName);
pDelList = NULL;
return(TRUE);
}
/*
* Function name: OpenFileProc()
*
* Parameters: hwnd, msg, mp1, mp2. Standard PM Dialog Proc params.
* Expects no user pointer.
*
* Returns: TRUE if user selects OK, FALSE if Cancel is selected.
*
* Purpose: This proc handles the user interface to select a file name.
* Some elementary checks are done to make sure the filename is
* valid.
*
* Usage/Warnings: The interface is NOT foolproof as it is possible to
* continue with a non-existant file name. Also, users
* are not currently allowed to view/edit the EAs attached
* to a directory.
*
* Calls: FillDirListBox(), FillFileListBox(), ParseFileName()
*/
MRESULT EXPENTRY OpenFileProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
static CHAR szCurrentPath[CCHMAXPATH],szBuffer[CCHMAXPATH];
CHAR szParsedPath[CCHMAXPATH];
SHORT sSelect;
switch(msg)
{
case WM_INITDLG:
FillDirListBox(hwnd,szCurrentPath);
FillFileListBox(hwnd);
WinSendDlgItemMsg(hwnd, IDD_FILEEDIT,EM_SETTEXTLIMIT,
MPFROM2SHORT(260,0),NULL);
return 0L;
case WM_CONTROL:
if(SHORT1FROMMP(mp1) == IDD_DIRLIST || /* An lbox item is selected */
SHORT1FROMMP(mp1) == IDD_FILELIST)
{
sSelect = SHORT1FROMMR( WinSendDlgItemMsg(hwnd, /* Get item->szBuffer */
SHORT1FROMMP(mp1),
LM_QUERYSELECTION, 0L, 0L));
WinSendDlgItemMsg(hwnd, SHORT1FROMMP(mp1),
LM_QUERYITEMTEXT,
MPFROM2SHORT(sSelect, sizeof szBuffer),
MPFROMP(szBuffer));
}
switch(SHORT1FROMMP(mp1))
{
case IDD_DIRLIST: /* Item was in the directory lbox */
switch(SHORT2FROMMP(mp1))
{
case LN_ENTER: /* Go to the select drive/dir */
if(*szBuffer == ' ')
DosSelectDisk(*(szBuffer+1) - '@');
else
DosChDir(szBuffer, 0L);
FillDirListBox(hwnd, szCurrentPath);
FillFileListBox(hwnd);
WinSetDlgItemText(hwnd, IDD_FILEEDIT, "");
return 0L;
}
break;
case IDD_FILELIST: /* Item was in the file lbox */
switch(SHORT2FROMMP(mp1))
{
case LN_SELECT: /* Copy name to entry field */
WinSetDlgItemText(hwnd, IDD_FILEEDIT, szBuffer);
return 0L;
case LN_ENTER: /* Try to query the file */
if(ParseFileName(szFileName, szBuffer) != FILE_VALID)
return 0; /* Some error, don't finish */
WinDismissDlg(hwnd, TRUE);
return 0L;
}
break;
}
break;
case WM_COMMAND:
switch(COMMANDMSG(&msg)->cmd)
{
case DID_OK: /* Try to query file in the entry field */
WinQueryDlgItemText(hwnd, IDD_FILEEDIT,
sizeof szBuffer, szBuffer);
switch(ParseFileName(szParsedPath, szBuffer))
{
case FILE_INVALID: /* Can't open the file */
WinAlarm(HWND_DESKTOP, WA_ERROR);
FillDirListBox(hwnd, szCurrentPath);
FillFileListBox(hwnd);
return 0L;
case FILE_PATH: /* It was an incomplete path name */
strcpy(szCurrentPath,szBuffer);
FillDirListBox(hwnd, szCurrentPath);
FillFileListBox(hwnd);
WinSetDlgItemText(hwnd, IDD_FILEEDIT, "");
return 0L;
case FILE_VALID: /* It was valid */
strcpy(szFileName, szParsedPath);
WinDismissDlg(hwnd, TRUE);
return 0L;
}
break;
case DID_CANCEL:
WinDismissDlg(hwnd, FALSE);
return 0L;
}
break;
}
return WinDefDlgProc(hwnd, msg, mp1, mp2);
}
/*
* Function name: FillDirListBox()
*
* Parameters: hwnd points to the current window handle
* pcCurrentPath points to a buffer which will be filled in
* with the current path.
*
* Returns: VOID
*
* Purpose: This routine is called by OpenFileProc to fill in the directory
* list box
*
* Usage/Warnings: Adequete error checking is NOT done on the return
* values of the system calls. Also, it is remotely
* possible that the calls to add to the list box could fail.
*
* Calls:
*/
VOID FillDirListBox(HWND hwnd, CHAR *pcCurrentPath)
{
static CHAR szDrive [] = " :";
FILEFINDBUF findbuf;
HDIR hDir = 1;
SHORT sDrive;
USHORT usDriveNum, usCurPathLen, usSearchCount = 1;
ULONG ulDriveMap;
DosQCurDisk(&usDriveNum, &ulDriveMap);
*pcCurrentPath = (CHAR)((CHAR) usDriveNum + '@');
*(pcCurrentPath+1) = ':';
*(pcCurrentPath+2) = '\\';
usCurPathLen = CCHMAXPATH;
DosQCurDir(0, pcCurrentPath + 3, &usCurPathLen);
WinSetDlgItemText(hwnd, IDD_PATH, pcCurrentPath);
WinSendDlgItemMsg(hwnd, IDD_DIRLIST, LM_DELETEALL, NULL, NULL);
for(sDrive = ('A'-'A'); sDrive <= ('Z'-'A'); sDrive++)
{
if(ulDriveMap & (1L << sDrive))
{
*(szDrive+1) = (CHAR)((CHAR) sDrive + 'A');
WinSendDlgItemMsg(hwnd, IDD_DIRLIST, LM_INSERTITEM,
MPFROM2SHORT(LIT_END, 0),
MPFROMP(szDrive));
}
}
DosFindFirst("*", &hDir, FILE_DIRECTORY | FILE_ALL, &findbuf,
sizeof findbuf, &usSearchCount, 0L);
while(usSearchCount)
{
if((findbuf.attrFile & FILE_DIRECTORY) &&
(findbuf.achName[0] != '.' || findbuf.achName[1]))
WinSendDlgItemMsg(hwnd, IDD_DIRLIST, LM_INSERTITEM,
MPFROM2SHORT(LIT_SORTASCENDING, 0),
MPFROMP(findbuf.achName));
if(DosFindNext(hDir, &findbuf, sizeof findbuf, &usSearchCount))
break;
}
}
/* This routine is called by OpenFileProc to fill the file list box */
/*
* Function name: FillFileListBox()
*
* Parameters: hwnd points to the current window handle
*
* Returns: VOID
*
* Purpose: This routine is called by OpenFileProc to fill in the file
* list box with files in the current directory.
*
* Usage/Warnings: Adequete error checking is NOT done on the return
* values of the system calls. Also, it is remotely
* possible that the calls to add to the list box could fail.
*
* Calls:
*/
VOID FillFileListBox(HWND hwnd)
{
FILEFINDBUF findbuf;
HDIR hDir = 1;
USHORT usSearchCount = 1; /* Read 1 entry at a time */
WinSendDlgItemMsg(hwnd, IDD_FILELIST, LM_DELETEALL, NULL, NULL);
DosFindFirst("*", &hDir, FILE_ALL, &findbuf, sizeof findbuf,
&usSearchCount, 0L);
while(usSearchCount)
{
WinSendDlgItemMsg(hwnd, IDD_FILELIST, LM_INSERTITEM,
MPFROM2SHORT(LIT_SORTASCENDING, 0),
MPFROMP(findbuf.achName));
if(DosFindNext(hDir, &findbuf, sizeof findbuf, &usSearchCount))
break;
}
}
/*
* Function name: ParseFileName()
*
* Parameters: pcOut points to a buffer for the return file specification.
* pcIn points to the buffer containing the raw input spec.
*
* Returns: FILE_INVALID if pcIn had invalid drive or no directory
* FILE_PATH if pcIn was empty or had just a path/no file name.
* FILE_VALID if pcIn point to good file.
*
* Purpose: This routine changes drive and directory as per pcIn string.
*
* Usage/Warnings: Note that pcOut is only valid if FILE_VALID is returned.
* in place of strupr(), a codepage should be fetched and
* DosCaseMap() should be used to allow for extended chars.
* This routine could use some cleanup work.
*
* Calls:
*/
SHORT ParseFileName(CHAR *pcOut, CHAR *pcIn)
{
CHAR *pcLastSlash, *pcFileOnly ;
ULONG ulDriveMap ;
USHORT usDriveNum, usDirLen = CCHMAXPATH;
strupr(pcIn); /* Does NOT handle extended chars, should use DosCaseMap */
if(*pcIn == '\000') /* If string is empty, return FILE_PATH */
return FILE_PATH;
/* Get drive from input string or use current drive */
if(*(pcIn+1) == ':') /* Yup, they specified a drive */
{
if(DosSelectDisk(*pcIn - '@')) /* Change to selected drive */
return FILE_INVALID;
pcIn += 2;
}
DosQCurDisk(&usDriveNum, &ulDriveMap); /* Get current drive */
*pcOut++ = (CHAR)((CHAR) usDriveNum + '@'); /* Build drive letter */
*pcOut++ = ':';
*pcOut++ = '\\';
if(*pcIn == '\000') /* If rest of the string is empty, return FILE_PATH */
return FILE_PATH;
/* Search for the last backslash. If none, it could be a directory. */
if(!(pcLastSlash = strrchr(pcIn, '\\'))) /* No slashes? */
{
if(!DosChDir(pcIn, 0L))
return FILE_PATH; /* It was a directory */
DosQCurDir(0, pcOut, &usDirLen); /* Get current dir & attach input fn */
if(*(pcOut+strlen(pcOut)-1) != '\\')
strcat(pcOut++, "\\");
strcat(pcOut, pcIn);
return FILE_VALID;
}
/* If the only backslash is at the beginning, change to root */
if(pcIn == pcLastSlash)
{
DosChDir("\\", 0L);
if(*(pcIn+1) == '\000')
return FILE_PATH;
strcpy(pcOut, pcIn+1);
return FILE_VALID;
}
/* Attempt to change directory -- Get current dir if OK */
*pcLastSlash = 0;
if(DosChDir(pcIn, 0L))
return FILE_INVALID;
DosQCurDir(0, pcOut, &usDirLen);
/* Append input filename if any */
pcFileOnly = pcLastSlash+1;
if(*pcFileOnly == '\000')
return FILE_PATH;
if(*(pcOut+strlen(pcOut)-1) != '\\')
strcat(pcOut++, "\\");
strcat(pcOut, pcFileOnly);
return FILE_VALID;
}