git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
1384 lines
30 KiB
C++
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);
|
|
}
|
|
}
|