//############################################################################ //# //# 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 #include #include #include #include #include #define __CRC32__ #include "w4ctsupp.hxx" #include //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 }