Files
mars-flaim/xflaim/util/sharutil.cpp
dsandersoremutah c55dab446f Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-01-27 21:06:39 +00:00

1384 lines
30 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 RCODE propertyExists(
char * pszProperty,
char * pszBuffer,
char ** ppszValue);
FSTATIC RCODE _flmWrapperFunc(
F_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( 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, 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, 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;
const size_t 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;
const size_t 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( m_szCurrDir, pszCurrDir);
unlock();
return( rc);
}
/****************************************************************************
Desc:
*****************************************************************************/
RCODE FlmContext::getCurrDir(
FLMBYTE * pszCurrDir)
{
RCODE rc = NE_XFLM_OK;
flmAssert( m_bIsSetup);
lock();
f_strcpy( pszCurrDir, 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,
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_pFtxInfo = 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,
FTX_INFO * pFtxInfo)
{
RCODE rc = NE_XFLM_OK;
// Initialize the base class
if( RC_BAD( rc = FlmContext::setup( TRUE)))
{
goto Exit;
}
m_pFtxInfo = pFtxInfo;
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)
{
char szName[ MAX_THREAD_NAME_LEN + 1];
RCODE rc = NE_XFLM_OK;
registerThread( pThread);
pThread->getName( szName);
if( RC_BAD( rc = f_threadCreate( NULL,
_flmWrapperFunc, szName,
FLM_DEFAULT_THREAD_GROUP, 0, pThread)))
{
goto Exit;
}
if( puiThreadID)
{
*puiThreadID = pThread->getID();
}
Exit:
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();
FLM_SECS_TO_TIMER_UNITS( uiMaxWait, 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(
F_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;
FLMUINT 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;
FLMUINT uiBack, uiFore;
FTXWinGetBackFore( pMainWindow, &uiBack, &uiFore);
FTXWinCPrintf( pMainWindow, uiBack, uiFore, pszMessage);
while ( FTXWinTestKB( pMainWindow) != FTXRC_SUCCESS)
{
f_sleep( 100); //don't hog the cpu
}
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_INFO ** ppFtxInfo,
FTX_WINDOW ** ppMainWindow,
FLMBOOL * pbShutdown)
{
FTX_SCREEN * pScreen = NULL;
FTX_WINDOW * pTitleWin = NULL;
FLMUINT uiCols;
int iResCode = 0;
if( FTXInit( pszTitle, (FLMBYTE)80, (FLMBYTE)50,
WPS_BLUE, WPS_WHITE, NULL, NULL, ppFtxInfo) != FTXRC_SUCCESS)
{
iResCode = 1;
goto Exit;
}
FTXSetShutdownFlag( *ppFtxInfo, pbShutdown);
if( FTXScreenInit( *ppFtxInfo, pszTitle, &pScreen)
!= FTXRC_SUCCESS)
{
iResCode = 1;
goto Exit;
}
if( FTXScreenGetSize( pScreen, &uiCols, puiScreenRows) != FTXRC_SUCCESS)
{
iResCode = 1;
goto Exit;
}
if ( FTXScreenInitStandardWindows( pScreen, WPS_RED, WPS_WHITE,
WPS_BLUE, WPS_WHITE, FALSE, FALSE, pszTitle,
&pTitleWin, ppMainWindow) != FTXRC_SUCCESS)
{
iResCode = 1;
goto Exit;
}
Exit:
return (RCODE)iResCode;
}
/****************************************************************************
Name: utilShutdownWindow
Desc: routine to shutdown the TUI
****************************************************************************/
void utilShutdownWindow( FTX_INFO * pFtxInfo)
{
FTXFree( &pFtxInfo);
}
/****************************************************************************
Desc: read the contents of the argument file into the ppszReturnString buffer
****************************************************************************/
RCODE fileToString(
char * pszFile,
char ** ppszReturnString)
{
char * pszBuffer = NULL;
IF_FileHdl * pFileHdl = NULL;
F_FileSystem fileSystem;
FLMUINT64 ui64FileSize = 0;
FLMUINT uiBytesRead = 0;
RCODE rc = NE_XFLM_OK;
if (RC_BAD(rc = fileSystem.Open( pszFile, XFLM_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->Close();
pFileHdl->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;
F_FileSystem fileSys;
//can't have newlines in the props or values
flmAssert( !f_strchr( pszProp, '\n'));
flmAssert( !f_strchr( pszValue, '\n'));
if ( RC_BAD( fileSys.Exists( 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 ( pszContents)
{
f_free( &pszContents);
}
return rc;
}
RCODE utilReadProperty(
char * pszFile,
char * pszProp,
FlmStringAcc * pAcc)
{
RCODE rc = NE_XFLM_OK;
F_FileSystem fileSys;
char * pszContents = NULL;
char * pszValue = NULL;
if ( RC_BAD( fileSys.Exists( 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 ( pszValue)
{
f_free( &pszValue);
}
if ( pszContents)
{
f_free( &pszContents);
}
return rc;
}
void scramble(
F_RandomGenerator * pRandGen,
FLMUINT * puiArray,
FLMUINT uiNumElems)
{
FLMUINT uiLoop;
FLMUINT uiTmp;
FLMUINT uiIndex;
for( uiLoop = 0; uiLoop < uiNumElems; uiLoop++)
{
uiIndex = pRandGen->randomChoice( 0, uiNumElems - 1);
f_swap(
puiArray[uiLoop],
puiArray[uiIndex],
uiTmp);
}
}