Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1079 lines
29 KiB

//+-------------------------------------------------------------------
//
// File: log.cxx
//
// Contents: The code for the logging servers client logging methods
//
// Functions: Log::Log()
// Log::~Log()
// Log::Info(inc, char *[])
// Log::WriteData(PCHAR)
//
// History: 24-Sep-90 DaveWi Initial Coding
// 11-Mar-94 DaveY Miniature Log.
// 10-Aug-95 ChrisAB Changed fopen()s to _fsopens() for
// proper chicago operation
//
//--------------------------------------------------------------------
#include <comtpch.hxx>
#pragma hdrstop
extern "C"
{
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <direct.h>
#include <share.h>
}
#include "log.hxx"
#include "log.h"
#define CCH_MAX_CHARS 1024
// Set up a table of the status text values
const char * aStatus[] = { LOG_PASS_TXT,
LOG_FAIL_TXT,
LOG_WARN_TXT,
LOG_ABORT_TXT,
LOG_INFO_TXT,
LOG_START_TXT,
LOG_DONE_TXT };
#ifdef WIN16
#define OutputDebugStringA OutputDebugString
#endif
//+-------------------------------------------------------------------
//
// Member: Log::Log(int, char *[], DWORD)
//
// Synopsis: Log constructor with command line data given
//
// Arguments: [argc] - Argument count
// [argv] - Argument array
// [fUseUnicode] - whether we should use WCHARs
//
// Returns: Results from Info()
//
// History: ??-???-?? ???????? Created
// Jun-11-92 DonCl added line to zero out LogStats struct
//
//--------------------------------------------------------------------
Log :: Log(int argc, char *argv[], DWORD dwCharType) :
fInfoSet(FALSE),
ulLastError(ERROR_SUCCESS)
{
#if defined (_WIN32)
//
// Check the result of the CMutex Contructor and continue if
// it succeeded
//
ulLastError = hMtxSerialize.QueryError();
if (ulLastError == ERROR_SUCCESS)
{
ulLastError = Info(argc, argv);
}
#else
ulLastError = Info(argc, argv);
#endif
}
//+-------------------------------------------------------------------
//
// Member: Log::Log(PCHAR, PCHAR, PCHAR, PCHAR, PCHAR)
//
// Synopsis: Log constructor with internal data given
//
// Arguments: [pszSrvr] - Name of logging server
// [pszTest] - Name of this test
// [pszName] - Name of test runner
// [pszSubPath] - Users log file qualifer
// [pszObject] - Name of invoking object
//
// Returns:
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// Jun-11-92 DonCl added line to zero out LogStats struct
//
// BUGBUG wszName unused - left until all components can co-ordinate
// with this. SarahJ
//--------------------------------------------------------------------
Log :: Log(PCHAR pszSrvr,
PCHAR pszTest,
PCHAR pszName,
PCHAR pszSubPath,
PCHAR pszObject) : ulLastError(ERROR_SUCCESS)
{
#if defined (_WIN32)
//
// Check the result of the CMutex Contructor and continue if
// it succeeded
//
ulLastError = hMtxSerialize.QueryError();
if (ulLastError != ERROR_SUCCESS)
{
return;
}
#endif
InitLogging();
// Print warning if server name given
/* BUGBUG Need to restore this once remote server is supported.
if(NULL != pszSrvr)
{
fprintf(stderr, "Remote server not supported with this version of "
"log.lib. Continuing.\n");
}
*/
ulLastError = SetInfo(NULL, pszTest, pszSubPath, pszObject);
if(ulLastError == ERROR_SUCCESS)
{
ulLastError = LogOpen();
if(ulLastError == ERROR_SUCCESS)
{
WriteData("\n*LOG_START*-%s", pszShortLogFileName);
}
}
}
//+-------------------------------------------------------------------
//
// Member: Log::~Log()
//
// Synopsis: Destroy the Log Object
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
Log :: ~Log()
{
if(fInfoSet != FALSE)
{
if(WriteData("\n*LOG_DONE*") != ERROR_SUCCESS)
{
LogPrintf(stderr, "ERROR: Failed to log \"%s\" status\n",
LOG_DONE_TXT);
}
}
SetLoggingDir((PCHAR) NULL);
SetMachineName((PCHAR) NULL);
SetObjectName((PCHAR) NULL);
SetTestName((PCHAR) NULL);
SetPath((PCHAR) NULL);
SetStatus((PCHAR) NULL);
SetLogFileName((PCHAR) NULL);
SetShortLogFileName((PCHAR) NULL);
CloseLogFile();
}
//+-------------------------------------------------------------------
//
// Member: Log::Info(int, char *[])
//
// Synopsis: Parse the command line and set the appropriate member variables
//
// Arguments: [argc] - Argument count
// [argv] - Argument vector
//
// Returns:
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// 30-Oct-92 SarahJ Updated parms to SetInfo
//
//--------------------------------------------------------------------
ULONG Log :: Info(int argc, char *argv[])
{
USHORT usNdx; // Index into cmnd line args
PCHAR pszTest = NULL; // Name of this test
PCHAR pszSubPath = NULL; // Users log file qualifer
PCHAR pszObject = NULL; // Name of invoking object
PCHAR pch; // Temporary pointer into a string
InitLogging();
// All the argv processing is still done in CHARs
if(ulLastError == ERROR_SUCCESS)
{
//
// For every command line switch, check its validity and parse its
// value. This version allows / or - for switches. If there are
// no command line switches, this loop is skipped. This is for the
// case when Log() is called with no messages.
//
for(usNdx = 1; usNdx < (unsigned short) argc; ++usNdx)
{
char *szArg = argv[ usNdx];
pch = szArg;
// check for / -
if(*szArg == '/' || *szArg == '-')
{
register int i = 1;
pch++;
//
// Check if next char is m, ie handed down from manager code.
// If so skip m
//
if (*pch == 'm' || *pch == 'M')
{
pch++;
i++;
}
++pch; // Skip next char and check for :
if(*pch++ == ':')
{
switch(toupper(szArg[i]))
{
case 'O': // Object name found
pszObject = (PCHAR)pch;
break;
case 'P': // Directory Path switch found
pszSubPath = (PCHAR)pch;
break;
case 'L': // Logging server name found
// BUGBUG We don't want this message spit to debugger
// all the time.
// BUGBUG OutputDebugStringA("Logging server not supported with "
// BUGBUG "this version of log.lib. Continuing.\n");
break;
case 'T': // Test name found
pszTest = (PCHAR)pch;
break;
default: // Skip this unknown argument
break;
}
}
}
}
// If no test name was given, set pszTest to the apps base name.
char szName[_MAX_FNAME];
if(pszTest == NULL || *pszTest == NULLTERM)
{
GetBaseFilename(argv[0], szName);
pszTest = szName;
}
}
ulLastError = SetInfo(NULL, pszTest, pszSubPath, pszObject);
// This was not here before, but it seems the log should be opened by now
if(ERROR_SUCCESS == ulLastError)
{
ulLastError = LogOpen() || WriteData("\n*LOG_START*-%s", pszShortLogFileName);
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: Log::WriteData(PCHAR, ...)
//
// Synopsis: Write a string to the Log file.
//
// Arguments: [pszFormat] - a printf-like format string
// [...] - The data to print out.
//
// Returns: ERROR_SUCCESS if successful
// Any error code from Log::SetStrData() or Log::LogData
// or CTCLock::QueryError()
//
// Modifies: ulLastError
//
// History: ??-???-?? ???????? Created
// 3-Jul-92 DeanE Modified to call WriteDataList
//
//--------------------------------------------------------------------
ULONG Log :: WriteData(PCHAR psz, ...)
{
CHAR szBuffer[CCH_MAX_CHARS];
va_list varArgs;
#ifndef WIN16
CTCLock clMemLock (hMtxSerialize); // Serialize access to this object
ULONG ulErr = clMemLock.QueryError();
if (ulErr != NO_ERROR)
{
return ulErr;
}
#endif
szBuffer[0] = '\0';
szBuffer[CCH_MAX_CHARS-1] = '\0';
if ((psz != NULL) && (pfLog != NULL))
{
// Print the caller's string to a buffer
va_start(varArgs, psz);
_vsnprintf(szBuffer, CCH_MAX_CHARS-1, psz, varArgs);
va_end(varArgs);
int iRet = fprintf(pfLog, "%s\n", szBuffer);
if (iRet < 0)
{
OutputDebugStringA("CTLOG::Failed to log data string : ");
OutputDebugStringA(szBuffer);
OutputDebugStringA("\n");
}
else
{
fflush(pfLog);
}
}
return(ERROR_SUCCESS);
}
//+-------------------------------------------------------------------
//
// Member: Log::WriteData2(PCHAR)
//
// Synopsis: Write a string to the Log file.
//
// Arguments: [psz] - string to print out
//
// Returns: ERROR_SUCCESS if successful
// Any error code from Log::SetStrData() or Log::LogData
// or CTCLock::QueryError()
//
// Modifies: ulLastError
//
// History: 3-Jul-92 DeanE Modified to call WriteDataList
//
//--------------------------------------------------------------------
ULONG Log :: WriteData2(PCHAR psz)
{
#ifndef WIN16
CTCLock clMemLock (hMtxSerialize); // Serialize access to this object
ULONG ulErr = clMemLock.QueryError();
if (ulErr != NO_ERROR)
{
return ulErr;
}
#endif
if ((psz != NULL) && (pfLog != NULL))
{
int iRet = fprintf(pfLog, "%s", psz);
if (iRet < 0)
{
OutputDebugStringA("CTLOG::Failed to log data string : ");
OutputDebugStringA(psz);
OutputDebugStringA("\n");
}
else
{
fflush(pfLog);
}
}
return(ERROR_SUCCESS);
}
#ifndef WIN16
//+-------------------------------------------------------------------
//
// Member: Log::WriteData2(PWCHAR)
//
// Synopsis: Write a string to the Log file.
//
// Arguments: [pwsz] - string to print out
//
// Returns: ERROR_SUCCESS if successful
// Any error code from Log::SetStrData() or Log::LogData
// or CTCLock::QueryError()
//
// Modifies: ulLastError
//
// History: 3-Jul-92 DeanE Modified to call WriteDataList
//
//--------------------------------------------------------------------
ULONG Log :: WriteData2(PWCHAR pwsz)
{
#ifndef WIN16
CTCLock clMemLock (hMtxSerialize); // Serialize access to this object
ULONG ulErr = clMemLock.QueryError();
if (ulErr != NO_ERROR)
{
return ulErr;
}
#endif
if ((pwsz != NULL) && (pfLog != NULL))
{
int iRet = fprintf(pfLog, "%ls", pwsz);
if (iRet < 0)
{
OutputDebugStringA("CTLOG::Failed to log data string : ");
// Note on Chicago this call will be stubbed out.
OutputDebugStringW(pwsz);
OutputDebugStringA("\n");
}
else
{
fflush(pfLog);
}
}
return(ERROR_SUCCESS);
}
#endif
//+-------------------------------------------------------------------
//
// Member: Log::WriteVar
//
// Synopsis: Write a variation status to the Log file.
//
// Arguments:
//
// Returns: ERROR_SUCCESS if successful
// Any error code from Log::SetStrData() or Log::LogData
// or CTCLock::QueryError()
//
// Modifies: ulLastError
//
// History: ??-???-?? ???????? Created
// 3-Jul-92 DeanE Modified to call WriteDataList
//
//--------------------------------------------------------------------
ULONG Log :: WriteVar(PCHAR pszVariation,
USHORT usStatus,
PCHAR pszStrFmt, ... )
{
CHAR szBuffer[CCH_MAX_CHARS];
va_list varArgs;
#ifndef WIN16
CTCLock clMemLock (hMtxSerialize); // Serialize access to this object
ULONG ulErr = clMemLock.QueryError();
if (ulErr != NO_ERROR)
{
return ulErr;
}
#endif
szBuffer[0] = '\0';
szBuffer[CCH_MAX_CHARS-1] = '\0';
if (pfLog != NULL)
{
int iRet;
if (pszStrFmt != NULL)
{
// Print the caller's string to a buffer
va_start(varArgs, pszStrFmt);
_vsnprintf(szBuffer, CCH_MAX_CHARS-1, pszStrFmt, varArgs);
va_end(varArgs);
iRet = fprintf(pfLog, "%s: %s: %s\n", aStatus[usStatus],
pszVariation, szBuffer);
}
else
{
iRet = fprintf(pfLog, "%s: %s\n", aStatus[usStatus], pszVariation);
}
if (iRet < 0)
{
OutputDebugStringA("CTLOG::Failed to log variation string : ");
OutputDebugStringA(pszVariation);
OutputDebugStringA("\n");
}
else
{
fflush(pfLog);
}
fflush(pfLog);
}
return(ERROR_SUCCESS);
}
//+-------------------------------------------------------------------
//
// Member: Log ::InitLogging(VOID)
//
// Synopsis: Initialize the classes data members.
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
void Log :: InitLogging(VOID)
{
pszLoggingDir = NULL;
pszMachineName = NULL;
pszObjectName = NULL;
pszTestName = NULL;
pszPath = NULL;
pszStatus = NULL;
pszVariation = NULL;
pszLogFileName = NULL;
pszShortLogFileName = NULL;
fInfoSet = FALSE;
pfLog = NULL;
}
//+-------------------------------------------------------------------
//
// Member: Log ::SetLogFile(VOID)
//
// Synopsis: Combine the logging file name components into a full path
// file name. If this new file name is not the same as that
// referenced by element pszLogFileName, switch to log data
// into the file in this new name.
//
// Returns: ERROR_SUCCESS if successful, else
// ERROR_INVALID_PARAMETER
// ERROR_OUTOFMEMORY
// ERROR_CANTOPEN
// Any error from AddComponent, CheckDir, SetLogFileName,
// or SetEventCount
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG Log :: SetLogFile()
{
if (((pszLoggingDir != (PCHAR) NULL) &&
(strlen(pszLoggingDir) > _MAX_PATH)) ||
((pszPath != NULL) && (strlen(pszPath) > _MAX_PATH)))
{
return ERROR_INVALID_PARAMETER;
}
PCHAR pszNewFileName = new char[_MAX_PATH + 1];
if(pszNewFileName == NULL)
{
return ERROR_OUTOFMEMORY;
}
//
// No -
// For each component of the new log file path, append it to the
// root logging directory. Make sure only one back-slash exists
// between each appended path component.
//
if(pszLoggingDir != NULL && *pszLoggingDir != NULLTERM)
{
strcpy(pszNewFileName, pszLoggingDir);
}
else
{
*pszNewFileName = NULLTERM;
}
ulLastError =
AddComponent(pszNewFileName, pszPath) ||
AddComponent(pszNewFileName, pszTestName);
//
// The the new file name was successfully built, see if it the same as
// the name of the currently open log file (if one is open). If is not
// the same file name, close the open one (if open) and open the new
// logging file. If the open is successful, save the name of the newly
// opened file for the next time thru here.
//
// A later version of this method could be written to create a LRU queue
// of some max number of open logging files. This version just keeps one
// file open at a time, closing it only to switch to a different log file.
//
if(ulLastError == ERROR_SUCCESS)
{
strcat(pszNewFileName, (const char *)".Log");
ulLastError = SetLogFileName((const char *) pszNewFileName);
if (ulLastError == ERROR_SUCCESS)
{
char szName[_MAX_FNAME];
GetBaseFilename(pszNewFileName, szName);
ulLastError = SetShortLogFileName((const char *) szName);
}
if (ulLastError == ERROR_SUCCESS)
{
// Changed this from fopen() to work on chicago 16 bit
pfLog = _fsopen(pszNewFileName, "a", _SH_DENYNO);
if(pfLog == NULL)
{
ulLastError = ERROR_CANTOPEN;
OutputDebugStringA("CTLOG::Failed to create log file");
OutputDebugStringA(pszNewFileName);
OutputDebugStringA("\n");
}
}
}
delete [] pszNewFileName;
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: Log ::AddComponent(PCHAR, PCHAR)
//
// Synopsis: Append a path component to the given string in szNewName.
// Make sure there is one and only one '\' between each
// component and no trailing '\' is present.
//
// Arguments: [szNewName] - Pointer to exist path (must not be NULL)
// [szComponent] - New component to add
//
// Returns: ERROR_SUCCESS if successful
// ERROR_INVALID_PARAMETER
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG Log :: AddComponent(PCHAR szNewName, PCHAR szComponent)
{
PCHAR pch = NULL;
// Path component provided?
if (szComponent != NULL && *szComponent != NULLTERM)
{
int nLen = strlen((const char *)szComponent);
//
// Trim trailing and leading '\'s from the component to be appended,
// then append the component to the file name.
//
pch = szComponent + nLen;
while (pch > szComponent)
{
if (*pch == SLASH)
{
*pch = NULLTERM;
pch--;
}
else
{
break;
}
}
pch = szComponent;
while (*pch == SLASH)
{
pch++;
}
//
// Append one '\' to the file name then append the given component.
//
if (strlen((const char *)szNewName) + nLen + 1 < _MAX_PATH)
{
nLen = strlen((const char *)szNewName);
if (nLen > 0)
{ // Add component separater
szNewName[ nLen++] = SLASH;
}
strcpy(&szNewName[nLen], (const char *)pch);
}
else
{
ulLastError = ERROR_INVALID_PARAMETER;
}
}
return(ulLastError);
}
//+-------------------------------------------------------------------
//
// Member: Log ::LogOpen(VOID)
//
// Synopsis: If we are not in the LogSvr and if logging remotly, try
// to a START record to the server. If not, or if the attempt
// fails, log the data locally. This may require opening the
// local log file.
//
// Returns: ERROR_SUCCESS if successful
// Results from Remote(), SetLogFile(), or OpenLogFile()
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG Log :: LogOpen()
{
if(pfLog == NULL)
{
//
// Something failed in the remote logging attempt, or this is our
// first call to open the log file, so set up to log locally.
//
ulLastError = SetLogFile();
if(ulLastError != ERROR_SUCCESS)
{
return ulLastError; // Setup failed... Don't go any further.
}
}
return ERROR_SUCCESS;
}
//+-------------------------------------------------------------------
//
// Member: Log ::SetInfo(const char *, const char *,
// const char *, const char *)
//
// Synopsis: Set the logging information about the test being run.
// User is set to pszTest OR logged on username OR MY_NAME in
// that order of preference.
// Machinename is set to computername OR MY_NAME in
// that order of preference.
//
//
// Arguments: [pszSrvr] - Name of logging server
// [pszTest] - Name of the test being run
// [pszSubPath] - Log file path qualifier
// [pszObject] - Name of object logging the data
//
// Returns: USHORT - ERROR_SUCCESS (ERROR_SUCCESS) if successful. Otherwise,
// the return value from SetTestName,
// SetTester, SetPath, or SerObjectName.
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// 09-Feb-92 BryanT Added Win32 support
// 01-Jul-92 Lizch Fixed bug where testername was getting
// overwritten if machinename not set.
// 30-Jul-92 SarahJ Fixed memory trashing bug - SetTester
// & SetmachineName were trashing environment
// variables
// 30-Oct-92 SarahJ Removed all signs of pszTester - it
// was only mis-used
//--------------------------------------------------------------------
ULONG Log :: SetInfo(const char * pszSrvr,
const char * pszTest,
const char * pszSubPath,
const char * pszObject)
{
ulLastError =
SetTestName(pszTest) ||
SetPath(pszSubPath) ||
SetObjectName(pszObject);
if(ulLastError == ERROR_SUCCESS && pszMachineName == NULL)
{
SetMachineName("MyMachineName");
if(pszMachineName == NULL)
{
// ulLastError has been set to error by SetMachineName.
fprintf(stderr, "ERROR! machine name not set\n");
}
}
if(ulLastError == ERROR_SUCCESS)
{
fInfoSet = TRUE; // Note that info has been set
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: Log ::OpenLogFile(VOID)
//
// Synopsis: Opens log file if not already open.
//
// Returns: ERROR_SUCCESS if successful, else ERROR_CANTOPEN
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG Log :: OpenLogFile(VOID)
{
ULONG ulErr = ERROR_SUCCESS;
if(pfLog == NULL)
{
// changed this from fopen() to work on chicago 16 bit
pfLog = _fsopen(pszLogFileName, "a", _SH_DENYNO);
if(pfLog == NULL)
{
ulErr = ERROR_CANTOPEN;
}
}
return(ulErr);
}
//+-------------------------------------------------------------------
//
// Member: Log ::CloseLogFile(VOID)
//
// Synopsis: If a logging file is open, write event count to the
// beginning of the file and close the file
//
// Returns: <nothing> - sets ulLastError if there is an error
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
void Log :: CloseLogFile(VOID)
{
if(pfLog != NULL)
{
fclose(pfLog);
pfLog = NULL;
}
// SetLogFileName((PCHAR) NULL);
}
//+-------------------------------------------------------------------
//
//
// Member: Log ::LogPrintf(HANDLE, PCHAR, ...)
//
// Synopsis: This version has a max formared output of STRBUFSIZ
// (see log.h). The only check I know how to make is to
// strlen the format string. It is not fool-proof but it's
// better than nothing. The method allows a printf-like format
// and args to be written to a file opened with 'open()'.
//
// Arguments: [nHandle] - Output File handle
// [pszFmt] - Format string for output
// [...] - Data to pass printf()
//
// Returns: ERROR_SUCCESS if successful
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// 16-Sep-92 SarahJ Changed this function to at most write
// STDSTRBUFSIZ bytes.
//
// Note: I have assumed that LogPrintf does not print > 1K
// and can find no use with more data.
// If I am wrong then the code from SetStrData should be
// copied here.
//
//--------------------------------------------------------------------
int Log :: LogPrintf(FILE *pf, PCHAR pszFmt, ...)
{
return ERROR_SUCCESS;
}
//+-------------------------------------------------------------------
//
// Member: Log ::NewString(PCHAR *, const char *)
//
// Synopsis: This method will delete the existing string if it exists,
// and (if a new string is given) will create and return a
// duplicate string.
// The assumption, here, is that the original pointer was
// properly initialized to NULL prior to calling this method
// the firsttime for that original string.
//
// Arguments: [pszOrig] - The original string
// [pszNewStr] - The new and improved string
//
// Returns: ERROR_SUCCESS if successful, else ERROR_OUTOFMEMORY.
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG Log :: NewString(PCHAR *pszOrig, const char * pszNewStr)
{
DelString(pszOrig);
// If a new string was given, duplicate it.
if(pszNewStr != NULL)
{
*pszOrig = new char[strlen(pszNewStr) + 1];
if(*pszOrig == NULL)
{
ulLastError = ERROR_OUTOFMEMORY;
}
else
{
strcpy(*pszOrig, pszNewStr);
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Function: DelString(PCHAR *)
//
// Synopsis: Given a pointer to a string, delete the memory if necessary
// and set the pointer to NULL
//
// Arguments: [pszOrig] Original string to delete
//
// Returns: <nothing>
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
VOID Log :: DelString(PCHAR *pszOrig)
{
if (*pszOrig != NULL)
{
delete *pszOrig;
*pszOrig = NULL;
}
}
//+-------------------------------------------------------------------
//
// Function: GetBaseFilename
//
// Synopsis: Return a filename with it's extension and path
// stripped off
//
// Arguments: [pszFileWithExtension] -- The full filename
// [pszBaseName] -- Where to put the base name
//
// Returns: <nothing>
//
// History: 15-Apr-96 MikeW Created
// 17-Oct-96 EricHans Fixed to return with path stripped
//
//--------------------------------------------------------------------
void Log :: GetBaseFilename(LPSTR pszFileWithExtension, LPSTR pszBaseName)
{
LPSTR pszStartOfExtension;
LPSTR pszLastBackslash;
UINT nCharsInBase;
pszStartOfExtension = strrchr(pszFileWithExtension, '.');
// assume this is a fully qualified path or
// just the filename itself
pszLastBackslash = strrchr(pszFileWithExtension, '\\');
if (NULL == pszStartOfExtension)
{
// find the end of the string
pszStartOfExtension = strchr(pszFileWithExtension, '\0');
}
if (NULL == pszLastBackslash)
{
nCharsInBase = pszStartOfExtension - pszFileWithExtension;
strncpy(pszBaseName, pszFileWithExtension, nCharsInBase);
}
else
{
if (pszLastBackslash > pszStartOfExtension)
{
// boundary condition: there's actually a dot in the path
// find the end of the string instead
pszStartOfExtension = strchr(pszFileWithExtension, '\0');
}
nCharsInBase = (pszStartOfExtension - pszLastBackslash) - 1;
strncpy(pszBaseName, pszLastBackslash + 1, nCharsInBase);
}
pszBaseName[nCharsInBase] = '\0';
}