400 lines
9.4 KiB
C
400 lines
9.4 KiB
C
/*
|
|
* Module Name: WSFSLIB.C
|
|
*
|
|
* Library/DLL: Common library functions for handling working set tuner files.
|
|
*
|
|
*
|
|
* Description:
|
|
*
|
|
* Library routines called by the working set tuner programs to open and
|
|
* read working set tuner files. These functions may be useful to ISVs, etc.,
|
|
*
|
|
* This is an OS/2 2.x specific file
|
|
*
|
|
* IBM/Microsoft Confidential
|
|
*
|
|
* Copyright (c) IBM Corporation 1987, 1989
|
|
* Copyright (c) Microsoft Corporation 1987, 1989
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* Modification History:
|
|
*
|
|
* 03/26/90 - created
|
|
*
|
|
*/
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <windows.h>
|
|
#include <time.h>
|
|
#include <wserror.h>
|
|
#include <wsdata.h>
|
|
#include <wsfslib.h>
|
|
|
|
#define MAXLINE 128
|
|
|
|
|
|
BOOL fWsIndicator = FALSE;
|
|
|
|
/*
|
|
* Function declarations and prototypes.
|
|
*/
|
|
|
|
|
|
/*
|
|
*
|
|
***EP WsWSPOpen
|
|
*
|
|
* Effects:
|
|
*
|
|
* Opens a WSP file, and reads and validates the file header.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Returns 0. If an error is encountered, exits with ERROR via an
|
|
* indirect call through pfnExit.
|
|
*/
|
|
|
|
USHORT FAR PASCAL
|
|
WsWSPOpen( PSZ pszFileName, FILE **phFile, PFN pfnExit, wsphdr_t *pWspHdr,
|
|
INT iExitCode, INT iOpenPrintCode )
|
|
{
|
|
ULONG rc = NO_ERROR;
|
|
INT iRet = 0;
|
|
ULONG cbRead = 0;
|
|
size_t stRead = 0;
|
|
|
|
/* Open module's input WSP file. */
|
|
|
|
if ((*phFile = fopen(pszFileName, "rb")) == NULL)
|
|
{
|
|
iRet = (*pfnExit)(iExitCode, iOpenPrintCode, MSG_FILE_OPEN, rc,
|
|
pszFileName);
|
|
return((USHORT)iRet);
|
|
}
|
|
|
|
|
|
|
|
/* Read WSP file header. */
|
|
stRead = fread((PVOID) pWspHdr, (ULONG) sizeof(*pWspHdr),1, *phFile);
|
|
if(!stRead)
|
|
{
|
|
iRet = (*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_OPEN, rc,
|
|
pszFileName);
|
|
return((USHORT)iRet);
|
|
}
|
|
|
|
|
|
/* Read module pathname (directly follows file header). */
|
|
|
|
#ifdef DEBUG
|
|
printf("WspHdr (%s): ulTime 0x%lx, ulSnaps 0x%lx, OffBits 0x%lx\n",
|
|
// szModPath, pWspHdr->wsphdr_ulTimeStamp,
|
|
pszFileName, pWspHdr->wsphdr_ulTimeStamp, // mdg 4/98
|
|
pWspHdr->wsphdr_ulSnaps, pWspHdr->wsphdr_ulOffBits);
|
|
#endif /* DEBUG */
|
|
|
|
/* Validate the WSP file header. */
|
|
if (_strcmpi(pWspHdr->wsphdr_chSignature, "WSP"))
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_BAD_HDR, (ULONG)-1, pszFileName);
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
***EP WsTMIOpen
|
|
*
|
|
* Effects:
|
|
*
|
|
* Opens a TMI file, and reads and validates the file header.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Returns the number of records in the TMI file. If an error is
|
|
* encountered, exits with ERROR via an indirect call through pfnExit.
|
|
*/
|
|
|
|
ULONG FAR PASCAL
|
|
WsTMIOpen( PSZ pszFileName, FILE **phFile, PFN pfnExit, USHORT usId, PCHAR pch)
|
|
{
|
|
//ULONG ulTmp;
|
|
ULONG rc = NO_ERROR;
|
|
ULONG cbRead = 0;
|
|
ULONG cFxns = 0;
|
|
CHAR szLineTMI[MAXLINE]; // Line from TMI file
|
|
CHAR szTDFID[8]; // TDF Identifier string
|
|
ULONG ulTDFID = 0; // TDF Identifier
|
|
|
|
/* Open TMI file (contains function names, etc., in ASCII). */
|
|
|
|
if ((*phFile = fopen(pszFileName, "rt")) == NULL)
|
|
{
|
|
(*pfnExit)(NOEXIT, PRINT_MSG, MSG_FILE_OPEN, rc,
|
|
pszFileName);
|
|
return(MSG_FILE_OPEN);
|
|
}
|
|
|
|
/* Validate TMI file. */
|
|
if (fgets(szLineTMI, MAXLINE, *phFile) == NULL){
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
|
|
pszFileName);
|
|
}
|
|
// # fxns
|
|
if (fgets(szLineTMI, MAXLINE, *phFile) == NULL){
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
|
|
pszFileName);
|
|
}
|
|
szLineTMI[strlen(szLineTMI) - 1] = '\0';
|
|
if (sscanf(szLineTMI,"/* Total Symbols= %u */", &cFxns) != 1){
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
|
|
pszFileName);
|
|
}
|
|
// MODNAME
|
|
if (fgets(szLineTMI, MAXLINE, *phFile) == NULL)
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
|
|
pszFileName);
|
|
// MAJOR
|
|
if (fgets(szLineTMI, MAXLINE, *phFile) == NULL)
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
|
|
pszFileName);
|
|
// TDFID
|
|
if (fgets(szLineTMI, MAXLINE, *phFile) == NULL)
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
|
|
pszFileName);
|
|
if (sscanf(szLineTMI, "TDFID = %s", szTDFID) != 1)
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc,
|
|
pszFileName);
|
|
ulTDFID = strtoul(szTDFID, (char **) 0, 0);
|
|
|
|
/* Check identifier field */
|
|
|
|
if (ulTDFID != (ULONG) usId)
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_BAD_HDR, (ULONG)-1,
|
|
pszFileName);
|
|
|
|
return(cFxns);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
***EP WsTMIReadRec
|
|
*
|
|
* Effects:
|
|
*
|
|
* Reads a record from a TMI file, including the variable length function
|
|
* name.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Function size, in bytes, from this record. If an error is
|
|
* encountered, exits with ERROR via an indirect call through pfnExit.
|
|
*/
|
|
|
|
ULONG FAR PASCAL
|
|
WsTMIReadRec( PSZ *ppszFxnName, PULONG pulFxnIndex, PULONG pulFxnAddr,
|
|
FILE *hFile, PFN pfnExit, PCHAR pch)
|
|
{
|
|
ULONG rc;
|
|
ULONG cbFxn;
|
|
UINT uiFxnAddrObj; // object portion of function address
|
|
ULONG cbFxnName; // size in bytes of function name
|
|
// Read in function name, etc.
|
|
|
|
rc = fscanf(hFile, "%ld %x:%lx 0x%lx %ul", // mdg 98/4
|
|
pulFxnIndex, &uiFxnAddrObj, pulFxnAddr, &cbFxn,
|
|
&cbFxnName);
|
|
|
|
if (rc != 5)
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc, "TMI file");
|
|
|
|
*ppszFxnName = malloc( 1 + cbFxnName ); // Allocate space for function name
|
|
if (*ppszFxnName == NULL) // Abort if no mem
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_NO_MEM, 1 + cbFxnName, "TMI file");
|
|
rc = fgetc( hFile ); // Skip leading blank space
|
|
fgets( *ppszFxnName, cbFxnName + 1, hFile );
|
|
rc = fgetc( hFile );
|
|
if (rc != '\n' || strlen( *ppszFxnName ) != cbFxnName)
|
|
(*pfnExit)(ERROR, PRINT_MSG, MSG_FILE_READ, rc, "TMI file");
|
|
|
|
return(cbFxn);
|
|
}
|
|
|
|
LPVOID APIENTRY AllocAndLockMem(DWORD cbMem, HGLOBAL *hMem)
|
|
{
|
|
|
|
//
|
|
// Changed to GHND from GMEM_MOVABLE
|
|
//
|
|
*hMem = GlobalAlloc(GHND, cbMem);
|
|
|
|
if(!*hMem) {
|
|
return(NULL);
|
|
}
|
|
|
|
return(GlobalLock(*hMem));
|
|
}
|
|
|
|
BOOL APIENTRY UnlockAndFreeMem(HGLOBAL hMem)
|
|
{
|
|
BOOL fRet;
|
|
|
|
fRet = GlobalUnlock(hMem);
|
|
if (fRet) {
|
|
return(fRet);
|
|
}
|
|
|
|
if (!GlobalFree(hMem)) {
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
void
|
|
ConvertAppToOem( unsigned argc, char* argv[] )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts the command line from ANSI to OEM, and force the app
|
|
to use OEM APIs
|
|
|
|
Arguments:
|
|
|
|
argc - Standard C argument count.
|
|
|
|
argv - Standard C argument strings.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
unsigned i;
|
|
|
|
for( i=0; i<argc; i++ ) {
|
|
CharToOem( argv[i], argv[i] );
|
|
}
|
|
SetFileApisToOEM();
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
***EP WsIndicator
|
|
*
|
|
* Effects:
|
|
*
|
|
* Displays a progress indicator on the console. Doesn't use stdout which may be
|
|
* redirected.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* eFunc Description nVal
|
|
* WSINDF_NEW, Start new indicator Value of 100% limit
|
|
* WSINDF_PROGRESS, Set progress of current indicator Value of progress toward limit
|
|
* WSINDF_FINISH Mark indicator as finished -ignored-
|
|
* -invalid- Do nothing
|
|
*
|
|
* In all valid cases, pszLabel sets string to display before indicator. If NULL,
|
|
* uses last set string.
|
|
*
|
|
* Returns:
|
|
*
|
|
* Function size, in bytes, from this record. If an error is
|
|
* encountered, exits with ERROR via an indirect call through pfnExit.
|
|
*/
|
|
|
|
VOID FAR PASCAL
|
|
WsProgress( WsIndicator_e eFunc, const char *pszLbl, unsigned long nVal )
|
|
{
|
|
static unsigned long
|
|
nLimit = 0, nCurrent = 0;
|
|
static const char *
|
|
pszLabel = "";
|
|
static unsigned nLabelLen = 0;
|
|
static char bStarted = FALSE;
|
|
static unsigned nLastLen = 0;
|
|
static HANDLE hConsole = NULL;
|
|
DWORD pnChars;
|
|
|
|
switch (eFunc)
|
|
{
|
|
case WSINDF_NEW:
|
|
if (bStarted)
|
|
WsIndicator( WSINDF_FINISH, NULL, 0 );
|
|
bStarted = TRUE;
|
|
nLimit = nVal;
|
|
nCurrent = 0;
|
|
nLastLen = ~0; // Force redraw
|
|
WsIndicator ( WSINDF_PROGRESS, pszLbl, 0 );
|
|
break;
|
|
|
|
case WSINDF_PROGRESS:
|
|
if (!bStarted)
|
|
break;
|
|
if (pszLbl != NULL)
|
|
{
|
|
pszLabel = pszLbl;
|
|
nLabelLen = strlen( pszLabel );
|
|
}
|
|
if (nVal > nCurrent) // Compare to current progress (ignore reverses)
|
|
if (nVal <= nLimit)
|
|
nCurrent = nVal;
|
|
else
|
|
nCurrent = nLimit;
|
|
{ // Calculate an indicator string and print it
|
|
unsigned nLen = (unsigned) ((40.1 * (double)nCurrent) / nLimit);
|
|
char * pszBuf;
|
|
|
|
if (nLastLen == nLen) // Optimization - Don't redraw if result would be the same
|
|
{
|
|
if (pszLbl == NULL)
|
|
break;
|
|
}
|
|
else
|
|
nLastLen = nLen;
|
|
if (hConsole == NULL)
|
|
{
|
|
hConsole = CreateFile( "CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
|
|
if (hConsole == NULL) // Couldn't get the console for some reason?
|
|
break;
|
|
}
|
|
WriteConsole( hConsole, "\r", 1, &pnChars, NULL );
|
|
WriteConsole( hConsole, pszLabel, nLabelLen, &pnChars, NULL );
|
|
WriteConsole( hConsole, " ", 1, &pnChars, NULL );
|
|
pszBuf = malloc( nLen + 1 );
|
|
if (pszBuf == NULL) // No memory? Oh, well...
|
|
break;
|
|
memset( pszBuf, '-', nLen );
|
|
pszBuf[nLen] = '\0';
|
|
WriteConsole( hConsole, pszBuf, nLen, &pnChars, NULL );
|
|
free( pszBuf);
|
|
}
|
|
break;
|
|
|
|
case WSINDF_FINISH:
|
|
if (!bStarted)
|
|
break;
|
|
WsIndicator( WSINDF_PROGRESS, pszLbl, nLimit );
|
|
if (hConsole != NULL)
|
|
{
|
|
WriteConsole( hConsole, "\n", 1, &pnChars, NULL );
|
|
CloseHandle( hConsole );
|
|
hConsole = NULL;
|
|
}
|
|
bStarted = FALSE;
|
|
}
|
|
}
|
|
|
|
|