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.
 
 
 
 
 
 

2699 lines
79 KiB

//+-------------------------------------------------------------------
//
// File: common.cxx
//
// Contents: The common methods for logsvr and the log sub-projects
//
// Classes: LOGCLASS Actually, this is a macroname that is defined
// at compile time
//
// Functions: DelString(PCHAR *)
// LOGCLASS ::InitLogging(VOID)
// LOGCLASS ::FreeLogging(VOID)
// LOGCLASS ::SetLogFile(VOID)
// LOGCLASS ::AddComponent(PCHAR, PCHAR)
// LOGCLASS ::SetEventCount(VOID)
// LOGCLASS ::LogOpen(VOID)
// LOGCLASS ::OpenLogFile(VOID)
// LOGCLASS ::LogData(VOID)
// LOGCLASS ::WriteToLogFile(VOID)
// LOGCLASS ::WriteHeader(VOID)
// LOGCLASS ::WriteBinItem(CHAR, PVOID, USHORT)
// LOGCLASS ::CheckDir(PCHAR)
// LOGCLASS ::NewString(PCHAR *, CPPSZ)
// LOGCLASS ::SetInfo(CPPSZ, CPPSZ, CPPSZ, CPPSZ)
// LOGCLASS ::SetStrData(PCHAR, va_list)
// LOGCLASS ::CloseLogFile(VOID)
// LOGCLASS ::SetBinData(USHORT, PVOID)
// LOGCLASS ::LogPrintf(HANDLE, PCHAR, ...)
// LOGCLASS ::FlushLogFile(USHORT)
// LOGCLASS ::SetIsComPort(CPPSZ)
// LOGCLASS ::LogEventCountVOID)
//
// History: 26-Sep-90 DaveWi Initial Coding
// 18-Oct-90 DaveWi Redesigned to be #included in log.cxx
// and logsvr.cxx.
// 25-Sep-91 BryanT Converted to C 7.0
// 14-Oct-91 SarahJ DCR 527 - changed WriteBinItem to not
// pad length argument to fixed length
// 30-Oct-91 SarahJ removed def for CCHMAXPATH
// 30-Oct-91 SarahJ removed addition of 11 spaces after event
// count for no purpose in LogEventCount
// 14-Nov-91 SarahJ replaced code to pad the event count
// with spaces as it has a purpose! Also
// explained padding in comment with code.
// 09-Feb-92 BryanT Win32 work and general cleanup.
// 16-Jul-92 DeanE Added wchar string support by changing
// vsprintf to w4vsprintf
// BUGBUG - the above addition may still
// not work because the string formed is
// then processed by non wchar functions
// 1-Aug-92 DwightKr Renamed CPCHAR as CPPSZ. CPCHAR
// conflicted with the 297 version of
// windows.h
// 17-Sep-92 SarahJ Bug fixes and memory usage improvements
// 30-Oct-92 Sarahj Removed the use of pszTester from mn:
// or elsewhere
//
//--------------------------------------------------------------------
#include <pch.cxx>
// BUGBUG Precompiled header does not work on Alpha for some unknown reason and
// so we temporarily remove it.
// #pragma hdrstop
VOID DelString(PCHAR *psz);
VOID DelString(LPWSTR *wsz);
#define LOGCLASS Log
//
// The SEEK_TO macro takes two different arguments. Either FILE_BEGIN
// which makes it seek to the beginning of the file or FILE_END where
// it seeks to the end.
//
#define SEEK_TO(n) \
((fIsComPort==FALSE && \
~0 == SetFilePointer(hLogFile,0,NULL,(n)) ? -1 : NO_ERROR))
#define COUNT_BUFLEN 12 // Buf len for logged data len buffer
#define SLASH_STRING "\\"
#define wSLASH_STRING L"\\"
//+-------------------------------------------------------------------
//
// 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 DelString(PCHAR *pszOrig)
{
if (*pszOrig != NULL)
{
delete *pszOrig;
*pszOrig = NULL;
}
}
//+-------------------------------------------------------------------
//
// Function: DelString(LPWSTR *)
//
// Synopsis: Given a pointer to a string, delete the memory if necessary
// and set the pointer to NULL
//
// Arguments: [wszOrig] Original string to delete
//
// Returns: <nothing>
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
VOID DelString(LPWSTR *wszOrig)
{
if (*wszOrig != NULL)
{
delete *wszOrig;
*wszOrig = NULL;
}
}
//+-------------------------------------------------------------------
//
// Function: wcNametoMbs(PCHAR *)
//
// Synopsis: Given a pointer to a WCHAR string, return a CHAR copy
//
// Arguments: [pwcName] - WCHAR string to copy
//
// Returns: <nothing>
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
PCHAR LOGCLASS::wcNametombs(PWCHAR pwcName)
{
PCHAR pszName = NULL;
if (pwcName != NULL)
{
size_t sizLen = wcslen(pwcName);
if ((pszName = new char[sizLen+1]) == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
memset(pszName, 0, sizLen +1);
if (wcstombs(pszName, pwcName, sizLen) == (size_t)0)
{
delete[] pszName;
ulLastError = ERROR_INVALID_DATA;
}
}
}
return pszName;
}
//+-------------------------------------------------------------------
//
// Class: LOGCLASS (Actually, this is a macroname that is defined
// at compile time)
//
// Purpose:
//
// Interface:
//
// History: ??-???-?? ???????? Created
//
// Notes: The macro LOGCLASS is set in 'makefile'. The methods in
// the file are used in the Log class and in the LogSvr class.
// In the makefile for building the Log class library log.lib,
// LOGCLASS is defined as "Log". In building logsvr.exe,
// LOGCLASS is defined as "LogSvr". This was done because the
// original version of this code was developed under
// Glockenspiel 1.x which does not support multiple inheritance
// and the inheritance tree for the classes which Log and LogSvr
// inherit are such that this was the best way to allow for
// maintaining only one version of these methods.
//
//--------------------------------------------------------------------
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::InitLogging(VOID)
//
// Synopsis: Initialize the classes data members.
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
void LOGCLASS :: InitLogging(VOID)
{
pszLoggingDir = NULL;
pszMachineName = NULL;
pszObjectName = NULL;
pszTestName = NULL;
pszPath = NULL;
pszStatus = NULL;
pszVariation = NULL;
pvBinData = NULL;
pszStrData = NULL;
pszLogFileName = NULL;
wszLoggingDir = NULL;
wszMachineName = NULL;
wszObjectName = NULL;
wszTestName = NULL;
wszPath = NULL;
wszStatus = NULL;
wszVariation = NULL;
wszStrData = NULL;
wszLogFileName = NULL;
fIsComPort = FALSE;
fFlushWrites = FALSE;
fInfoSet = FALSE;
ulEventCount = 0L;
ulEventTime = 0L;
usBinLen = 0;
hLogFile = INVALID_HANDLE_VALUE;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::FreeLogging(VOID)
//
// Synopsis: Reset existing Logging members back to initial state
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
void LOGCLASS :: FreeLogging()
{
va_list vaDummy = LOG_VA_NULL;
CloseLogFile();
fIsComPort = FALSE;
fFlushWrites = FALSE;
fInfoSet = FALSE;
if(FALSE == fIsUnicode)
{
SetLoggingDir((PCHAR) NULL);
SetMachineName((PCHAR) NULL);
SetObjectName((PCHAR) NULL);
SetTestName((PCHAR) NULL);
SetPath((PCHAR) NULL);
SetStatus((PCHAR) NULL);
SetVariation((PCHAR) NULL);
SetStrData((PCHAR) NULL, vaDummy);
}
else
{
SetLoggingDir((LPWSTR) NULL);
SetMachineName((LPWSTR) NULL);
SetObjectName((LPWSTR) NULL);
SetTestName((LPWSTR) NULL);
SetPath((LPWSTR) NULL);
SetStatus((LPWSTR) NULL);
SetVariation((LPWSTR) NULL);
SetStrData((LPWSTR) NULL, vaDummy);
}
ulEventCount = 0L;
ulEventTime = 0L;
SetBinData(0, NULL);
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::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: NO_ERROR if successful
// ERROR_INVALID_PARAMETER
// ERROR_NOT_ENOUGH_MEMORY
// Any error from AddComponent, CheckDir, SetLogFileName,
// or SetEventCount
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: SetLogFile()
{
// if unicode, use the unicode version
if(TRUE == fIsUnicode)
{
return wSetLogFile();
}
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_NOT_ENOUGH_MEMORY;
}
//
// Are we going to log to a COM port?
//
if(SetIsComPort((const char *)pszLoggingDir) != FALSE)
{
fIsComPort = TRUE; // Yes.
strcpy(pszNewFileName, pszLoggingDir);
}
else
{
if(SetIsComPort((const char *)pszPath) != FALSE)
{
fIsComPort = TRUE; // Yes, locally
strcpy(pszNewFileName, pszPath);
}
else
{
//
// 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 == NO_ERROR)
{
if(fIsComPort == FALSE)
{
strcat(pszNewFileName, (const char *)".LOG");
}
if((pszLogFileName == NULL) ||
(hLogFile == INVALID_HANDLE_VALUE) ||
_stricmp(pszNewFileName, pszLogFileName) != SAME)
{
CloseLogFile(); // Make sure it is really closed
//
// Make sure the directory part of the logging file name exists.
// Make each sub-directory that does not exist, then open the
// logging file.
//
ulLastError = CheckDir(pszNewFileName);
if(ulLastError == NO_ERROR)
{
DWORD dwFlags = GENERIC_WRITE;
if(fIsComPort == FALSE)
{
dwFlags |= GENERIC_READ;
}
hLogFile = CreateFileA(pszNewFileName,
dwFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if(hLogFile == INVALID_HANDLE_VALUE)
{
ulLastError = GetLastError();
}
else
{
if(SEEK_TO(FILE_END) != NO_ERROR)
{
ulLastError = GetLastError();
}
else
{
ulLastError =
SetLogFileName((const char *) pszNewFileName) ||
SetEventCount();
}
}
}
}
}
delete [] pszNewFileName;
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::wSetLogFile(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: NO_ERROR if successful
// ERROR_INVALID_PARAMETER
// ERROR_NOT_ENOUGH_MEMORY
// Any error from AddComponent, CheckDir, SetLogFileName,
// or SetEventCount
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: wSetLogFile()
{
CHK_UNICODE(TRUE);
if(((wszLoggingDir != NULL) &&
(wcslen(wszLoggingDir) > _MAX_PATH)) ||
((wszPath != NULL) && (wcslen(wszPath) > _MAX_PATH)))
{
return ERROR_INVALID_PARAMETER;
}
LPWSTR wszNewFileName = new WCHAR[_MAX_PATH + 1];
if(wszNewFileName == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Are we going to log to a COM port?
//
if(SetIsComPort((LPCWSTR) wszLoggingDir) != FALSE)
{
fIsComPort = TRUE; // Yes.
wcscpy(wszNewFileName, wszLoggingDir);
}
else
{
if(SetIsComPort((LPCWSTR) wszPath) != FALSE)
{
fIsComPort = TRUE; // Yes, locally
wcscpy(wszNewFileName, wszPath);
}
else
{
//
// 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(wszLoggingDir != NULL && *wszLoggingDir != wNULLTERM)
{
wcscpy(wszNewFileName, wszLoggingDir);
}
else
{
*wszNewFileName = wNULLTERM;
}
ulLastError = AddComponent(wszNewFileName, wszPath) ||
AddComponent(wszNewFileName, wszTestName);
}
}
//
// 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 == NO_ERROR)
{
if(fIsComPort == FALSE)
{
wcscat(wszNewFileName, L".LOG");
}
if((wszLogFileName == NULL) || (hLogFile == INVALID_HANDLE_VALUE) ||
_wcsicmp(wszNewFileName, wszLogFileName) != SAME)
{
CloseLogFile(); // Make sure it is really closed
//
// Make sure the directory part of the logging file name exists.
// Make each sub-directory that does not exist, then open the
// logging file.
//
ulLastError = CheckDir(wszNewFileName);
if(ulLastError == NO_ERROR)
{
DWORD dwFlags = GENERIC_WRITE;
if(fIsComPort == FALSE)
{
dwFlags |= GENERIC_READ;
}
hLogFile = CreateFileW(wszNewFileName,
dwFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if(hLogFile == INVALID_HANDLE_VALUE)
{
ulLastError = GetLastError();
}
else
{
if(SEEK_TO(FILE_END) != NO_ERROR)
{
ulLastError = GetLastError();
}
else
{
ulLastError = SetLogFileName((LPCWSTR) wszNewFileName)
|| SetEventCount();
}
}
}
}
}
delete [] wszNewFileName;
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::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: NO_ERROR if successful
// ERROR_INVALID_NAME
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: AddComponent(PCHAR szNewName, PCHAR szComponent)
{
CHK_UNICODE(FALSE);
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_NAME;
}
}
return(ulLastError);
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::AddComponent(LPWSTR, LPWSTR)
//
// 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: [wszNewName] - Pointer to exist path (must not be NULL)
// [wszComponent] - New component to add
//
// Returns: NO_ERROR if successful
// ERROR_INVALID_NAME
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: AddComponent(LPWSTR wszNewName, LPWSTR wszComponent)
{
CHK_UNICODE(TRUE);
LPWSTR wch = NULL;
// Path component provided?
if(wszComponent != NULL && *wszComponent != wNULLTERM)
{
int nLen = wcslen((LPWSTR) wszComponent);
//
// Trim trailing and leading backslash from the component to be
// appended, then append the component to the file name.
//
wch = wszComponent + nLen;
while(wch > wszComponent)
{
if(*wch == wSLASH)
{
*wch = wNULLTERM;
wch--;
}
else
{
break;
}
}
wch = wszComponent;
while(*wch == wSLASH)
{
wch++;
}
//
// Append one backslash to the file name then append the
// given component.
//
if(wcslen(wszNewName) + nLen + 1 < _MAX_PATH)
{
nLen = wcslen(wszNewName);
if(nLen > 0)
{ // Add component separater
wszNewName[nLen++] = wSLASH;
}
wcscpy(&wszNewName[nLen], wch);
}
else
{
ulLastError = ERROR_INVALID_NAME;
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::SetEventCount(VOID)
//
// Synopsis: This version assumes the current event count is in ASCII
// format at beginning of the file. It is also assumed that
// the value is in the range 0-65535 so it will fit in a small
// buffer and in a USHORT.
//
// Returns: NO_ERROR if successful
// Values from GetLastError() after CRT function is called
// CORRUPT_LOG_FILE
// ERROR_NOT_ENOUGH_MEMORY
//
// Notes: This should not need converting to unicode - dda
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: SetEventCount()
{
//
// If we're using a COM port, set the EventCount to 0 since
// we can't read from it anyway
//
if(fIsComPort != FALSE)
{
ulEventCount = 0L;
return NO_ERROR;
}
//
// This version assumes the log file is a binary file, not normally
// readable by the user without the LOGVIEWER utility. It seeks to
// the beginning of the file, reads into zsCount, translates szCount
// to a ULONG, and seeks to the end.
//
if(SEEK_TO(FILE_BEGIN) != NO_ERROR)
{
ulLastError = GetLastError();
}
else
{
LONG lLen = GetFileSize(hLogFile, NULL);
if(lLen == -1L)
{
ulLastError = GetLastError();
}
else if(lLen < MIN_LINE_HDR_LEN)
{
ulEventCount = 0L; // The file has been newly created
}
else
{
PCHAR pszTmp = new CHAR[LINE_HDR_LEN+1];
// Read the data line header
if(pszTmp != NULL)
{
//
// SarahJ - Event count is held in a ulong therefore its
// maximum length as ascii will be 10 digits - and at this
// point you have a mega file! This means that the maximum
// length that the data can be is 2, and 99.9% of the time
// will be 1. The below code depends on at most 2 chars being
// used for the length. First read MIN_LINE_HDR_LEN bytes
// then read 1 more byte to find the :.
//
DWORD dwBytesRead;
if(FALSE == ReadFile(hLogFile, (LPVOID) pszTmp,
MIN_LINE_HDR_LEN, &dwBytesRead, NULL) ||
MIN_LINE_HDR_LEN != dwBytesRead)
{
ulLastError = GetLastError();
}
else
{
PCHAR pchTmp = &pszTmp[MIN_LINE_HDR_LEN - 1];
if(*pchTmp != ':')
{
if(FALSE == ReadFile(hLogFile, (LPVOID) pszTmp,
1, &dwBytesRead, NULL) ||
1 != dwBytesRead)
{
ulLastError = GetLastError();
}
}
else if(*pchTmp != ':')
{
ulEventCount = 0L;
}
else
{
*pchTmp = NULLTERM;
// Get the # bytes in the event count value. The line
// starts with x: where x is the LOG_EVENTS_ID
// ID character.
if(*pszTmp == LOG_EVENTS)
{
ULONG ulLen = (ULONG) atoi(&pszTmp[2]);
if(ulLen > 0)
{
PCHAR pszCount = new CHAR[ulLen + 1];
if(pszCount != NULL)
{
// Read the event count value
if(FALSE == ReadFile(hLogFile,
(LPVOID) pszTmp,
ulLen, &dwBytesRead,
NULL) ||
ulLen != dwBytesRead)
{
ulLastError = GetLastError();
ulEventCount = 0L;
}
else
{
pszCount[ulLen] = NULLTERM;
ulEventCount = atol(pszCount);
}
delete pszCount;
}
else
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
ulEventCount = 0L;
}
}
else
{
ulEventCount = 0L;
}
}
else
{
ulLastError = CORRUPT_LOG_FILE;
ulEventCount = 0L;
}
}
delete pszTmp;
}
}
else
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
ulEventCount = 0L;
}
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::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: NO_ERROR if successful
// Results from Remote(), SetLogFile(), or OpenLogFile()
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: LogOpen()
{
if(hLogFile == INVALID_HANDLE_VALUE)
{
//
// 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 != NO_ERROR)
{
return ulLastError; // Setup failed... Don't go any further.
}
}
return OpenLogFile();
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::OpenLogFile(VOID)
//
// Synopsis: This version assumes that SetLogFile has already been called.
//
// Returns: Value of GetLastError() if a CRT function fails otherwise,
// return code from FlushLogFile()
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: OpenLogFile()
{
long lLen;
//
// If the logging file is empty, write a header to the file and set the
// event counter to zero.
//
if(fIsComPort == FALSE)
{
lLen = GetFileSize(hLogFile, NULL);
if(lLen == -1L)
{
ulLastError = GetLastError();
return ulLastError;
}
}
else
{
lLen = 0L;
}
if(lLen < LINE_HDR_LEN)
{
if(SEEK_TO(FILE_BEGIN) != NO_ERROR)
{
ulLastError = GetLastError();
}
else
{
ulLastError = WriteHeader();
}
}
return FlushLogFile(ulLastError);
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::LogData(VOID)
//
// Synopsis: If logging remotely, try to send data to the server. If
// not, or if the attempt fails, log the data locally. This
// may require opening the local log file.
//
// Returns: Result from WriteToLogFile
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: LogData()
{
if(hLogFile == INVALID_HANDLE_VALUE)
{
//
// This is our first call to open the log file
//
ulLastError = SetLogFile();
if(ulLastError != NO_ERROR)
{
return ulLastError; // Setup failed; Don't go any further.
}
}
// Log file opened OK, so write the data
return WriteToLogFile();
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::WriteToLogFile(VOID)
//
// Synopsis: Write data out to the log file.
//
// Returns: NO_ERROR if successful
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: WriteToLogFile()
{
// use unicode method
if(TRUE == fIsUnicode)
{
return wWriteToLogFile();
}
char chBuf[COUNT_BUFLEN];
int cLen = sprintf(chBuf, "%lu", ulEventCount + 1);
ulLastError = WriteBinItem(LOG_EVENT_NUM, (PVOID) chBuf, cLen);
if(ulLastError == NO_ERROR)
{
//
// If the event time has not already been set, set it to the
// current system time.
//
cLen = sprintf(chBuf, "%lu", (ulEventTime==0L) ?
time((time_t *) NULL) : ulEventTime);
ulLastError = WriteBinItem(LOG_EVENT_TIME,
(PVOID) chBuf, strlen((const char *)chBuf))
|| WriteBinItem(LOG_MACHINE,
(PVOID) pszMachineName,
(pszMachineName == NULL) ?
0 : strlen((const char *)pszMachineName))
|| WriteBinItem(LOG_OBJECT,
(PVOID) pszObjectName,
(pszObjectName == NULL) ?
0 : strlen((const char *)pszObjectName))
|| WriteBinItem(LOG_VARIATION,
(PVOID) pszVariation,
(pszVariation == NULL) ?
0 : strlen((const char *)pszVariation))
|| WriteBinItem(LOG_STATUS,
(PVOID) pszStatus,
(pszStatus == NULL) ?
0 : strlen((const char *)pszStatus))
|| WriteBinItem(LOG_STRING,
(PVOID) pszStrData,
(pszStrData == NULL) ?
0 : strlen((const char *)pszStrData))
|| WriteBinItem(LOG_BINARY, pvBinData, usBinLen);
if(ulLastError == NO_ERROR)
{
++ulEventCount; // Increment the count of logged events
if(pszStatus != NULL
&& strcmp(pszStatus, LOG_DONE_TXT) == SAME)
{
CloseLogFile(); // Make sure the data has been flushed
}
}
}
// Clean up in preparation for next packet
va_list vaDummy = LOG_VA_NULL;
SetStatus((PCHAR) NULL);
SetVariation((PCHAR) NULL);
ulEventTime = 0L;
SetBinData(0, NULL);
SetStrData((PCHAR) NULL, vaDummy);
return FlushLogFile(ulLastError);
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::wWriteToLogFile(VOID)
//
// Synopsis: Write data out to the log file.
//
// Returns: NO_ERROR if successful
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: wWriteToLogFile()
{
CHK_UNICODE(TRUE);
WCHAR wchBuf[COUNT_BUFLEN];
int cLen = swprintf(wchBuf, L"%lu", ulEventCount + 1);
ulLastError = WriteBinItem(LOG_EVENT_NUM, (PVOID) wchBuf,
cLen * sizeof(WCHAR));
if(ulLastError == NO_ERROR)
{
//
// If the event time has not already been set, set it to the
// current system time.
//
cLen = swprintf(wchBuf, L"%lu", (ulEventTime==0L) ?
time((time_t *) NULL) : ulEventTime);
ulLastError = WriteBinItem(LOG_EVENT_TIME,
(PVOID) wchBuf,
wcslen(wchBuf) * sizeof(WCHAR))
|| WriteBinItem(LOG_MACHINE,
(PVOID) wszMachineName,
(wszMachineName == NULL) ?
0 : wcslen(wszMachineName) * sizeof(WCHAR))
|| WriteBinItem(LOG_OBJECT,
(PVOID) wszObjectName,
(wszObjectName == NULL) ?
0 : wcslen(wszObjectName) * sizeof(WCHAR))
|| WriteBinItem(LOG_VARIATION,
(PVOID) wszVariation,
(wszVariation == NULL) ?
0 : wcslen(wszVariation) * sizeof(WCHAR))
|| WriteBinItem(LOG_STATUS,
(PVOID) wszStatus,
(wszStatus == NULL) ?
0 : wcslen(wszStatus) * sizeof(WCHAR))
|| WriteBinItem(LOG_STRING,
(PVOID) wszStrData,
(wszStrData == NULL) ?
0 : wcslen(wszStrData) * sizeof(WCHAR))
|| WriteBinItem(LOG_BINARY, pvBinData, usBinLen);
if(ulLastError == NO_ERROR)
{
++ulEventCount; // Increment the count of logged events
if(wszStatus != NULL &&
wcscmp(wszStatus, wLOG_DONE_TXT) == SAME)
{
CloseLogFile(); // Make sure the data has been flushed
}
}
}
// Clean up in preparation for next packet
va_list vaDummy = LOG_VA_NULL;
SetStatus((LPWSTR) NULL);
SetVariation((LPWSTR) NULL);
ulEventTime = 0L;
SetBinData(0, NULL);
SetStrData((LPWSTR) NULL, vaDummy);
return FlushLogFile(ulLastError);
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::WriteHeader(VOID)
//
// Synopsis: Write data about this logging file. This only happens
// when the file is first created.
//
// Returns: NO_ERROR if successful
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: WriteHeader()
{
LogEventCount();
if (ulLastError == NO_ERROR)
{
if(FALSE == fIsUnicode)
{
ulLastError = WriteBinItem(LOG_TEST_NAME, (PVOID) pszTestName,
(pszTestName == NULL) ?
0 : strlen(pszTestName));
if (ulLastError == NO_ERROR)
{
char chBuf[COUNT_BUFLEN];
// Show when log file was started
int cLen = sprintf(chBuf, "%lu", time((time_t *)NULL));
ulLastError =
WriteBinItem(LOG_TEST_TIME, (PVOID) chBuf, cLen) ||
WriteBinItem(LOG_SERVER, (PVOID) NULL, 0);
}
}
else
{
ulLastError = WriteBinItem(LOG_TEST_NAME, (PVOID) wszTestName,
(wszTestName == NULL) ? 0 :
wcslen(wszTestName) * sizeof(WCHAR));
if (ulLastError == NO_ERROR)
{
WCHAR wchBuf[COUNT_BUFLEN];
// Show when log file was started
int cLen = swprintf(wchBuf, L"%lu", time((time_t *)NULL));
ulLastError =
WriteBinItem(LOG_TEST_TIME, (PVOID) wchBuf,
cLen * sizeof(WCHAR)) ||
WriteBinItem(LOG_SERVER, (PVOID) NULL, 0);
}
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::WriteBinItem(CHAR, PVOID, ULONG)
//
// Synopsis: Attempt to write Binary data to the log file
//
// Arguments: [chMark] The Item ID for the data
// [pvItem] Pointer to the data data
// [ulItemLen] Length of data to write
//
// Returns: NO_ERROR if successful
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// 19-Sep_92 SarahJ Changed length to be ULONG so
// Data 32K can be written (note
// with header stuff it is > 32K)
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: WriteBinItem(CHAR chMark,
PVOID pvItem,
ULONG ulItemLen)
{
if(fIsComPort != FALSE && chMark == LOG_BINARY)
{
return NO_ERROR; // Do not send binary data to a COM port
}
//
// Write everything at the end of the file except for the # events in
// the file.
//
if(SEEK_TO((chMark == LOG_EVENTS)? FILE_BEGIN : FILE_END) != NO_ERROR)
{
ulLastError = GetLastError();
return ulLastError;
}
CHAR szLen[LINE_HDR_LEN+1];
//
// Every field of data starts with a header of the form 'x:nnnnn:' where
// 'x' is the given ID char and nnnnn is the # of bytes of data.
//
int nLen = sprintf(szLen, "%c:%u:", chMark, ulItemLen);
//
// SarahJ - changed to not pad the number out to LINE_HDR_LEN -3, but to
// use minimum # of digits as per DCR 527
//
// We do not have to check dwBytesWritten because WriteFile will
// fail on a file if all bytes not written.
DWORD dwBytesWritten;
if(FALSE == WriteFile(hLogFile, (CONST LPVOID) szLen, nLen,
&dwBytesWritten, NULL))
{
ulLastError = GetLastError();
return ulLastError;
}
if(ulItemLen > 0 && ulLastError == NO_ERROR)
{
if(FALSE == WriteFile(hLogFile, (CONST LPVOID) pvItem, ulItemLen,
&dwBytesWritten, NULL))
{
ulLastError = GetLastError();
return ulLastError;
}
}
// Every field of data ends with a '\n'
if(FALSE == WriteFile(hLogFile, (CONST LPVOID) "\n", sizeof(CHAR),
&dwBytesWritten, NULL))
{
ulLastError = GetLastError();
}
// carriage return for com port
if(fIsComPort == TRUE &&
FALSE == WriteFile(hLogFile, (CONST LPVOID) "\r", sizeof(CHAR),
&dwBytesWritten, NULL))
{
ulLastError = GetLastError();
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::CheckDir(PCHAR)
//
// Synopsis: Make sure each subdirectory in the given path exists.
//
// Arguments: [pszRelPath] - Pathname to check, relative to
// current directory
//
// Returns: NO_ERROR if the the directory does exist or was
// successfully made. A GetLastError() value otherwise.
//
//
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// 92-Apr-17 DwightKr Added EINVAL to _mkdir() check. We'll
// get this back on the N386 compiler if
// the directory already exists
// 01-Jul-92 Lizch Gutted routine to use much simpler ctcopy code
// courtesy of DwightKr
//
// 16-Sep-92 SarahJ Added check that _fullpath does not return NULL
// to fix bug 300
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: CheckDir(PCHAR pszRelPath)
{
CHK_UNICODE(FALSE);
char *pszToken;
char *pszFileName;
char pszPath[_MAX_PATH];
char szDirToMake[_MAX_PATH] = "\0";
if(fIsComPort != FALSE)
{
return NO_ERROR; // COM port directories are an oxymoran.
}
if(0 != GetFullPathNameA(pszRelPath, _MAX_PATH - 1, pszPath, &pszFileName))
{
#ifdef TRACE
printf("Making directory %s\n", pszPath);
#endif
// First, we need to remove the filename off the
// end of the path so we do not create a dir with it! Look for
// the last backslash. It is either at the end (no file - error),
// the beginning (file at root - error), somewhere in between, or
// not at all.
if(NULL == (pszFileName = strrchr(pszPath, '\\')) ||
pszFileName == pszPath ||
'\0' == *(pszFileName + 1))
{
*pszPath = '\0';
}
else
{
*pszFileName = '\0';
}
// Just blindly create directories based on the backslashes parsed
// by strtok. We will look at the return from GetLastError to
// if we were successful at the end.
pszToken = strtok(pszPath, SLASH_STRING);
while(pszToken != NULL)
{
strcat(szDirToMake, pszToken);
if(CreateDirectoryA(szDirToMake, NULL) == TRUE)
{
#ifdef TRACE
printf ("Made directory %s\n", szDirToMake);
#endif
ulLastError = NO_ERROR;
}
else
{
#ifdef TRACE
printf("Didn't make directory %s\n", szDirToMake);
#endif
ulLastError = GetLastError();
}
pszToken = strtok(NULL, SLASH_STRING);
if(pszToken != NULL)
{
strcat(szDirToMake, SLASH_STRING);
}
}
// Leave error checking until we have tryed to add all directories -
// we might as well simply check whether the final addition worked.
// At this point, if the error return indicates the path already
// exists as a directory or file, we need to error out if it is
// actually a file.
if(ulLastError == ERROR_FILE_EXISTS ||
ulLastError == ERROR_ACCESS_DENIED ||
ulLastError == ERROR_ALREADY_EXISTS)
{
DWORD dwAttr;
// Now check if it is a directory, in which case we are OK, else if
// it is a file we need to error out.
if(~0 == (dwAttr = GetFileAttributesA(szDirToMake)))
{
ulLastError = GetLastError();
}
else
{
if(FILE_ATTRIBUTE_DIRECTORY == dwAttr)
{
#ifdef TRACE
printf ("Path already existed - success!\n");
#endif
ulLastError = NO_ERROR;
}
}
}
}
else // GetFullPathName failed
{
ulLastError = GetLastError();
fprintf(stderr, "Bad relative path %s\n", pszRelPath);
#ifdef DBG
*szDirToMake = '\0'; // just done for below error message
#endif
}
#ifdef DBG
if(ulLastError != NO_ERROR)
{
fprintf(stderr, "Fatal error making logging directory:\n\t\t %s.\n"
"Error %u.\n", szDirToMake, ulLastError);
}
#endif
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::CheckDir(LPWSTR)
//
// Synopsis: Make sure each subdirectory in the given path exists.
//
// Arguments: [wszRelPath] - Pathname to check, relative to
// current directory
//
// Returns: NO_ERROR if the the directory does exist or was
// successfully made. An GetLastError() value otherwise.
//
//
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// 92-Apr-17 DwightKr Added EINVAL to _mkdir() check. We'll
// get this back on the N386 compiler if
// the directory already exists
// 01-Jul-92 Lizch Gutted routine to use much simpler ctcopy code
// courtesy of DwightKr
//
// 16-Sep-92 SarahJ Added check that _fullpath does not return NULL
// to fix bug 300
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: CheckDir(LPWSTR wszRelPath)
{
CHK_UNICODE(TRUE);
LPWSTR wszFileName;
LPWSTR wszToken;
WCHAR wszPath[_MAX_PATH];
WCHAR wszDirToMake[_MAX_PATH] = L"\0";
if(fIsComPort != FALSE)
{
return NO_ERROR; // COM port directories are an oxymoran.
}
// check good directory name - is the NULL valid??
if(0 != GetFullPathNameW(wszRelPath, _MAX_PATH - 1, wszPath, NULL))
{
#ifdef TRACE
printf("Making directory %ls\n", wszPath);
#endif
// First, we need to remove the filename off the
// end of the path so we do not create a dir with it! Look for
// the last backslash. It is either at the end (no file - error),
// the beginning (file at root - error), somewhere in between, or
// not at all.
if(NULL == (wszFileName = wcsrchr(wszPath, '\\')) ||
wszFileName == wszPath ||
'\0' == *(wszFileName + 1))
{
*wszPath = '\0';
}
else
{
*wszFileName = '\0';
}
// Just blindly create directories based on the backslashes parsed
// by wcstok. We will look at the return from GetLastError to
// if we were successful at the end.
wszToken = wcstok(wszPath, wSLASH_STRING);
while(wszToken != NULL)
{
wcscat(wszDirToMake, wszToken);
if(CreateDirectoryW(wszDirToMake, NULL) == TRUE)
{
#ifdef TRACE
fprintf(stderr, "Made directory %ls\n", wszDirToMake);
#endif
ulLastError = NO_ERROR;
}
else
{
#ifdef TRACE
fprintf(stderr, "Didn't make directory %ls\n", wszDirToMake);
#endif
ulLastError = GetLastError();
}
wszToken = wcstok(NULL, wSLASH_STRING);
if(wszToken != NULL)
{
wcscat(wszDirToMake, wSLASH_STRING);
}
}
// Leave error checking until we have tryed to add all directories -
// we might as well simply check whether the final addition worked.
// At this point, if the error return indicates the path already
// exists as a directory or file, we need to error out if it is
// actually a file.
if(ulLastError == ERROR_FILE_EXISTS ||
ulLastError == ERROR_ALREADY_EXISTS)
{
DWORD dwAttr;
// Now check if it is a directory, in which case we are OK, else if
// it is a file we need to error out.
if(~0 == (dwAttr = GetFileAttributesW(wszDirToMake)))
{
ulLastError = GetLastError();
}
else
{
if(FILE_ATTRIBUTE_DIRECTORY == dwAttr)
{
#ifdef TRACE
fprintf(stderr, "Path already existed - success!\n");
#endif
ulLastError = NO_ERROR;
}
}
}
}
else // GetFullPathName failed
{
ulLastError = GetLastError();
fprintf(stderr, "Bad relative path %ls\n", wszRelPath);
#ifdef DBG
*wszDirToMake = L'\0'; // just done for below error message
#endif
}
#ifdef DBG
if(ulLastError != NO_ERROR)
{
fprintf(stderr, "Fatal error making logging directory:\n\t\t %ls.\n"
"Error %u.\n", wszDirToMake, ulLastError);
}
#endif
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::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: Returns NULL if 'new' fails or if pszNew is NULL.
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: NewString(PCHAR *pszOrig, const char * pszNewStr)
{
CHK_UNICODE(FALSE);
DelString(pszOrig);
// If a new string was given, duplicate it.
if(pszNewStr != NULL)
{
*pszOrig = new char[strlen(pszNewStr) + 1];
if(*pszOrig == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
strcpy(*pszOrig, pszNewStr);
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::NewString(LPWSTR *, LPCWSTR)
//
// 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: [wszOrig] - The original string
// [wszNewStr] - The new and improved string
//
// Returns: Returns NULL if 'new' fails or if pszNew is NULL.
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: NewString(LPWSTR *wszOrig, LPCWSTR wszNewStr)
{
CHK_UNICODE(TRUE);
DelString(wszOrig);
// If a new string was given, duplicate it.
if(wszNewStr != NULL)
{
*wszOrig = new WCHAR[wcslen(wszNewStr) + 1];
if(*wszOrig == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
wcscpy(*wszOrig, wszNewStr);
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::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 - NO_ERROR (NO_ERROR) 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 LOGCLASS :: SetInfo(const char * pszSrvr,
const char * pszTest,
const char * pszSubPath,
const char * pszObject)
{
CHK_UNICODE(FALSE);
//BUGBUG Temp code
LPSTR pszTempMachineName = "MyMachineName";
ulLastError =
SetTestName(pszTest) ||
SetPath(pszSubPath) ||
SetObjectName(pszObject);
if(ulLastError != NO_ERROR)
{
return ulLastError;
}
if(pszMachineName == NULL)
{
//
// Get network computername. The computername field
// is used for pszMachineName
//
#if defined (__WIN32__) || defined (WIN32)
LPBYTE lpbBuffer = NULL;
/* BUGBUG
PCHAR pszName;
*/
//
// Then, get the machine name, if not already set.
//
if(pszMachineName == NULL)
{
// BUGBUG Temporary code
SetMachineName(pszTempMachineName);
// BUGBUG End of temporary code
/* BUGBUG
if(NERR_Success == NetWkstaGetInfo(NULL, 101, &lpbBuffer))
{
pszName =
wcNametombs((PWCHAR) ((PWKSTA_INFO_101)lpbBuffer)->
wki101_computername);
SetMachineName(pszName);
NetApiBufferFree(lpbBuffer);
delete pszName;
}
*/
}
#else
/* BUGBUG
USHORT usAvail = 0;
USHORT usRC = NetWkstaGetInfo(NULL, 10, NULL, 0, &usAvail);
if(usRC == NERR_BufTooSmall && usAvail > 0)
{
PCHAR pchBuf = (PCHAR)new CHAR[usAvail];
if(pchBuf != NULL)
{
usRC = NetWkstaGetInfo(NULL, 10, pchBuf, usAvail, &usAvail);
if(usRC == NO_ERROR)
{
if(pszMachineName == NULL)
{
SetMachineName(((struct wksta_info_10 *)
pchBuf)->wki10_computername);
}
}
delete pchBuf;
}
}
*/
// BUGBUG Temporary code
SetMachineName(pszTempMachineName);
// BUGBUG End of temporary code
#endif // defined (__WIN32__) || (WIN32)
if(pszMachineName == NULL)
{
fprintf(stderr, "ERROR! machine name not set\n");
}
}
if(ulLastError == NO_ERROR)
{
fInfoSet = TRUE; // Note that info has been set
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::SetInfo(LPCWSTR, LPCWSTR,
// LPCWSTR, LPCWSTR)
//
// 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: [wszSrvr] - Name of logging server
// [wszTest] - Name of the test being run
// [wszSubPath] - Log file path qualifier
// [wszObject] - Name of object logging the data
//
// Returns: USHORT - NO_ERROR (NO_ERROR) 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 LOGCLASS :: SetInfo(LPCWSTR wszSrvr,
LPCWSTR wszTest,
LPCWSTR wszSubPath,
LPCWSTR wszObject)
{
CHK_UNICODE(TRUE);
ulLastError =
SetTestName(wszTest) ||
SetPath(wszSubPath) ||
SetObjectName(wszObject);
if(ulLastError != NO_ERROR)
{
return ulLastError;
}
if(wszMachineName == NULL)
{
//
// Get network computername. The computername field
// is used for pszMachineName
//
#if defined (__WIN32__) || defined (WIN32)
/* BUGBUG
LPBYTE lpbBuffer;
//
// Then, get the machine name, if not already set.
//
if(wszMachineName == NULL)
{
if(NERR_Success == NetWkstaGetInfo(NULL, 101, &lpbBuffer))
{
SetMachineName((LPWSTR) (((PWKSTA_INFO_101)lpbBuffer)->
wki101_computername));
NetApiBufferFree(lpbBuffer);
}
}
*/
#else
USHORT usAvail = 0;
// BUGBUG
// USHORT usRC = NetWkstaGetInfo(NULL, 10, NULL, 0, &usAvail);
if(usRC == NERR_BufTooSmall && usAvail > 0)
{
LPWSTR wchBuf = new WCHAR[usAvail];
if(wchBuf != NULL)
{
// BUGBUG
// usRC = NetWkstaGetInfo(NULL, 10, pchBuf, usAvail, &usAvail);
if(usRC == NO_ERROR)
{
if(wszMachineName == NULL)
{
SetMachineName(((struct wksta_info_10 *)
pchBuf)->wki10_computername);
}
}
delete wchBuf;
}
}
#endif // defined (__WIN32__) || (WIN32)
if(wszMachineName == NULL)
{
fprintf(stderr, "ERROR! machine name not set\n");
}
}
if(ulLastError == NO_ERROR)
{
fInfoSet = TRUE; // Note that info has been set
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::SetStrData(PCHAR, va_list)
//
// Synopsis: Set the string information that is to be logged.
//
// Effects: Create a temporary buffer for the formatted string, format
// the string and copy the new formated string to pszStrData.
// This version limits the formatted string to STRBUFSIZ chars.
// See LOG.H for STRBUFSIZ value. The only check I know how
// to make is to strlen the format string. It not a fool-proof
// check but it's better than nothing...
//
// Arguments: [pszFmt] - Format to use for writing the string (printf-like)
// [pArgs] - Arguments to print
//
// Returns: NO_ERROR if successful
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// 16-Sep-92 SarahJ changed code to use _vsnprintf
// so that we allocate 1K first
// if that is too small then 32K
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: SetStrData(PCHAR pszFmt, va_list pArgs)
{
CHK_UNICODE(FALSE);
if (pszFmt == NULL || *pszFmt == NULLTERM)
{
NewString(&pszStrData, NULL);
}
else
{
//
// Start off by allocating 1K
//
PCHAR szTmpBuf = new CHAR[STDSTRBUFSIZ];
if (szTmpBuf == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
// note _vsnprintf returns -1 if szTmpBuf gets more than 1K
int iLen;
if ((iLen = _vsnprintf(szTmpBuf,
STDSTRBUFSIZ - 1,
pszFmt,
pArgs)) >= 0)
{
ulLastError = NewString(&pszStrData, (const char *)szTmpBuf);
}
else if (iLen == -1)
{
//
// So we have more than 1K data, so lets leap to allocating 32K
//
delete [] szTmpBuf;
szTmpBuf = new CHAR[HUGESTRBUFSIZ];
if (szTmpBuf == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else if ((iLen =_vsnprintf(szTmpBuf,
HUGESTRBUFSIZ - 1,
pszFmt,
pArgs)) >= 0)
{
ulLastError = NewString(&pszStrData,
(const char *) szTmpBuf);
}
else if (iLen == -1) //we have a ton of date - so truncate
{
strcpy(&szTmpBuf[HUGESTRBUFSIZ - STR_TRUNC_LEN - 2],
STR_TRUNCATION);
ulLastError = NewString(&pszStrData,
(const char *) szTmpBuf);
}
}
if (iLen < -1) // from either _vsnprintf
{
ulLastError = TOM_CORRUPT_LOG_DATA;
}
delete [] szTmpBuf;
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::SetStrData(LPWSTR, va_list)
//
// Synopsis: Set the string information that is to be logged.
//
// Effects: Create a temporary buffer for the formatted string, format
// the string and copy the new formated string to pszStrData.
// This version limits the formatted string to STRBUFSIZ chars.
// See LOG.H for STRBUFSIZ value. The only check I know how
// to make is to strlen the format string. It not a fool-proof
// check but it's better than nothing...
//
// Arguments: [wszFmt] - Format to use for writing the string (printf-like)
// [pArgs] - Arguments to print
//
// Returns: NO_ERROR if successful
//
// Modifies:
//
// History: ??-???-?? ???????? Created
// 16-Sep-92 SarahJ changed code to use _vsnprintf
// so that we allocate 1K first
// if that is too small then 32K
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: SetStrData(LPWSTR wszFmt, va_list pArgs)
{
CHK_UNICODE(TRUE);
if(wszFmt == NULL || *wszFmt == wNULLTERM)
{
NewString(&wszStrData, NULL);
}
else
{
//
// Start off by allocating 1K
//
LPWSTR wszTmpBuf = new WCHAR[STDSTRBUFSIZ];
if(wszTmpBuf == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
// note _vsnprintf returns -1 if szTmpBuf gets more than 1K
int iLen;
if((iLen = _vsnwprintf(wszTmpBuf, STDSTRBUFSIZ - 1,
wszFmt, pArgs))
>= 0)
{
ulLastError = NewString(&wszStrData, (LPCWSTR) wszTmpBuf);
}
else if(iLen == -1)
{
//
// So we have more than 1K data, so lets leap to allocating 32K
//
delete [] wszTmpBuf;
wszTmpBuf = new WCHAR[HUGESTRBUFSIZ];
if(wszTmpBuf == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else if((iLen = _vsnwprintf(wszTmpBuf, HUGESTRBUFSIZ-1,
wszFmt, pArgs))
>= 0)
{
ulLastError = NewString(&wszStrData,
(LPCWSTR) wszTmpBuf);
}
else if(iLen == -1) //we have a ton of date - so truncate
{
wcscpy(&wszTmpBuf[HUGESTRBUFSIZ - STR_TRUNC_LEN - 2],
wSTR_TRUNCATION);
ulLastError = NewString(&wszStrData, (LPCWSTR) wszTmpBuf);
}
}
if(iLen < -1) // from either _vsnwprintf
{
ulLastError = TOM_CORRUPT_LOG_DATA;
}
delete [] wszTmpBuf;
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::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 LOGCLASS :: CloseLogFile(VOID)
{
if(hLogFile != INVALID_HANDLE_VALUE)
{
LogEventCount();
if (ulLastError == NO_ERROR && SEEK_TO(FILE_END) != NO_ERROR)
{
ulLastError = GetLastError();
}
CloseHandle(hLogFile);
hLogFile = INVALID_HANDLE_VALUE;
}
if(FALSE == fIsUnicode)
{
SetLogFileName((PCHAR) NULL);
}
else
{
SetLogFileName((LPWSTR) NULL);
}
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::SetBinData(USHORT, PVOID)
//
// Synopsis: Given a buffer of binary data, copy it into the internal
// temp buffer.
//
// Arguments: [usBytes] - Number of bytes to transfer
// [pvData] - Pointer to data buffer
//
// Returns: NO_ERROR if successful
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
ULONG LOGCLASS :: SetBinData(USHORT usBytes, PVOID pvData)
{
if(pvBinData != NULL)
{
delete pvBinData;
pvBinData = NULL;
usBinLen = 0;
}
if(usBytes > 0 && pvData != NULL)
{
// Change to BYTE support WCHAR and CHAR transparently
// PUCHAR puchData = (PUCHAR)new CHAR[usBytes];
PBYTE pbData = new BYTE[usBytes];
if(pbData == NULL)
{
usBinLen = 0;
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
memcpy(pbData, pvData, (size_t)usBytes);
usBinLen = usBytes;
pvBinData = (PVOID)pbData;
ulLastError = NO_ERROR;
}
}
else if((usBytes > 0 && pvData == NULL)
|| (usBytes == 0 && pvData != NULL))
{
ulLastError = ERROR_INVALID_PARAMETER;
}
else
{
ulLastError = NO_ERROR;
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::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: NO_ERROR 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 LOGCLASS :: LogPrintf(HANDLE hHandle, PCHAR pszFmt, ...)
{
CHK_UNICODE(FALSE);
if(pszFmt == NULL || strlen(pszFmt) >= STDSTRBUFSIZ)
{
ulLastError = ERROR_INVALID_PARAMETER;
}
else
{
PCHAR szTmpBuf = new CHAR[STDSTRBUFSIZ];
if(szTmpBuf == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
va_list pMarker;
va_start(pMarker, pszFmt);
// On other error, return will be negative and not -1...
int nLen = _vsnprintf(szTmpBuf, STDSTRBUFSIZ - 1, pszFmt, pMarker);
// ...if -1 then buffer has more than STDSTRBUFSIZ chars in it,
// but we will not support more in this method - truncate.
if(nLen == -1)
{
nLen = (STDSTRBUFSIZ - 1) * sizeof(CHAR);
}
DWORD dwBytesWritten;
if(nLen >= 0)
{
if(FALSE == WriteFile(hHandle, (CONST LPVOID) szTmpBuf, nLen,
&dwBytesWritten, NULL))
{
ulLastError = NO_ERROR;
}
else
{
ulLastError = GetLastError();
}
}
else
{
ulLastError = ERROR_INVALID_PARAMETER;
}
delete szTmpBuf;
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::LogPrintf(HANDLE, LPWSTR, ...)
//
// 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: [hHandle] - Output File handle
// [wszFmt] - Format string for output
// [...] - Data to pass printf()
//
// Returns: NO_ERROR 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 LOGCLASS :: LogPrintf(HANDLE hHandle, LPWSTR wszFmt, ...)
{
CHK_UNICODE(TRUE);
if(wszFmt == NULL || wcslen(wszFmt) >= STDSTRBUFSIZ)
{
ulLastError = ERROR_INVALID_PARAMETER;
}
else
{
LPWSTR wszTmpBuf = new WCHAR[STDSTRBUFSIZ];
if(wszTmpBuf == NULL)
{
ulLastError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
va_list pMarker;
va_start(pMarker, wszFmt);
int nLen = _vsnwprintf(wszTmpBuf, STDSTRBUFSIZ - 1, wszFmt,
pMarker);
if(nLen == -1) // if -1 then buffer has STDSTRBUFSIZ char in it
{
nLen = (STDSTRBUFSIZ - 1) * sizeof(WCHAR);
}
DWORD dwBytesWritten;
if(nLen >= 0)
{
if(FALSE == WriteFile(hHandle, (CONST LPVOID) wszTmpBuf, nLen,
&dwBytesWritten, NULL))
{
ulLastError = NO_ERROR;
}
else
{
ulLastError = GetLastError();
}
}
else
{
ulLastError = ERROR_INVALID_PARAMETER;
}
delete wszTmpBuf;
}
}
return ulLastError;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::FlushLogFile(USHORT)
//
// Synopsis: This version checks if flushing was requested. If yes,
// the logging file is closed. The method simply retirns
// it's parameter which, in the calling code is the value
// of ulLastError.
//
// Arguments: [usErr] - Return value
//
// Returns: Whatever is passed as the first argument
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//------------------------------------------------------------------
ULONG LOGCLASS :: FlushLogFile(ULONG ulErr)
{
if(fFlushWrites != FALSE && hLogFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hLogFile);
hLogFile = INVALID_HANDLE_VALUE;
if(FALSE == fIsUnicode)
{
SetLogFileName((PCHAR) NULL);
}
else
{
SetLogFileName((LPWSTR) NULL);
}
fIsComPort = FALSE;
}
return ulErr;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::SetIsComPort(const char *)
//
// Synopsis: This version sets the element fIsComPort to TRUE if the
// given name is that of a COM port, else FALSE. This
// version checks if the given file name is "COMn*" where
// 'n' is a numerical value > 0.
//
// Arguments: [pszFileName] - The file name to test
//
// Returns: TRUE if it is a comm port, FALSE otherwise
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
BOOL LOGCLASS :: SetIsComPort(const char * pszFileName)
{
CHK_UNICODE(FALSE);
BOOL fRC = TRUE;
if ((pszFileName != NULL) &&
(*pszFileName != NULLTERM) &&
(_strnicmp(pszFileName, (const char *)"COM", 3) == SAME) &&
(strlen(pszFileName) > 3))
{
PCHAR cp = (PCHAR)&pszFileName[3];
// Make sure everything after COM is a digit
do
{
if (!isdigit(*cp))
{
fRC = FALSE;
}
} while (fRC && ++cp);
}
else
{
fRC = FALSE;
}
return(fRC);
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::SetIsComPort(LPCWSTR)
//
// Synopsis: This version sets the element fIsComPort to TRUE if the
// given name is that of a COM port, else FALSE. This
// version checks if the given file name is "COMn*" where
// 'n' is a numerical value > 0.
//
// Arguments: [wszFileName] - The file name to test
//
// Returns: TRUE if it is a comm port, FALSE otherwise
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
BOOL LOGCLASS :: SetIsComPort(LPCWSTR wszFileName)
{
CHK_UNICODE(TRUE);
BOOL fRC = TRUE;
if((wszFileName != NULL) && (*wszFileName != NULLTERM) &&
(_wcsnicmp(wszFileName, L"COM", 3) == SAME) &&
(wcslen(wszFileName) > 3))
{
LPWSTR cp = (LPWSTR) &wszFileName[3];
// Make sure everything after COM is a digit
do
{
if(!isdigit(*cp))
{
fRC = FALSE;
}
}
while(fRC && ++cp);
}
else
{
fRC = FALSE;
}
return fRC;
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS ::LogEventCount(VOID)
//
// Synopsis: This method causes the number of logged events that are
// in this file is written into this log file.
//
// Returns: <nothing>
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
void LOGCLASS :: LogEventCount()
{
if(TRUE == fIsUnicode)
{
wLogEventCount();
return;
}
CHAR chBuf[COUNT_BUFLEN];
int cLen = sprintf(chBuf, "%lu", ulEventCount);
//
// The event count needs to be padded so that as the count gets larger
// we can insert in the file without overwriting the next line
//
while(cLen < COUNT_BUFLEN - 1)
{
chBuf[cLen++] = ' ';
}
chBuf[COUNT_BUFLEN - 1] = NULLTERM;
WriteBinItem(LOG_EVENTS, (PVOID) chBuf, COUNT_BUFLEN - 1);
}
//+-------------------------------------------------------------------
//
// Member: LOGCLASS :: wLogEventCount(VOID)
//
// Synopsis: This method causes the number of logged events that are
// in this file is written into this log file.
//
// Returns: <nothing>
//
// Modifies:
//
// History: ??-???-?? ???????? Created
//
//--------------------------------------------------------------------
void LOGCLASS :: wLogEventCount()
{
CHK_UNICODE(TRUE);
WCHAR wchBuf[COUNT_BUFLEN];
int cLen = swprintf(wchBuf, L"%lu", ulEventCount);
//
// The event count needs to be padded so that as the count gets larger
// we can insert in the file without overwriting the next line
//
while(cLen < COUNT_BUFLEN - 1)
{
wchBuf[cLen++] = L' ';
}
wchBuf[COUNT_BUFLEN - 1] = wNULLTERM;
WriteBinItem(LOG_EVENTS, (PVOID) wchBuf,
(COUNT_BUFLEN - 1) * sizeof(WCHAR));
}