590 lines
18 KiB
C++
590 lines
18 KiB
C++
//############################################################################
|
|
//#
|
|
//# Microsoft Windows
|
|
//# Copyright (C) Microsoft Corporation, 1992 - 1992.
|
|
//# All rights reserved.
|
|
//#
|
|
//############################################################################
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
// File: W4CTSUPP.CXX
|
|
//
|
|
// Contents: Contains support functions for docfile testing
|
|
//
|
|
// Command line: N/A
|
|
//
|
|
// Requires: must be linked with program containing function main()
|
|
//
|
|
// Notes: Compiled to create W4CTSUPP.LIB
|
|
//
|
|
// Created: RichE March 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <direct.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
|
|
#define __CRC32__
|
|
#include "w4ctsupp.hxx"
|
|
|
|
#include <dfdeb.hxx>
|
|
|
|
//char for separating FAT file name from extension
|
|
#define FILE_NAME_SEPARATOR '.'
|
|
|
|
//global array of interesting file sizes for IStream read/writes
|
|
USHORT ausSIZE_ARRAY[] = {0,1,2,255,256,257,511,512,513,2047,2048,2049,4095,4096,4097};
|
|
|
|
//test logging file pointer
|
|
static FILE *fileLogFile = NULL;
|
|
|
|
//should log be closed after every log write, modified by SetDebugMode()
|
|
static BOOL fCloseLogAfterWrite = FALSE;
|
|
|
|
//test name string for ErrExit and application use
|
|
char szTestName[MAX_TEST_NAME_LEN + 1] = "No Test Name Specified";
|
|
|
|
//random number seed used by test apps
|
|
USHORT usRandomSeed = 0;
|
|
|
|
//routing variable for standard out in tprintf and ErrExit calls
|
|
//can be changed from default of DEST_OUT
|
|
BYTE bDestOut = DEST_OUT;
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: Allocate, public
|
|
//
|
|
// Synopsis: allocate memory, exit with error if malloc failes
|
|
//
|
|
// Arguments: [cbBytesToAllocate] - size of memory block to allocate
|
|
//
|
|
// Returns: void pointer to block of memory allocated
|
|
//
|
|
// Created: RichE March 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void *Allocate(size_t cbBytesToAllocate)
|
|
{
|
|
void *pvMemPtr;
|
|
|
|
pvMemPtr = (void *) malloc(cbBytesToAllocate);
|
|
if(pvMemPtr == NULL)
|
|
{
|
|
ErrExit(DEST_ERR, ERR, "Unable to allocate %u bytes of memory\n",
|
|
cbBytesToAllocate);
|
|
}
|
|
|
|
return pvMemPtr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: MakePath, public
|
|
//
|
|
// Synopsis: makes a sub-directory at end of specified path
|
|
//
|
|
// Effects: For each char in pszDirToMake, if it's a '\', make the destination
|
|
// directory at the level accumulated in pszPathBuf, else append
|
|
// the next letter of the dest path to pszPathBuf. After the loop,
|
|
// attempt to _mkdir a final time (since the path probably won't
|
|
// end with a '\').
|
|
//
|
|
// Arguments: [pszDirToMake] - full directory path name to make
|
|
//
|
|
// Returns: TRUE if all directories in path were made OK, otherwise FALSE
|
|
//
|
|
// Created: RichE January 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL MakePath(char *pszDirToMake)
|
|
{
|
|
#ifdef DBCS
|
|
char *pszDirToMakeSav = pszDirToMake;
|
|
#endif
|
|
char *pcDestPathSoFar;
|
|
char *pszPathBuf;
|
|
int iRc;
|
|
|
|
pszPathBuf = (char *) Allocate(_MAX_PATH + 1);
|
|
pcDestPathSoFar = pszPathBuf;
|
|
|
|
//
|
|
//while not at end of path string, if this char is a back slash, make
|
|
//the directory up to the slash. in either case, copy the next char
|
|
//into the accumulated path buffer.
|
|
//
|
|
|
|
while (*pszDirToMake)
|
|
{
|
|
if (*pszDirToMake == '\\')
|
|
{
|
|
*pcDestPathSoFar = NIL;
|
|
iRc = _mkdir(pszPathBuf);
|
|
tprintf(bDestOut, "Trying to make directory %s, returned %d\n",
|
|
pszPathBuf, iRc);
|
|
}
|
|
#ifdef DBCS
|
|
#ifdef _MAC
|
|
if (iskanji (*pszDirToMake)) // iskanji is in dbcsutil.cpp
|
|
#else
|
|
if (IsDBCSLeadbyte (*pszDirToMake))
|
|
#endif
|
|
*pcDestPathSoFar++ = *pszDirToMake++;
|
|
#endif
|
|
*pcDestPathSoFar++ = *pszDirToMake++;
|
|
}
|
|
|
|
//
|
|
//if the last char wasn't a back slash, the last part of the path hasn't
|
|
//been made so make it.
|
|
//
|
|
#ifdef DBCS
|
|
#ifdef _MAC
|
|
DecLpch (pszDirToMakeSav, pszDirToMake);
|
|
#else
|
|
pszDirToMake = AnsiPrev (pszDirToMakeSav, pszDirToMake);
|
|
#endif // MAC
|
|
if (*pszDirToMake != '\\')
|
|
#else
|
|
if (*(--pszDirToMake) != '\\')
|
|
#endif
|
|
{
|
|
*pcDestPathSoFar = NIL;
|
|
iRc = _mkdir(pszPathBuf);
|
|
tprintf(bDestOut, "Trying to make directory %s, returned %d\n",
|
|
pszPathBuf, iRc);
|
|
}
|
|
|
|
free(pszPathBuf);
|
|
|
|
return (iRc == 0) ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: SetDebugMode, public
|
|
//
|
|
// Synopsis: sets debugging mode and program exit control and tprintf routing
|
|
//
|
|
// Effects: Sets exit control to 'no exit when complete.' depending upon
|
|
// the char passed, in calls debug macro to set appropriate
|
|
// debug mode. If no debug is specified, sets program exit
|
|
// control to 'exit when complete' and sets flag to close log
|
|
// file after every log write. If a debug mode other than
|
|
// none is specified, redirects default output destination to
|
|
// DEST_LOG instead of DEST_OUT. Also sets capture buffer to
|
|
// unlimited size
|
|
//
|
|
// Arguments: [DebugMode] - single character representing desired mode
|
|
//
|
|
// Modifiles: [fCloseLogAfterWrite] - if running in non-debug mode, close
|
|
// log file after every write
|
|
//
|
|
// Created: RichE April 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SetDebugMode(char DebugMode)
|
|
{
|
|
SET_DISPLAY_BUF_SIZE;
|
|
|
|
NO_EXIT_WHEN_DONE;
|
|
|
|
switch(DebugMode)
|
|
{
|
|
case 'a':
|
|
DEBUG_ALL;
|
|
bDestOut = DEST_LOG;
|
|
break;
|
|
|
|
case 'n':
|
|
DEBUG_NONE;
|
|
EXIT_WHEN_DONE;
|
|
//fCloseLogAfterWrite = TRUE;
|
|
break;
|
|
|
|
case 'd':
|
|
DEBUG_DOCFILE;
|
|
bDestOut = DEST_LOG;
|
|
break;
|
|
|
|
case 'm':
|
|
DEBUG_MSF;
|
|
bDestOut = DEST_LOG;
|
|
break;
|
|
|
|
case 'i':
|
|
default:
|
|
DEBUG_INTERNAL_ERRORS;
|
|
bDestOut = DEST_LOG;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: ErrExit, public
|
|
//
|
|
// Synopsis: allows error output to any combo of stdout, stderr, and logfile
|
|
//
|
|
// Effects: depending upon flags passed in, will display (via vfprintf)
|
|
// error output to any combination of stdout, stderr, and a user-
|
|
// supplied log file. if output destination is a log file,
|
|
// will open the log file if not already open and set
|
|
// all output to the error output destination as well.
|
|
// prints docfile error message based on error code, or
|
|
// generic error message is error is undefined. prints error
|
|
// return code, prints FAIL message using extern global [szTestName]
|
|
// (defined in calling test) and exits with error code.
|
|
//
|
|
// Arguments: [bOutputDest] - bit flags specifying where output goes
|
|
// valid flags defined in W4CTSUPP.HXX
|
|
// [ErrCode] - error code to use in exit() function
|
|
// [fmt] - vfprintf formatting string
|
|
// [...] - parameters to vfprintf function
|
|
//
|
|
// Created: RichE March 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void ErrExit(BYTE bOutputDest, SCODE ErrCode, char *fmt, ...)
|
|
{
|
|
USHORT iErrIndex = 0;
|
|
|
|
struct
|
|
{
|
|
SCODE scErrCode;
|
|
char *pszErrMessage;
|
|
} aszErrMessages[] = {S_FALSE, "S_FALSE",
|
|
STG_E_INVALIDFUNCTION, "STG_E_INVALIDFUNCTION",
|
|
STG_E_FILENOTFOUND, "STG_E_FILENOTFOUND",
|
|
STG_E_TOOMANYOPENFILES, "STG_E_TOOMANYOPENFILES",
|
|
STG_E_ACCESSDENIED, "STG_E_ACCESSDENIED",
|
|
STG_E_INVALIDHANDLE, "STG_E_INVALIDHANDLE",
|
|
STG_E_INSUFFICIENTMEMORY, "STG_E_INSUFFICIENTMEMORY",
|
|
STG_E_INVALIDPOINTER, "STG_E_INVALIDPOINTER",
|
|
STG_E_NOMOREFILES, "STG_E_NOMOREFILES",
|
|
STG_E_WRITEFAULT, "STG_E_WRITEFAULT",
|
|
STG_E_READFAULT, "STG_E_READFAULT",
|
|
STG_E_LOCKVIOLATION, "STG_E_LOCKVIOLATION",
|
|
STG_E_FILEALREADYEXISTS, "STG_E_FILEALREADYEXISTS",
|
|
STG_E_INVALIDPARAMETER, "STG_E_INVALIDPARAMETER",
|
|
STG_E_MEDIUMFULL, "STG_E_MEDIUMFULL",
|
|
STG_E_ABNORMALAPIEXIT, "STG_E_ABNORMALAPIEXIT",
|
|
STG_E_INVALIDHEADER, "STG_E_INVALIDHEADER",
|
|
STG_E_INVALIDNAME, "STG_E_INVALIDNAME",
|
|
STG_E_UNKNOWN, "STG_E_UNKNOWN",
|
|
STG_E_UNIMPLEMENTEDFUNCTION, "STG_E_UNIMPLEMENTEDFUNCTION",
|
|
STG_E_INVALIDFLAG, "STG_E_INVALIDFLAG",
|
|
STG_E_INUSE, "STG_E_INUSE",
|
|
STG_E_NOTCURRENT, "STG_E_NOTCURRENT",
|
|
STG_E_REVERTED, "STG_E_REVERTED",
|
|
STG_S_CONVERTED, "STG_S_CONVERTED",
|
|
ERR, "GENERIC_ERROR"
|
|
};
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
//if dest is log file, open log file if not already open
|
|
//and set all output to DEST_ERR as well.
|
|
if (bOutputDest & DEST_LOG)
|
|
{
|
|
bOutputDest |= DEST_ERR;
|
|
|
|
if (fileLogFile == NULL)
|
|
{
|
|
LogFile(NULL, LOG_OPEN);
|
|
}
|
|
|
|
vfprintf(fileLogFile, fmt, args);
|
|
|
|
if (fCloseLogAfterWrite == TRUE)
|
|
{
|
|
LogFile(NULL, LOG_CLOSE);
|
|
}
|
|
}
|
|
|
|
if (bOutputDest & DEST_OUT)
|
|
{
|
|
vfprintf(stdout, fmt, args);
|
|
}
|
|
|
|
if (bOutputDest & DEST_ERR)
|
|
{
|
|
vfprintf(stderr, fmt, args);
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
tprintf(bOutputDest, "Return code %lu (0x%08lX), ", ErrCode, ErrCode);
|
|
|
|
//lookup error in struct table and print error message
|
|
while (aszErrMessages[iErrIndex].scErrCode != ErrCode)
|
|
{
|
|
if (aszErrMessages[iErrIndex].scErrCode == ERR)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
iErrIndex++;
|
|
}
|
|
}
|
|
|
|
tprintf(bOutputDest, "%s\n", aszErrMessages[iErrIndex].pszErrMessage);
|
|
|
|
tprintf(bOutputDest, "FAIL: %s\n", szTestName);
|
|
|
|
exit((int) ErrCode);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: tprintf, public
|
|
//
|
|
// Synopsis: allows output to any combo of stdout, stderr, and logfile
|
|
//
|
|
// Effects: depending upon flags passed in, will display (via vfprintf)
|
|
// output to any combination of stdout, stderr, and a user-
|
|
// supplied log file. if output destination is a log file,
|
|
// will open the log file if not already open and set
|
|
// all output to the error output destination as well.
|
|
//
|
|
// Arguments: [bOutputDest] - bit flags specifying where output goes
|
|
// valid flags defined in W4CTSUPP.HXX
|
|
// [fmt] - vfprintf formatting string
|
|
// [...] - parameters to vfprintf function
|
|
//
|
|
// Created: RichE March 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void tprintf(BYTE bOutputDest, char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
//if dest is log file, open log file if not already open
|
|
//and set all output to DEST_ERR as well.
|
|
if (bOutputDest & DEST_LOG)
|
|
{
|
|
bOutputDest |= DEST_ERR;
|
|
|
|
if (fileLogFile == NULL)
|
|
{
|
|
LogFile(NULL, LOG_OPEN);
|
|
}
|
|
|
|
vfprintf(fileLogFile, fmt, args);
|
|
|
|
if (fCloseLogAfterWrite == TRUE)
|
|
{
|
|
LogFile(NULL, LOG_CLOSE);
|
|
}
|
|
}
|
|
|
|
if (bOutputDest & DEST_OUT)
|
|
{
|
|
vfprintf(stdout, fmt, args);
|
|
}
|
|
|
|
if (bOutputDest & DEST_ERR)
|
|
{
|
|
vfprintf(stderr, fmt, args);
|
|
}
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: LogFile, public
|
|
//
|
|
// Synopsis: opens or closed specified file for logging via tprintf and errexit
|
|
//
|
|
// Effects: the specfied file is opened via fopen for logging purposes when
|
|
// [bLogFileAction] = LOG_OPEN and closed for LOG_CLOSE. The
|
|
// calling application should open the LogFile via a LOG_INIT
|
|
// call which will define the routine to call to ensure that the
|
|
// log file is closed upon completion and set the log file name.
|
|
//
|
|
// Modifies: [fileLogFile] - the global variable defined at top of this file
|
|
// will contain a pointer to the log file stream on exit.
|
|
//
|
|
// Arguments: [pszLogFileName] - pathname of file for logging purposes
|
|
// [bLogFileAction] - whether to open or close the log file
|
|
//
|
|
// Notes: [pszLogReOpenName] is the filename to use for opening the log
|
|
// file. In non-debug runs, the log file is closed after every
|
|
// log write and re-opened before the next write.
|
|
//
|
|
// Created: RichE March 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void LogFile(char *pszLogFileName, BYTE bLogFileAction)
|
|
{
|
|
static char *pszLogReOpenName = NULL;
|
|
static BOOL fFirstInitCall = FALSE;
|
|
char *pszTestDataDir;
|
|
|
|
switch (bLogFileAction)
|
|
{
|
|
case LOG_INIT:
|
|
if (pszLogFileName == NULL)
|
|
{
|
|
ErrExit(DEST_ERR, ERR, "No filename specified for LOG_INIT\n");
|
|
}
|
|
|
|
if (fileLogFile != NULL)
|
|
{
|
|
fclose(fileLogFile);
|
|
free(pszLogReOpenName);
|
|
}
|
|
|
|
pszLogReOpenName = (char *) Allocate(strlen(pszLogFileName)+1);
|
|
strcpy(pszLogReOpenName, pszLogFileName);
|
|
|
|
if (fFirstInitCall == FALSE)
|
|
{
|
|
//register function to call on program exit
|
|
//
|
|
|
|
atexit(MakeSureThatLogIsClosed);
|
|
fFirstInitCall = TRUE;
|
|
|
|
//
|
|
//change to dir specified by DFDATA env variable, if it's set
|
|
//
|
|
|
|
if (pszTestDataDir = getenv("DFDATA"))
|
|
{
|
|
_chdir(pszTestDataDir);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LOG_OPEN:
|
|
if (fileLogFile != NULL)
|
|
{
|
|
ErrExit(DEST_ERR,ERR,"Can't open log file %s, log is already open!",
|
|
pszLogReOpenName);
|
|
}
|
|
|
|
if (pszLogReOpenName == NULL)
|
|
{
|
|
pszLogReOpenName = (char *) Allocate(strlen(LOG_DEFAULT_NAME)+1);
|
|
strcpy(pszLogReOpenName, LOG_DEFAULT_NAME);
|
|
}
|
|
|
|
if ((fileLogFile = fopen(pszLogReOpenName, "w")) == NULL)
|
|
{
|
|
ErrExit(DEST_ERR, ERR, "Error opening log file %s\n",
|
|
pszLogReOpenName);
|
|
}
|
|
|
|
break;
|
|
|
|
case LOG_CLOSE:
|
|
if (fileLogFile != NULL)
|
|
{
|
|
fflush(fileLogFile);
|
|
fclose(fileLogFile);
|
|
}
|
|
else
|
|
{
|
|
tprintf(DEST_ERR,"Warning: can't close log file %s, log isn't open!",
|
|
pszLogReOpenName);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
ErrExit(DEST_ERR,ERR,"Invalid parameter to LogFile() function!");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: MakeSureThatLogFileIsClosed
|
|
//
|
|
// Synopsis: closes log file on exit
|
|
//
|
|
// Effects: immediately flushes all file buffers, and then calls Logfile to
|
|
// close the test log file. upon abnormal exit (GP fault), this saves most
|
|
// of the log information.
|
|
//
|
|
// Created: RichE March 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MakeSureThatLogIsClosed(void)
|
|
{
|
|
//fflush(fileLogFile);
|
|
LogFile(NULL, LOG_CLOSE);
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: MakeSingle, public
|
|
//
|
|
// Synopsis: converts TCHAR string to single character string
|
|
//
|
|
// Arguments: [pszSingleName] - pointer to TCHAR string
|
|
// [ptcsWideName] - buffer to hold returned single-wide string
|
|
//
|
|
// Modifies: [pszSingleName] - on exit holds single-wide character string
|
|
//
|
|
// Created: RichE March 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MakeSingle(char *pszSingleName, TCHAR *ptcsWideName)
|
|
{
|
|
#ifdef UNICODE
|
|
USHORT cusBufLen = (tcslen(ptcsWideName)+1) * sizeof(TCHAR);
|
|
|
|
if (_fwcstombs(pszSingleName, ptcsWideName, cusBufLen) == -1)
|
|
{
|
|
ErrExit(DEST_LOG, ERR, "Error converting TCHAR string to single wide\n");
|
|
}
|
|
#else
|
|
strcpy(pszSingleName, ptcsWideName);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Function: MakeWide, public
|
|
//
|
|
// Synopsis: converts single character string to multi-byte (TCHAR) string
|
|
//
|
|
// Arguments: [ptcsWideName] - buffer to hold returned TCHAR string
|
|
// [pszSingleName] - pointer to single wide string
|
|
//
|
|
// Modifies: [ptcsWideName] - on exit holds wide character string
|
|
//
|
|
// Created: RichE March 1992
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void MakeWide(TCHAR *ptcsWideName, char *pszSingleName)
|
|
{
|
|
#ifdef UNICODE
|
|
USHORT cusBufLen = (strlen(pszSingleName)+1) * sizeof(TCHAR);
|
|
|
|
if (_fmbstowcs(ptcsWideName, pszSingleName, cusBufLen) == -1)
|
|
{
|
|
ErrExit(DEST_LOG, ERR, "Error converting name %s to TCHAR string\n", pszSingleName);
|
|
}
|
|
#else
|
|
strcpy(ptcsWideName, pszSingleName);
|
|
#endif
|
|
}
|