Files
mars-flaim/xflaim/util/sharutil.cpp
2006-05-19 19:45:40 +00:00

2083 lines
46 KiB
C++

//------------------------------------------------------------------------------
// Desc: Shared utility routines
//
// Tabs: 3
//
// Copyright (c) 1997-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: sharutil.cpp 3129 2006-01-25 11:46:17 -0700 (Wed, 25 Jan 2006) ahodgkinson $
//------------------------------------------------------------------------------
#include "flaimsys.h"
#include "sharutil.h"
FSTATIC FTX_WINDOW * wpsGetThrdWin( void);
FINLINE void wpsLock(
F_MUTEX * phMutex)
{
f_mutexLock( *phMutex);
}
FINLINE void wpsUnlock(
F_MUTEX * phMutex)
{
f_mutexUnlock( *phMutex);
}
static FLMBOOL gv_bShutdown = FALSE;
static FLMBOOL gv_bInitialized = FALSE;
static FLMBOOL gv_bOptimize = FALSE;
static WPSSCREEN * gv_pScreenList = NULL;
static F_MUTEX gv_hDispMutex = F_MUTEX_NULL;
FSTATIC RCODE propertyExists(
char * pszProperty,
char * pszBuffer,
char ** ppszValue);
FSTATIC RCODE _flmWrapperFunc(
IF_Thread * pThread);
/********************************************************************
Desc: Parses command-line parameters
*********************************************************************/
void flmUtilParseParams(
char * pszCommandBuffer,
FLMINT iMaxArgs,
FLMINT * iArgcRV,
char ** ppArgvRV)
{
FLMINT iArgC = 0;
for (;;)
{
/* Strip off leading white space. */
while ((*pszCommandBuffer == ' ') || (*pszCommandBuffer == '\t'))
pszCommandBuffer++;
if (!(*pszCommandBuffer))
break;
if ((*pszCommandBuffer == '"') || (*pszCommandBuffer == '\''))
{
char cQuoteChar = *pszCommandBuffer;
pszCommandBuffer++;
ppArgvRV [iArgC] = pszCommandBuffer;
iArgC++;
while ((*pszCommandBuffer) && (*pszCommandBuffer != cQuoteChar))
pszCommandBuffer++;
if (*pszCommandBuffer)
*pszCommandBuffer++ = 0;
}
else
{
ppArgvRV [iArgC] = pszCommandBuffer;
iArgC++;
while ((*pszCommandBuffer) &&
(*pszCommandBuffer != ' ') &&
(*pszCommandBuffer != '\t'))
pszCommandBuffer++;
if (*pszCommandBuffer)
*pszCommandBuffer++ = 0;
}
/* Quit if we have reached the maximum allowable number of arguments. */
if (iArgC == iMaxArgs)
break;
}
*iArgcRV = iArgC;
}
/****************************************************************************
Name: FlmVector::setElementAt
Desc: a vector set item operation.
****************************************************************************/
#define FLMVECTOR_START_AMOUNT 16
#define FLMVECTOR_GROW_AMOUNT 2
RCODE FlmVector::setElementAt( void * pData, FLMUINT uiIndex)
{
RCODE rc = NE_XFLM_OK;
if ( !m_pElementArray)
{
TEST_RC( rc = f_calloc( sizeof( void*) * FLMVECTOR_START_AMOUNT,
&m_pElementArray));
m_uiArraySize = FLMVECTOR_START_AMOUNT;
}
if ( uiIndex >= m_uiArraySize)
{
TEST_RC( rc = f_recalloc(
sizeof( void*) * m_uiArraySize * FLMVECTOR_GROW_AMOUNT,
&m_pElementArray));
m_uiArraySize *= FLMVECTOR_GROW_AMOUNT;
}
m_pElementArray[ uiIndex] = pData;
Exit:
return rc;
}
/****************************************************************************
Name: FlmVector::getElementAt
Desc: a vector get item operation
****************************************************************************/
void * FlmVector::getElementAt( FLMUINT uiIndex)
{
//if you hit this you are indexing into the vector out of bounds.
//unlike a real array, we can catch this here! oh joy!
flmAssert ( uiIndex < m_uiArraySize);
return m_pElementArray[ uiIndex];
}
/****************************************************************************
Name: FlmStringAcc::appendCHAR
Desc: append a char (or the same char many times) to the string
****************************************************************************/
RCODE FlmStringAcc::appendCHAR( char ucChar, FLMUINT uiHowMany)
{
RCODE rc = NE_XFLM_OK;
if ( uiHowMany == 1)
{
FLMBYTE szStr[ 2];
szStr[ 0] = ucChar;
szStr[ 1] = 0;
rc = this->appendTEXT( (const FLMBYTE*)szStr);
}
else
{
FLMBYTE * pszStr;
if( RC_BAD( rc = f_alloc( uiHowMany + 1, &pszStr)))
{
goto Exit;
}
f_memset( pszStr, ucChar, uiHowMany);
pszStr[ uiHowMany] = 0;
rc = this->appendTEXT( pszStr);
f_free( &pszStr);
}
Exit:
return rc;
}
/****************************************************************************
Name: FlmStringAcc::appendTEXT
Desc: appending text to the accumulator safely. all other methods in
the class funnel through this one, as this one contains the logic
for making sure storage requirements are met.
****************************************************************************/
RCODE FlmStringAcc::appendTEXT( const FLMBYTE * pszVal)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiIncomingStrLen;
FLMUINT uiStrLen;
//be forgiving if they pass in a NULL
if ( !pszVal)
{
goto Exit;
}
//also be forgiving if they pass a 0-length string
else if( (uiIncomingStrLen = f_strlen( (const char *)pszVal)) == 0)
{
goto Exit;
}
//compute total size we need to store the new total
if ( m_bQuickBufActive || m_pszVal)
{
uiStrLen = uiIncomingStrLen + m_uiValStrLen;
}
else
{
uiStrLen = uiIncomingStrLen;
}
//just use small buffer if it's small enough
if ( uiStrLen < FSA_QUICKBUF_BUFFER_SIZE)
{
f_strcat( m_szQuickBuf, (const char *)pszVal);
m_bQuickBufActive = TRUE;
}
//we are exceeding the quickbuf size, so get the bytes from the heap
else
{
//ensure storage requirements are met (and then some)
if ( m_pszVal == NULL)
{
FLMUINT uiNewBytes = (uiStrLen+1) * 4;
if ( RC_OK ( rc = f_alloc(
(FLMUINT)(sizeof( FLMBYTE) * uiNewBytes),
&m_pszVal)))
{
m_uiBytesAllocatedForPszVal = uiNewBytes;
m_pszVal[ 0] = 0;
}
else
{
goto Exit;
}
}
else if ( (m_uiBytesAllocatedForPszVal-1) < uiStrLen)
{
FLMUINT uiNewBytes = (uiStrLen+1) * 4;
if ( RC_OK( rc = f_realloc(
(FLMUINT)(sizeof( FLMBYTE) * uiNewBytes),
&m_pszVal)))
{
m_uiBytesAllocatedForPszVal = uiNewBytes;
}
else
{
goto Exit;
}
}
//if transitioning from quick buf to heap buf, we need to
//transfer over the quick buf contents and unset the flag
if ( m_bQuickBufActive)
{
m_bQuickBufActive = FALSE;
f_strcpy( m_pszVal, m_szQuickBuf);
//no need to zero out m_szQuickBuf because it will never
//be used again, unless a clear() is issued, in which
//case it will be zeroed out then.
}
//copy over the string
f_strcat( m_pszVal, (const char *)pszVal);
}
m_uiValStrLen = uiStrLen;
Exit:
return rc;
}
/****************************************************************************
Desc: printf into the FlmStringAcc
****************************************************************************/
RCODE FlmStringAcc::printf(
const char * pszFormatString,
...)
{
f_va_list args;
char * pDestStr = NULL;
FLMSIZET iSize = 4096;
RCODE rc = NE_XFLM_OK;
if( RC_BAD( rc = f_alloc( iSize, &pDestStr)))
{
goto Exit;
}
f_va_start( args, pszFormatString);
f_vsprintf( pDestStr, pszFormatString, &args);
f_va_end( args);
this->clear();
TEST_RC( rc = this->appendTEXT( (FLMBYTE *)pDestStr));
Exit:
if ( pDestStr)
{
f_free( &pDestStr);
}
return rc;
}
/****************************************************************************
Desc: formatted appender like sprintf
****************************************************************************/
RCODE FlmStringAcc::appendf(
const char * pszFormatString,
...)
{
f_va_list args;
char * pDestStr = NULL;
FLMSIZET iSize = 4096;
RCODE rc = NE_XFLM_OK;
if( RC_BAD( rc = f_alloc( iSize, &pDestStr)))
{
goto Exit;
}
f_va_start( args, pszFormatString);
f_vsprintf( pDestStr, pszFormatString, &args);
f_va_end( args);
TEST_RC( rc = this->appendTEXT( (FLMBYTE *)pDestStr));
Exit:
if ( pDestStr)
{
f_free( &pDestStr);
}
return rc;
}
/****************************************************************************
Desc: Constructor
*****************************************************************************/
FlmContext::FlmContext()
{
m_szCurrDir[ 0] = '\0';
m_hMutex = F_MUTEX_NULL;
m_bIsSetup = FALSE;
}
/****************************************************************************
Desc: Destructor
*****************************************************************************/
FlmContext::~FlmContext( void)
{
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &m_hMutex);
m_hMutex = F_MUTEX_NULL;
}
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmContext::setup(
FLMBOOL bShared)
{
RCODE rc = NE_XFLM_OK;
if( bShared)
{
if( RC_BAD( rc = f_mutexCreate( &m_hMutex)))
{
goto Exit;
}
}
m_bIsSetup = TRUE;
Exit:
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmContext::setCurrDir(
FLMBYTE * pszCurrDir)
{
RCODE rc = NE_XFLM_OK;
flmAssert( m_bIsSetup);
lock();
f_strcpy( (char *)m_szCurrDir, (const char *)pszCurrDir);
unlock();
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmContext::getCurrDir(
FLMBYTE * pszCurrDir)
{
RCODE rc = NE_XFLM_OK;
flmAssert( m_bIsSetup);
lock();
f_strcpy( (char *)pszCurrDir, (const char *)m_szCurrDir);
unlock();
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
void FlmContext::lock( void)
{
flmAssert( m_bIsSetup);
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
}
}
/****************************************************************************
Desc:
*****************************************************************************/
void FlmContext::unlock( void)
{
flmAssert( m_bIsSetup);
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexUnlock( m_hMutex);
}
}
/****************************************************************************
Desc:
*****************************************************************************/
FlmThreadContext::FlmThreadContext( void)
{
m_pScreen = NULL;
m_pWindow = NULL;
m_bShutdown = FALSE;
m_pLocalContext = NULL;
m_pSharedContext = NULL;
m_pNext = NULL;
m_pPrev = NULL;
m_uiID = 0;
m_hMutex = F_MUTEX_NULL;
m_pThrdFunc = NULL;
m_pvAppData = NULL;
m_pThread = NULL;
m_bFuncExited = FALSE;
}
/****************************************************************************
Desc:
*****************************************************************************/
FlmThreadContext::~FlmThreadContext( void)
{
// Free the local context
if( m_pLocalContext)
{
m_pLocalContext->Release();
}
// Destroy the semaphore
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &m_hMutex);
}
}
/****************************************************************************
Desc:
*****************************************************************************/
void FlmThreadContext::lock( void)
{
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
}
}
/****************************************************************************
Desc:
*****************************************************************************/
void FlmThreadContext::unlock( void)
{
if( m_hMutex != F_MUTEX_NULL)
{
f_mutexUnlock( m_hMutex);
}
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmThreadContext::setup(
FlmSharedContext * pSharedContext,
const char * pszThreadName,
THREAD_FUNC_p pFunc,
void * pvAppData)
{
RCODE rc = NE_XFLM_OK;
flmAssert( pSharedContext != NULL);
m_pSharedContext = pSharedContext;
m_pThrdFunc = pFunc;
m_pvAppData = pvAppData;
if( (m_pLocalContext = f_new FlmContext) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if( RC_BAD( rc = f_mutexCreate( &m_hMutex)))
{
goto Exit;
}
if( pszThreadName &&
f_strlen( pszThreadName) <= MAX_THREAD_NAME_LEN)
{
f_strcpy( m_szName, pszThreadName);
}
else
{
f_sprintf( m_szName, "flmGenericThread");
}
if( RC_BAD( rc = m_pLocalContext->setup( FALSE)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
void FlmThreadContext::getName(
char * pszName,
FLMBOOL bLocked)
{
if( !bLocked)
{
lock();
}
f_strcpy( pszName, m_szName);
if( !bLocked)
{
unlock();
}
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmThreadContext::execute( void)
{
flmAssert( m_pThrdFunc != NULL);
m_FuncRC = m_pThrdFunc( this, m_pvAppData);
return m_FuncRC;
}
/****************************************************************************
Desc:
*****************************************************************************/
void FlmThreadContext::shutdown()
{
m_bShutdown = TRUE;
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmThreadContext::exec( void)
{
flmAssert( m_pThrdFunc != NULL);
return( (RCODE)(m_pThrdFunc( this, m_pvAppData)));
}
/****************************************************************************
Desc:
*****************************************************************************/
FlmSharedContext::FlmSharedContext( void)
{
m_pParentContext = NULL;
m_pThreadList = NULL;
m_bLocalShutdownFlag = FALSE;
m_pbShutdownFlag = &m_bLocalShutdownFlag;
m_hSem = F_SEM_NULL;
m_uiNextProcID = 1;
m_bPrivateShare = FALSE;
}
/****************************************************************************
Desc:
*****************************************************************************/
FlmSharedContext::~FlmSharedContext( void)
{
// Clean up the thread list
shutdown();
// Free the ESem
if( m_hSem != F_SEM_NULL)
{
f_semDestroy( &m_hSem);
}
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmSharedContext::init(
FlmSharedContext * pSharedContext)
{
RCODE rc = NE_XFLM_OK;
// Initialize the base class
if( RC_BAD( rc = FlmContext::setup( TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = f_semCreate( &m_hSem)))
{
goto Exit;
}
m_pParentContext = pSharedContext;
Exit:
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
void FlmSharedContext::shutdown( void)
{
FLMBOOL bLocked = FALSE;
*m_pbShutdownFlag = TRUE;
for( ;;)
{
lock();
bLocked = TRUE;
if( m_pThreadList)
{
m_pThreadList->shutdown();
}
else
{
break;
}
unlock();
bLocked = FALSE;
(void)f_semWait( m_hSem, 1000);
}
if( bLocked)
{
unlock();
}
}
/****************************************************************************
Desc:
*****************************************************************************/
void FlmSharedContext::wait( void)
{
FLMBOOL bLocked = FALSE;
for( ;;)
{
lock();
bLocked = TRUE;
if( !m_pThreadList)
{
break;
}
unlock();
bLocked = FALSE;
(void)f_semWait( m_hSem, 1000);
}
if( bLocked)
{
unlock();
}
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmSharedContext::spawn(
FlmThreadContext * pThread,
FLMUINT * puiThreadID)
{
RCODE rc = NE_XFLM_OK;
char szName[ MAX_THREAD_NAME_LEN + 1];
IF_ThreadMgr * pThreadMgr = NULL;
registerThread( pThread);
pThread->getName( szName);
if( RC_BAD( rc = FlmGetThreadMgr( &pThreadMgr)))
{
goto Exit;
}
if( RC_BAD( rc = pThreadMgr->createThread( NULL,
_flmWrapperFunc, szName, 0, 0, pThread)))
{
goto Exit;
}
if( puiThreadID)
{
*puiThreadID = pThread->getID();
}
Exit:
if( pThreadMgr)
{
pThreadMgr->Release();
}
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmSharedContext::spawn(
char * pszThreadName,
THREAD_FUNC_p pFunc,
void * pvUserData,
FLMUINT * puiThreadID)
{
FlmThreadContext * pThread;
RCODE rc = NE_XFLM_OK;
if( (pThread = f_new FlmThreadContext) == NULL)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
if( RC_BAD( rc = pThread->setup( this, pszThreadName, pFunc, pvUserData)))
{
goto Exit;
}
if( RC_BAD( rc = spawn( pThread, puiThreadID)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmSharedContext::registerThread(
FlmThreadContext * pThread)
{
RCODE rc = NE_XFLM_OK;
lock();
pThread->setNext( m_pThreadList);
if( m_pThreadList)
{
m_pThreadList->setPrev( pThread);
}
m_pThreadList = pThread;
pThread->setID( m_uiNextProcID++);
unlock();
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmSharedContext::deregisterThread(
FlmThreadContext * pThread)
{
FlmThreadContext * pTmpThrd;
RCODE rc = NE_XFLM_OK;
lock();
pTmpThrd = m_pThreadList;
while( pTmpThrd)
{
if( pTmpThrd == pThread)
{
if( pTmpThrd->getPrev())
{
pTmpThrd->getPrev()->setNext( pTmpThrd->getNext());
}
if( pTmpThrd->getNext())
{
pTmpThrd->getNext()->setPrev( pTmpThrd->getPrev());
}
if( pTmpThrd == m_pThreadList)
{
m_pThreadList = pTmpThrd->getNext();
}
pTmpThrd->Release();
break;
}
pTmpThrd = pTmpThrd->getNext();
}
f_semSignal( m_hSem);
unlock();
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmSharedContext::killThread(
FLMUINT uiThreadID,
FLMUINT uiMaxWait)
{
FlmThreadContext * pThread;
FLMUINT uiStartTime;
RCODE rc = NE_XFLM_OK;
lock();
pThread = m_pThreadList;
while( pThread)
{
if( pThread->getID() == uiThreadID)
{
pThread->shutdown();
break;
}
pThread = pThread->getNext();
}
unlock();
// Wait for the thread to exit
uiStartTime = FLM_GET_TIMER();
uiMaxWait = FLM_SECS_TO_TIMER_UNITS( uiMaxWait);
for( ;;)
{
(void)f_semWait( m_hSem, 200);
lock();
pThread = m_pThreadList;
while( pThread)
{
if( pThread->getID() == uiThreadID)
{
break;
}
pThread = pThread->getNext();
}
unlock();
if( !pThread)
{
break;
}
if( uiMaxWait)
{
if( FLM_GET_TIMER() - uiStartTime >= uiMaxWait)
{
rc = RC_SET( NE_XFLM_FAILURE);
goto Exit;
}
}
}
Exit:
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmSharedContext::setFocus(
FLMUINT uiThreadID)
{
FlmThreadContext * pThread;
lock();
pThread = m_pThreadList;
while( pThread)
{
if( pThread->getID() == uiThreadID)
{
if( pThread->getScreen())
{
FTXScreenDisplay( pThread->getScreen());
}
break;
}
pThread = pThread->getNext();
}
unlock();
return( NE_XFLM_OK);
}
/****************************************************************************
Desc:
*****************************************************************************/
FLMBOOL FlmSharedContext::isThreadTerminating(
FLMUINT uiThreadID)
{
FLMBOOL bTerminating = FALSE;
FlmThreadContext * pThread;
lock();
pThread = m_pThreadList;
while( pThread)
{
if( pThread->getID() == uiThreadID)
{
if( pThread->getShutdownFlag())
{
bTerminating = TRUE;
}
break;
}
pThread = pThread->getNext();
}
unlock();
return( bTerminating);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmSharedContext::getThread(
FLMUINT uiThreadID,
FlmThreadContext ** ppThread)
{
FlmThreadContext * pThread;
lock();
pThread = m_pThreadList;
while( pThread)
{
if( pThread->getID() == uiThreadID)
{
if( ppThread)
{
*ppThread = pThread;
}
break;
}
pThread = pThread->getNext();
}
unlock();
return( ((pThread != NULL)
? NE_XFLM_OK
: RC_SET( NE_XFLM_NOT_FOUND)));
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE _flmWrapperFunc(
IF_Thread * pFlmThread)
{
FlmThreadContext * pThread = (FlmThreadContext *)pFlmThread->getParm1();
FlmSharedContext * pSharedContext = pThread->getSharedContext();
pThread->setFlmThread( pFlmThread);
if( RC_BAD( pThread->execute()))
{
goto Exit;
}
Exit:
pThread->setFuncExited();
pThread->setFlmThread( NULL);
// Unlink the thread from the shared context
pSharedContext->deregisterThread( pThread);
return( NE_XFLM_OK);
}
/****************************************************************************
Desc: callback to use to output a line
****************************************************************************/
void utilOutputLine(
char * pszData,
void * pvUserData)
{
FTX_WINDOW * pMainWindow = (FTX_WINDOW*)pvUserData;
eColorType uiBack, uiFore;
FTXWinGetBackFore( pMainWindow, &uiBack, &uiFore);
FTXWinCPrintf( pMainWindow, uiBack, uiFore, "%s\n", pszData);
}
/****************************************************************************
Name: utilPressAnyKey
Desc: callback to serve as a 'pager' function when the Usage: help
is too long to fit on one screen.
****************************************************************************/
void utilPressAnyKey( char * pszMessage, void * pvUserData)
{
FTX_WINDOW * pMainWindow = (FTX_WINDOW*)pvUserData;
FLMUINT uiChar;
eColorType uiBack, uiFore;
FTXWinGetBackFore( pMainWindow, &uiBack, &uiFore);
FTXWinCPrintf( pMainWindow, uiBack, uiFore, pszMessage);
while( RC_BAD( FTXWinTestKB( pMainWindow)))
{
f_sleep( 100);
}
FTXWinCPrintf( pMainWindow, uiBack, uiFore,
"\r ");
FTXWinCPrintf( pMainWindow, uiBack, uiFore, "\r");
FTXWinInputChar( pMainWindow, &uiChar);
}
/****************************************************************************
Name: utilInitWindow
Desc: routine to startup the TUI
****************************************************************************/
RCODE utilInitWindow(
char * pszTitle,
FLMUINT * puiScreenRows,
FTX_WINDOW ** ppMainWindow,
FLMBOOL * pbShutdown)
{
FTX_SCREEN * pScreen = NULL;
FTX_WINDOW * pTitleWin = NULL;
FLMUINT uiCols;
int iResCode = 0;
if( RC_BAD( FTXInit( pszTitle, (FLMBYTE)80, (FLMBYTE)50,
FLM_BLUE, FLM_WHITE, NULL, NULL)))
{
iResCode = 1;
goto Exit;
}
FTXSetShutdownFlag( pbShutdown);
if( RC_BAD( FTXScreenInit( pszTitle, &pScreen)))
{
iResCode = 1;
goto Exit;
}
if( RC_BAD( FTXScreenGetSize( pScreen, &uiCols, puiScreenRows)))
{
iResCode = 1;
goto Exit;
}
if( RC_BAD( FTXScreenInitStandardWindows( pScreen, FLM_RED, FLM_WHITE,
FLM_BLUE, FLM_WHITE, FALSE, FALSE, pszTitle,
&pTitleWin, ppMainWindow)))
{
iResCode = 1;
goto Exit;
}
Exit:
return (RCODE)iResCode;
}
/****************************************************************************
Name: utilShutdownWindow
Desc: routine to shutdown the TUI
****************************************************************************/
void utilShutdownWindow()
{
FTXExit();
}
/****************************************************************************
Desc: read the contents of the argument file into the ppszReturnString buffer
****************************************************************************/
RCODE fileToString(
char * pszFile,
char ** ppszReturnString)
{
RCODE rc = NE_XFLM_OK;
char * pszBuffer = NULL;
IF_FileHdl * pFileHdl = NULL;
FLMUINT64 ui64FileSize = 0;
FLMUINT uiBytesRead = 0;
IF_FileSystem * pFileSystem = NULL;
if( RC_BAD( rc = FlmGetFileSystem( &pFileSystem)))
{
goto Exit;
}
if (RC_BAD(rc = pFileSystem->openFile( pszFile, FLM_IO_RDONLY, &pFileHdl)))
{
goto Exit;
}
if (RC_BAD( rc = pFileHdl->size( &ui64FileSize)))
{
goto Exit;
}
if( ui64FileSize == 0)
{
goto Exit;
}
if( RC_BAD( rc = f_alloc( (FLMUINT)(ui64FileSize + 1), &pszBuffer)))
{
goto Exit;
}
if (RC_BAD( rc = pFileHdl->read( 0, (FLMUINT)ui64FileSize,
pszBuffer, &uiBytesRead)))
{
goto Exit;
}
flmAssert( ui64FileSize == uiBytesRead);
pszBuffer[ ui64FileSize] = 0;
Exit:
if( pFileHdl)
{
pFileHdl->Release();
}
if( pFileSystem)
{
pFileSystem->Release();
}
if ( RC_BAD( rc) && pszBuffer)
{
f_free( &pszBuffer);
}
else if ( RC_OK( rc))
{
*ppszReturnString = pszBuffer;
}
return( rc);
}
/****************************************************************************
Desc: allocate a copy of the arg string and return it out
****************************************************************************/
char * getStringClone(
char * pszSrcStr)
{
char * pszReturnVal = NULL;
if( RC_BAD( f_alloc( f_strlen( pszSrcStr) + 1, &pszReturnVal)))
{
goto Exit;
}
f_strcpy( pszReturnVal, pszSrcStr);
Exit:
return pszReturnVal;
}
/****************************************************************************
Desc: fill a buffer with the current (or given) time
****************************************************************************/
FLMUINT utilGetTimeString(
char * pszOutString,
FLMUINT uiBufferSize,
FLMUINT uiInSeconds) //default param to use user-supplied time
{
F_TMSTAMP timeStamp;
FLMUINT uiSeconds;
if ( uiInSeconds != 0)
{
f_timeSecondsToDate( uiInSeconds, &timeStamp);
}
else
{
f_timeGetTimeStamp( &timeStamp);
}
f_timeDateToSeconds( &timeStamp, &uiSeconds);
char szTemp[ 256];
f_sprintf( szTemp,
"%4u-%02u-%02u %02u:%02u:%02u",
(unsigned)timeStamp.year,
(unsigned)(timeStamp.month + 1),
(unsigned)timeStamp.day,
(unsigned)timeStamp.hour,
(unsigned)timeStamp.minute,
(unsigned)timeStamp.second);
f_strncpy( pszOutString, szTemp, uiBufferSize - 1);
pszOutString[ uiBufferSize-1] = 0;
return uiSeconds;
}
#define UTIL_PROP_DELIMITER '!'
FSTATIC RCODE propertyExists(
char * pszProperty,
char * pszBuffer,
char ** ppszValue)
{
flmAssert( pszProperty);
FlmStringAcc acc;
RCODE rc = NE_XFLM_OK; //returns only memory errors
*ppszValue = NULL;
if ( !pszBuffer)
{
goto Exit;
}
else
{
char * pszValue;
acc.appendf( "%s%c", pszProperty, UTIL_PROP_DELIMITER);
if ( (pszValue = (char *)f_strstr( pszBuffer, pszProperty)) != NULL)
{
pszValue = (char *)(1 + f_strchr( pszValue, UTIL_PROP_DELIMITER));
*ppszValue = getStringClone( pszValue);
if ( !*ppszValue)
{
rc = RC_SET( NE_XFLM_MEM);
goto Exit;
}
((FLMBYTE*)(f_strchr( *ppszValue, '\n')))[ 0] = 0;
}
else
{
goto Exit;
}
}
Exit:
return rc;
}
RCODE utilWriteProperty(
char * pszFile,
char * pszProp,
char * pszValue)
{
RCODE rc = NE_XFLM_OK;
char * pszContents = NULL;
char * pszExistingProperty;
FlmStringAcc newContents;
IF_FileSystem * pFileSystem = NULL;
if( RC_BAD( rc = FlmGetFileSystem( &pFileSystem)))
{
goto Exit;
}
//can't have newlines in the props or values
flmAssert( !f_strchr( pszProp, '\n'));
flmAssert( !f_strchr( pszValue, '\n'));
if ( RC_BAD( pFileSystem->doesFileExist( pszFile)))
{
//add trailing newline
TEST_RC( rc = f_filecpy( pszFile, ""));
}
if ( RC_BAD( fileToString( pszFile, &pszContents)))
{
goto Exit;
}
//propertyExists returns out a new
TEST_RC( rc = propertyExists( pszProp, pszContents, &pszExistingProperty));
if ( !pszExistingProperty)
{
newContents.appendf( "%s%c%s\n", pszProp, UTIL_PROP_DELIMITER, pszValue);
newContents.appendTEXT( (FLMBYTE *)pszContents);
}
else
{
f_free( &pszExistingProperty);
pszExistingProperty = NULL;
FLMUINT uiProps = 0;
//write out nulls in place of the "\n"'s throughout the contents
char * pszNuller = pszContents;
for( ;;)
{
pszNuller = (char *)f_strchr( pszNuller, '\n');
if ( pszNuller)
{
pszNuller[ 0] = 0;
pszNuller++;
uiProps++;
}
else
{
break;
}
}
char * pszNextLine = pszContents;
char * pszNextProp;
char * pszNextVal;
char * pszBang;
while ( uiProps--)
{
pszBang = (char *)f_strchr( pszNextLine, UTIL_PROP_DELIMITER);
flmAssert( pszBang); //better have a UTIL_PROP_DELIMITER in it
pszBang[ 0] = 0;
pszNextProp = pszNextLine;
pszNextVal = pszBang + 1;
if ( !(STREQ( pszNextProp, pszProp)))
{
pszBang[ 0] = UTIL_PROP_DELIMITER;
newContents.appendTEXT( (FLMBYTE *)pszNextLine);
newContents.appendCHAR( '\n');
}
else
{
newContents.appendf( "%s%c%s\n",
pszNextProp, UTIL_PROP_DELIMITER, pszValue);
pszBang[ 0] = UTIL_PROP_DELIMITER;
}
pszNextLine = pszNextLine + f_strlen( pszNextLine) + 1;
}
}
rc = f_filecpy( pszFile, newContents.getTEXT());
Exit:
if( pFileSystem)
{
pFileSystem->Release();
}
if ( pszContents)
{
f_free( &pszContents);
}
return rc;
}
RCODE utilReadProperty(
char * pszFile,
char * pszProp,
FlmStringAcc * pAcc)
{
RCODE rc = NE_XFLM_OK;
char * pszContents = NULL;
char * pszValue = NULL;
IF_FileSystem * pFileSystem = NULL;
if( RC_BAD( rc = FlmGetFileSystem( &pFileSystem)))
{
goto Exit;
}
if ( RC_BAD( pFileSystem->doesFileExist( pszFile)))
{
//be nice here. simply don't append anything into FlmStringAcc
goto Exit;
}
if ( RC_BAD( fileToString( pszFile, &pszContents)))
{
goto Exit;
}
TEST_RC( rc = propertyExists( pszProp, pszContents, &pszValue));
TEST_RC( rc = pAcc->appendTEXT( (FLMBYTE *)pszValue));
Exit:
if( pFileSystem)
{
pFileSystem->Release();
}
if( pszValue)
{
f_free( &pszValue);
}
if( pszContents)
{
f_free( &pszContents);
}
return( rc);
}
void scramble(
IF_RandomGenerator * pRandGen,
FLMUINT * puiArray,
FLMUINT uiNumElems)
{
FLMUINT uiLoop;
FLMUINT uiTmp;
FLMUINT uiIndex;
for( uiLoop = 0; uiLoop < uiNumElems; uiLoop++)
{
uiIndex = pRandGen->getUINT32( 0, (FLMUINT32)(uiNumElems - 1));
f_swap(
puiArray[uiLoop],
puiArray[uiIndex],
uiTmp);
}
}
/****************************************************************************
Desc: Initialize and set the title
****************************************************************************/
void WpsInit(
FLMUINT uiRows, // 0xFFFF means use current screen height.
FLMUINT uiCols, // 0xFFFF means use current screen width.
const char * pszScreenTitle)
{
char szTitleAndVer[ 100];
if( gv_bInitialized)
{
return;
}
// Setup utilities title which includes the software version.
#ifdef SECURE_UTIL
f_sprintf( (char *)szTitleAndVer, "%s - %s (%u)",
pszScreenTitle, SRC_VER_STR, (unsigned)UTIL_VER);
#else
f_sprintf( (char *)szTitleAndVer, "%s - %s (UNSECURE:%u)",
pszScreenTitle, SRC_VER_STR, (unsigned)UTIL_VER);
#endif
FTXInit( szTitleAndVer, uiCols, uiRows, FLM_BLACK, FLM_LIGHTGRAY,
NULL, NULL);
if( RC_BAD( f_mutexCreate( &gv_hDispMutex)))
{
flmAssert( 0);
}
WpsThrdInit( szTitleAndVer);
gv_bInitialized = TRUE;
}
/****************************************************************************
Desc: Initialize WPS using an existing FTX environment
****************************************************************************/
void WpsInitFTX( void)
{
if( gv_bInitialized)
{
return;
}
if( RC_BAD( f_mutexCreate( &gv_hDispMutex)))
{
flmAssert( 0);
}
gv_bInitialized = TRUE;
}
/****************************************************************************
Desc: Restores the screen to an initial state
****************************************************************************/
void WpsExit( void)
{
if( !gv_bInitialized)
{
return;
}
gv_bShutdown = TRUE;
WpsThrdExit();
f_mutexDestroy( &gv_hDispMutex);
FTXExit();
gv_bInitialized = FALSE;
}
/****************************************************************************
Desc: Initialize and set the title of a thread's screen
***************************************************************************/
void WpsThrdInitUsingScreen(
FTX_SCREEN * pFtxScreen,
const char * pszScreenTitle)
{
FLMUINT uiRows;
FLMUINT uiThrdId;
WPSSCREEN * pCurScreen = NULL;
wpsLock( &gv_hDispMutex);
uiThrdId = f_threadId();
pCurScreen = gv_pScreenList;
while( pCurScreen != NULL)
{
if( pCurScreen->uiScreenId == uiThrdId)
{
break;
}
pCurScreen = pCurScreen->pNext;
}
if( pCurScreen == NULL)
{
if( RC_BAD( f_calloc( sizeof( WPSSCREEN), &pCurScreen)))
{
flmAssert( 0);
}
pCurScreen->uiScreenId = uiThrdId;
pCurScreen->pNext = gv_pScreenList;
gv_pScreenList = pCurScreen;
if( pFtxScreen != NULL)
{
pCurScreen->pScreen = pFtxScreen;
pCurScreen->bPrivate = FALSE;
}
else
{
if( RC_BAD( FTXScreenInit( pszScreenTitle,
&(pCurScreen->pScreen))))
{
flmAssert( 0);
}
pCurScreen->bPrivate = TRUE;
}
if( RC_BAD( FTXScreenGetSize( pCurScreen->pScreen, NULL, &uiRows)))
{
flmAssert( 0);
}
if( RC_BAD( FTXWinInit( pCurScreen->pScreen, 0,
(FLMBYTE)(uiRows - 1), &(pCurScreen->pWin))))
{
flmAssert( 0);
}
FTXWinMove( pCurScreen->pWin, 0, 1);
if( RC_BAD( FTXWinInit( pCurScreen->pScreen, 0,
1, &(pCurScreen->pTitleWin))))
{
flmAssert( 0);
}
FTXWinPaintBackground( pCurScreen->pTitleWin, FLM_RED);
FTXWinPrintStr( pCurScreen->pTitleWin, pszScreenTitle);
FTXWinOpen( pCurScreen->pTitleWin);
FTXWinOpen( pCurScreen->pWin);
}
wpsUnlock( &gv_hDispMutex);
}
/****************************************************************************
Desc: Frees all screen resources allocated to a thread
Ret:
****************************************************************************/
void WpsThrdExit( void)
{
FLMUINT uiThrdId;
WPSSCREEN * pPrevScreen = NULL;
WPSSCREEN * pCurScreen = NULL;
wpsLock( &gv_hDispMutex);
uiThrdId = f_threadId();
pCurScreen = gv_pScreenList;
while( pCurScreen != NULL)
{
if( pCurScreen->uiScreenId == uiThrdId)
{
break;
}
pPrevScreen = pCurScreen;
pCurScreen = pCurScreen->pNext;
}
if( pCurScreen != NULL)
{
if( pCurScreen == gv_pScreenList)
{
gv_pScreenList = pCurScreen->pNext;
}
if( pPrevScreen != NULL)
{
pPrevScreen->pNext = pCurScreen->pNext;
}
if( pCurScreen->bPrivate == TRUE)
{
FTXScreenFree( &(pCurScreen->pScreen));
}
else
{
FTXWinFree( &(pCurScreen->pTitleWin));
FTXWinFree( &(pCurScreen->pWin));
}
f_free( &pCurScreen);
}
wpsUnlock( &gv_hDispMutex);
}
/****************************************************************************
Desc: Returns the size of the screen in columns and rows.
****************************************************************************/
void WpsScrSize(
FLMUINT * puiNumColsRV,
FLMUINT * puiNumRowsRV
)
{
FTXWinGetCanvasSize( wpsGetThrdWin(), puiNumColsRV, puiNumRowsRV);
}
/****************************************************************************
Desc: Output a string at present cursor location.
****************************************************************************/
void WpsStrOut(
const char * pszString)
{
FTXWinPrintStr( wpsGetThrdWin(), pszString);
if( !gv_bOptimize)
{
FTXRefresh();
}
}
/****************************************************************************
Desc: Output a formatted string at present cursor location.
****************************************************************************/
void WpsPrintf(
const char * pszFormat, ...)
{
char szBuffer[ 512];
f_va_list args;
f_va_start( args, pszFormat);
f_vsprintf( szBuffer, pszFormat, &args);
f_va_end( args);
FTXWinPrintStr( wpsGetThrdWin(), szBuffer);
if( !gv_bOptimize)
{
FTXRefresh();
}
}
/****************************************************************************
Desc: Output a formatted string at present cursor location with color
****************************************************************************/
void WpsCPrintf(
eColorType uiBack,
eColorType uiFore,
const char * pszFormat, ...)
{
char szBuffer[ 512];
f_va_list args;
eColorType uiOldBack;
eColorType uiOldFore;
f_va_start( args, pszFormat);
f_vsprintf( szBuffer, pszFormat, &args);
f_va_end( args);
FTXWinGetBackFore( wpsGetThrdWin(), &uiOldBack, &uiOldFore);
FTXWinSetBackFore( wpsGetThrdWin(), uiBack, uiFore);
FTXWinPrintStr( wpsGetThrdWin(), szBuffer);
FTXWinSetBackFore( wpsGetThrdWin(), uiOldBack, uiOldFore);
if( !gv_bOptimize)
{
FTXRefresh();
}
}
/****************************************************************************
Desc: Output a character to the screen at the current location. If char is
a LineFeed then a CarriageReturn will be inserted before the LineFeed.
Notes:On NLM becomes a blocking function if the char is the newline character.
****************************************************************************/
void WpsChrOut(
char chr
)
{
FTXWinPrintChar( wpsGetThrdWin(), (FLMUINT)chr);
if( !gv_bOptimize)
{
FTXRefresh();
}
}
/****************************************************************************
Desc: Clear the screen from the col/row down
Notes: If col==row==0 then clear entire screen
****************************************************************************/
void WpsScrClr(
FLMUINT uiCol,
FLMUINT uiRow
)
{
FTX_WINDOW * pThrdWin;
FLMUINT uiCurrCol;
FLMUINT uiCurrRow;
pThrdWin = wpsGetThrdWin();
FTXWinGetCursorPos( pThrdWin, &uiCurrCol, &uiCurrRow);
if( uiCol == 255)
{
uiCol = uiCurrCol;
}
if( uiRow == 255)
{
uiRow = uiCurrRow;
}
FTXWinClearXY( pThrdWin, uiCol, uiRow);
FTXWinSetCursorPos( pThrdWin, uiCol, uiRow);
if( !gv_bOptimize)
{
FTXRefresh();
}
}
/****************************************************************************
Desc: Position to the column and row specified.
Notes: The NLM could call GetPositionOfOutputCursor(&r,&c);
****************************************************************************/
void WpsScrPos(
FLMUINT uiCol,
FLMUINT uiRow
)
{
FTX_WINDOW * pThrdWin;
FLMUINT uiCurrCol;
FLMUINT uiCurrRow;
pThrdWin = wpsGetThrdWin();
FTXWinGetCursorPos( pThrdWin, &uiCurrCol, &uiCurrRow);
if( uiCol == 255)
{
uiCol = uiCurrCol;
}
if( uiRow == 255)
{
uiRow = uiCurrRow;
}
FTXWinSetCursorPos( pThrdWin, uiCol, uiRow);
}
/****************************************************************************
Desc: Clear from input cursor to end of line
****************************************************************************/
void WpsLineClr(
FLMUINT uiCol,
FLMUINT uiRow
)
{
FTX_WINDOW * pThrdWin;
FLMUINT uiCurrCol;
FLMUINT uiCurrRow;
pThrdWin = wpsGetThrdWin();
FTXWinGetCursorPos( pThrdWin, &uiCurrCol, &uiCurrRow);
if( uiCol == 255)
{
uiCol = uiCurrCol;
}
if( uiRow == 255)
{
uiRow = uiCurrRow;
}
FTXWinClearLine( pThrdWin, uiCol, uiRow);
if( !gv_bOptimize)
{
FTXRefresh();
}
}
/****************************************************************************
Desc: Edit a line of data like gets(s). Newline replaced by NULL character.
Ret: WPK Character
Notes: Does not support WP extended character input - but could easily!
****************************************************************************/
FLMUINT WpsLineEd(
char * pszString,
FLMUINT uiMaxLen,
FLMBOOL * pbShutdown
)
{
FLMUINT uiCharCount;
FLMUINT uiCursorType;
uiCursorType = FTXWinGetCursorType( wpsGetThrdWin());
FTXWinSetCursorType( wpsGetThrdWin(), FLM_CURSOR_UNDERLINE);
FTXSetShutdownFlag( pbShutdown);
uiCharCount = FTXLineEd( wpsGetThrdWin(), pszString, uiMaxLen);
FTXSetShutdownFlag( NULL);
FTXWinSetCursorType( wpsGetThrdWin(), uiCursorType);
return( uiCharCount);
}
/****************************************************************************
Desc: Sets the FTX shutdown flag pointer
Ret:
****************************************************************************/
void WpsSetShutdown(
FLMBOOL * pbShutdown
)
{
FTXSetShutdownFlag( pbShutdown);
}
/****************************************************************************
Desc: Edit a line of data with advanced features.
Ret: Number of characters input.
****************************************************************************/
FLMUINT WpsLineEditExt(
char * pszBuffer,
FLMUINT uiBufSize,
FLMUINT uiMaxWidth,
FLMBOOL * pbShutdown,
FLMUINT * puiTermChar
)
{
FLMUINT uiCharCount = 0;
FLMUINT uiCursorType;
uiCursorType = FTXWinGetCursorType( wpsGetThrdWin());
FTXWinSetCursorType( wpsGetThrdWin(), FLM_CURSOR_UNDERLINE);
FTXSetShutdownFlag( pbShutdown);
FTXLineEdit( wpsGetThrdWin(), pszBuffer, uiBufSize, uiMaxWidth,
&uiCharCount, puiTermChar);
FTXSetShutdownFlag( NULL);
FTXWinSetCursorType( wpsGetThrdWin(), uiCursorType);
return( (FLMINT)uiCharCount);
}
/****************************************************************************
Desc: Get the current X coordinate of the cursor
****************************************************************************/
FLMUINT WpsCurrCol( void)
{
FLMUINT uiCol;
FTXWinGetCursorPos( wpsGetThrdWin(), &uiCol, NULL);
return( uiCol);
}
/****************************************************************************
Desc: Get the current Y coordinate of the cursor
****************************************************************************/
FLMUINT WpsCurrRow( void)
{
FLMUINT uiRow;
FTXWinGetCursorPos( wpsGetThrdWin(), NULL, &uiRow);
return( uiRow);
}
/****************************************************************************
Desc: Set the background and foreground colors
Ret: None
****************************************************************************/
void WpsScrBackFor(
eColorType backColor,
eColorType foreColor)
{
FTXWinSetBackFore( wpsGetThrdWin(), backColor, foreColor);
}
/****************************************************************************
Desc : Sets the cursor attributes.
****************************************************************************/
void WpsCursorSetType(
FLMUINT uiType)
{
FTXWinSetCursorType( wpsGetThrdWin(), uiType);
FTXRefresh();
}
/****************************************************************************
Desc: Specifies that display performance (throughput) should be
optimal.
****************************************************************************/
void WpsOptimize( void)
{
gv_bOptimize = TRUE;
}
/****************************************************************************
Desc: Draws a border around the current thread's screen
Ret: none
****************************************************************************/
void WpsDrawBorder( void)
{
FTXWinDrawBorder( wpsGetThrdWin());
if( !gv_bOptimize)
{
FTXRefresh();
}
}
/****************************************************************************
Desc: Convert keyboard sequences/scan codes to WPK key strokes.
Notes: Does not support WP extended character input - but could easily!
****************************************************************************/
FLMUINT WpkIncar( void)
{
FLMUINT uiChar;
FTXWinInputChar( wpsGetThrdWin(), &uiChar);
return( uiChar);
}
/****************************************************************************
Desc: Convert keyboard sequences/scan codes to WPK key strokes. This
routine accepts a pointer to a shutdown flag.
****************************************************************************/
FLMUINT WpkGetChar(
FLMBOOL * pbShutdown
)
{
FLMUINT uiChar;
FTXSetShutdownFlag( pbShutdown);
FTXWinInputChar( wpsGetThrdWin(), &uiChar);
FTXSetShutdownFlag( NULL);
return( uiChar);
}
/****************************************************************************
Desc: Tests the keyboard for a pending character
Ret: 1 if key available, 0 if no key available
****************************************************************************/
FLMUINT WpkTestKB( void)
{
FLMUINT uiCharAvail;
uiCharAvail = (FLMUINT)(FTXWinTestKB( wpsGetThrdWin()) ==
NE_FLM_OK ? 1 : 0);
return( uiCharAvail);
}
/****************************************************************************
Desc: Returns a pointer to a thread's screen
****************************************************************************/
FTX_SCREEN * WpsGetThrdScreen( void)
{
FLMUINT uiThrdId;
WPSSCREEN * pCurScreen = NULL;
wpsLock( &gv_hDispMutex);
uiThrdId = f_threadId();
pCurScreen = gv_pScreenList;
while( pCurScreen != NULL)
{
if( pCurScreen->uiScreenId == uiThrdId)
{
break;
}
pCurScreen = pCurScreen->pNext;
}
if( pCurScreen == NULL)
{
flmAssert( 0);
}
wpsUnlock( &gv_hDispMutex);
return( pCurScreen->pScreen);
}
/****************************************************************************
Desc: Returns a pointer to a thread's screen
****************************************************************************/
FSTATIC FTX_WINDOW * wpsGetThrdWin( void)
{
FLMUINT uiThrdId;
WPSSCREEN * pCurScreen = NULL;
wpsLock( &gv_hDispMutex);
uiThrdId = f_threadId();
pCurScreen = gv_pScreenList;
while( pCurScreen != NULL)
{
if( pCurScreen->uiScreenId == uiThrdId)
{
break;
}
pCurScreen = pCurScreen->pNext;
}
if( pCurScreen == NULL)
{
flmAssert( 0);
}
wpsUnlock( &gv_hDispMutex);
return( pCurScreen->pWin);
}