2020-09-30 17:12:29 +02:00

386 lines
7.8 KiB
C++

// FM.CPP Copyright (C) Microsoft Corporation 1995, All Rights reserved.
#include "stdafx.h"
#include "hccom.h"
#define SzEnd(x) (x + strlen(x))
/***************************************************************************
*
- Name: FmNewTemp
-
* Purpose: Create a unique FM for a temporary file
*
* Arguments: none
*
* Returns: the new FM, or fmNil if failure
*
* Globals Used:
*
* +++
*
* Notes:
*
***************************************************************************/
const char txtTmpName[] = "~hc";
FM STDCALL FmNewTemp(void)
{
char szTmpName[MAX_PATH];
strcpy(szTmpName, GetTmpDirectory());
GetTempFileName(szTmpName, txtTmpName, 0, szTmpName);
#ifdef _DEBUG
DBWIN("Creating a temporary file");
#endif
return FmNew(szTmpName);
}
/***************************************************************************
*
- Name: FmNew
-
* Purpose: Allocate and initialize a new FM
*
* Arguments: sz - filename string
*
* Returns: FM (handle to fully canonicalized filename)
*
* Globals Used:
*
* +++
*
* Notes:
*
***************************************************************************/
FM STDCALL FmNew(PCSTR psz)
{
char szFullPath[MAX_PATH];
FM fm;
PSTR pszFileName;
if (IsEmptyString(psz))
return NULL;
// Canonicalize filename
if (GetFullPathName(psz, sizeof(szFullPath), szFullPath, &pszFileName) == 0) {
SetLastError((DWORD) RC_Invalid | SETERROR_MASK);
return NULL;
}
else {
fm = lcStrDup(szFullPath);
/*
* Convert to upper case to make it less likely that two FMs will
* contain different strings yet refer to the same file.
*/
CharUpper(fm);
}
return fm;
}
/***************************************************************************
*
- SzPartsFm
-
* Purpose:
* Extract a string from an FM
*
* Arguments:
* FM - the File Moniker you'll be extracting the string from
* PSTR szDest - destination string
* INT iPart - the parts of the full pathname you want
*
* Returns:
* szDest, or NULL if error (?)
*
* Globals Used:
*
* +++
*
* Notes:
*
***************************************************************************/
void STDCALL SzPartsFm(FM fm, PSTR pszDest, int iPart)
{
int iDrive, iDir, iBase, iExt;
if (!fm || pszDest == NULL) {
SetLastError((DWORD) RC_BadArg | SETERROR_MASK);
return;
}
// special case so we don't waste effort
if (iPart == PARTALL) {
strcpy(pszDest, fm);
return;
}
SnoopPath(fm, &iDrive, &iDir, &iBase, &iExt);
*pszDest = '\0';
if (iPart & PARTDRIVE) {
strcat(pszDest, fm + iDrive);
}
if (iPart & PARTDIR) {
strcat(pszDest, fm + iDir);
}
if (iPart & PARTBASE) {
strcat(pszDest, fm + iBase);
}
ASSERT(!(iPart & PARTEXT));
}
/***************************************************************************
*
- Name: SnoopPath()
-
* Purpose:
* Looks through a string for the various components of a file name and
* returns the offsets into the string where each part starts.
*
* Arguments:
* sz - string to snoop
* *iDrive - offset for the drive specification if present
* *iDir - offset for the directory path if present
* *iBase - offset to the filename if present
* *iExt - offset to the extension (including dot) if present
*
* Returns:
* sets the index parameters for each respective part. the index is set
* to point to the end of the string if the part is not present (thus
* making it point to a null string).
*
*
* +++
*
* Notes:
*
***************************************************************************/
void STDCALL SnoopPath(PCSTR szFile, int *pDrive, int *pDirPos,
int *pBasePos, int *pExtPos)
{
int i;
int cb = strlen(szFile);
BOOL fDir = FALSE;
*pDrive = *pExtPos = cb;
*pDirPos = *pBasePos = 0;
for (i = 0; szFile[i]; i++) {
switch (szFile[i]) {
case ':':
*pDrive = 0;
*pDirPos = i + 1;
*pBasePos = i + 1;
break;
case '/':
case '\\':
fDir = TRUE;
*pBasePos = i + 1;
*pExtPos = cb;
break;
case '.':
if (szFile[i + 1] != '.')
*pExtPos = i;
break;
default:
while(IsDBCSLeadByte(szFile[i]))
i += 2;
break;
}
}
if (!fDir)
*pDirPos = i;
}
/***************************************************************************
*
- Name: FmNewSzDir
-
* Purpose: Create an FM describing the file "sz" in the directory "dir"
* If sz is a simple filename the FM locates the file in the
* directory specified. If there is a drive or a rooted path
* in the filename the directory parameter is ignored.
* Relative paths are allowed and will reference off the dir
* parameter or the default (current) directory as appropriate.
*
* This does not create a file or expect one to exist at the
* final destination (that's what FmNewExistSzDir is for), all
* wind up with is a cookie to a fully qualified path name.
*
* Arguments: sz - filename ("File.ext"),
* or partial pathname ("Dir\File.ext"),
* or current directory ("c:File.ext"),
* or full pathname ("C:\Dir\Dir\File.ext")
* dir - DIR_CURRENT et al.
*
* Returns: the new FM, or fmNil if error
* sz is unchanged
*
* Globals Used:
*
* +++
*
* Notes:
*
***************************************************************************/
FM STDCALL FmNewSzDir(PCSTR szFile, DIR dir)
{
int iDrive, iDir, iBase, iExt;
int cb;
if (IsEmptyString(szFile)) {
SetLastError((DWORD) RC_BadArg | SETERROR_MASK);
return NULL;
}
cb = strlen(szFile);
SnoopPath(szFile, &iDrive, &iDir, &iBase, &iExt);
if (!szFile[iBase]) { // no name
SetLastError((DWORD) RC_BadArg | SETERROR_MASK);
return NULL;
}
else if (szFile[iDrive] || szFile[iDir] == '\\' ||
szFile[iDir] == '/' || szFile[iDir] == '.') {
/*
* there's a drive or root slash so we have an implicit directory
* spec and we can ignore the directory parameter and use what was
* passed.
*/
return FmNew(szFile);
}
else {
/*
* dir & (dir-1) checks to make sure there is only one bit set which
* is followed by a check to make sure that it is also a permitted bit
*/
CHAR szBuf[MAX_PATH];
ASSERT(((dir & (dir - 1)) == 0) &&
(dir &
(DIR_CURRENT | DIR_BOOKMARK | DIR_ANNOTATE | DIR_TEMP)));
if (SzGetDir(dir, szBuf) == NULL)
return NULL;
strcat(szBuf, szFile + iBase);
return FmNew(szBuf);
}
}
/***************************************************************************
*
- Name: SzGetDir
-
* Purpose: returns the rooted path of a DIR
*
* Arguments: dir - DIR (must be one field only, and must be an actual dir -
* not DIR_PATH)
* sz - buffer for storage (should be at least MAX_PATH)
*
* Returns: sz - fine
* NULL - OS Error (check GetLastError)
*
* Globals Used:
*
* +++
*
***************************************************************************/
PSTR STDCALL SzGetDir(DIR dir, PSTR sz)
{
int i=0;
PSTR psz;
ASSERT(sz);
switch (dir) {
case DIR_CURRENT:
GetCurrentDirectory(MAX_PATH, sz);
break;
case DIR_BOOKMARK:
case DIR_ANNOTATE:
GetWindowsDirectory(sz, MAX_PATH);
break;
default:
SetLastError((DWORD) RC_BadArg | SETERROR_MASK);
sz = NULL;
break;
}
if (sz != NULL) {
ASSERT(*sz);
psz = SzEnd(sz) - 1;
if (psz < sz)
return sz;
// Make sure that the string ends with a slash.
PSTR pszTmp = sz;
while (pszTmp < psz) {
if (IsDBCSLeadByte(*pszTmp))
pszTmp += 2;
pszTmp++;
}
if (*pszTmp != '\\' && *pszTmp != '/') {
pszTmp[1] = '\\';
pszTmp[2] = '\0';
}
ASSERT(strlen(sz) < MAX_PATH);
}
return sz;
}
/***************************************************************************
FUNCTION: RemoveFM
PURPOSE: Same as DisposeFm, but this one also zero's the handle.
PARAMETERS:
pfm
RETURNS:
COMMENTS:
MODIFICATION DATES:
25-Oct-1993 [ralphw]
***************************************************************************/
void STDCALL RemoveFM(FM* pfm)
{
if (*pfm) {
lcFree((void*) *pfm);
*pfm = NULL;
}
}