git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@358 0109f412-320b-0410-ab79-c3e0c5ffbbe6
599 lines
14 KiB
C++
599 lines
14 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: This file contains misc toolkit functions
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 2000-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: ftkmisc.cpp 3115 2006-01-19 13:24:39 -0700 (Thu, 19 Jan 2006) dsanders $
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "ftksys.h"
|
|
|
|
FLMUINT gv_uiStartupCount = 0;
|
|
FLMUINT gv_uiSerialInitCount = 0;
|
|
F_MUTEX gv_hSerialMutex = F_MUTEX_NULL;
|
|
IF_FileSystem * gv_pFileSystem = NULL;
|
|
IF_RandomGenerator * gv_pSerialRandom = NULL;
|
|
IF_ThreadMgr * gv_pThreadMgr = NULL;
|
|
|
|
FSTATIC RCODE f_initSerialNumberGenerator( void);
|
|
|
|
FSTATIC void f_freeSerialNumberGenerator( void);
|
|
|
|
#ifdef FLM_AIX
|
|
#ifndef nsleep
|
|
extern "C"
|
|
{
|
|
extern int nsleep( struct timestruc_t *, struct timestruc_t *);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FLMAPI ftkStartup( void)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if( ++gv_uiStartupCount > 1)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_memoryInit();
|
|
|
|
if( RC_BAD( rc = f_allocFileSystem( &gv_pFileSystem)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_allocThreadMgr( &gv_pThreadMgr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_initSerialNumberGenerator()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_checkErrorCodeTables()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
ftkShutdown();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
void FLMAPI ftkShutdown( void)
|
|
{
|
|
if( !gv_uiStartupCount || --gv_uiStartupCount > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( gv_pThreadMgr)
|
|
{
|
|
gv_pThreadMgr->Release();
|
|
gv_pThreadMgr = NULL;
|
|
}
|
|
|
|
if( gv_pFileSystem)
|
|
{
|
|
gv_pFileSystem->Release();
|
|
gv_pFileSystem = NULL;
|
|
}
|
|
|
|
f_freeSerialNumberGenerator();
|
|
f_memoryCleanup();
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This routine causes the calling process to delay the given number
|
|
of milliseconds. Due to the nature of the call, the actual sleep
|
|
time is almost guaranteed to be different from requested sleep time.
|
|
****************************************************************************/
|
|
#ifdef FLM_UNIX
|
|
void FLMAPI f_sleep(
|
|
FLMUINT uiMilliseconds)
|
|
{
|
|
#ifdef FLM_AIX
|
|
struct timestruc_t timeout;
|
|
struct timestruc_t remain;
|
|
#else
|
|
struct timespec timeout;
|
|
#endif
|
|
|
|
timeout.tv_sec = (uiMilliseconds / 1000);
|
|
timeout.tv_nsec = (uiMilliseconds % 1000) * 1000000;
|
|
|
|
#ifdef FLM_AIX
|
|
nsleep(&timeout, &remain);
|
|
#else
|
|
nanosleep(&timeout, 0);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#ifdef FLM_WIN
|
|
void FLMAPI f_sleep(
|
|
FLMUINT uiMilliseconds)
|
|
{
|
|
Sleep( (DWORD)uiMilliseconds);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
#ifdef FLM_NLM
|
|
void FLMAPI f_sleep(
|
|
FLMUINT uiMilliseconds)
|
|
{
|
|
if( !uiMilliseconds )
|
|
{
|
|
kYieldThread();
|
|
}
|
|
else
|
|
{
|
|
kDelayThread( uiMilliseconds);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: This routine initializes the serial number generator. If the O/S
|
|
does not provide support for GUID generation or if the GUID
|
|
routines fail for some reason, a pseudo-GUID will be generated.
|
|
Notes: This routine should only be called once by the process.
|
|
****************************************************************************/
|
|
FSTATIC RCODE f_initSerialNumberGenerator( void)
|
|
{
|
|
FLMUINT uiTime;
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
if (++gv_uiSerialInitCount > 1)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_mutexCreate( &gv_hSerialMutex)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_timeGetSeconds( &uiTime );
|
|
|
|
#if defined( FLM_UNIX)
|
|
|
|
if( RC_BAD( rc = FlmAllocRandomGenerator( &gv_pSerialRandom)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
gv_pSerialRandom->setSeed( (FLMUINT32)(uiTime ^ (FLMUINT)getpid()));
|
|
#endif
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FSTATIC void f_freeSerialNumberGenerator( void)
|
|
{
|
|
if( (--gv_uiSerialInitCount) > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( gv_pSerialRandom)
|
|
{
|
|
gv_pSerialRandom->Release();
|
|
gv_pSerialRandom = NULL;
|
|
}
|
|
|
|
if( gv_hSerialMutex != F_MUTEX_NULL)
|
|
{
|
|
f_mutexDestroy( &gv_hSerialMutex);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This routine will use the operating system calls to generate a
|
|
"globally unique" identifier. Typically, this is based on the
|
|
MAC address of an ethernet card installed in the machine. If the
|
|
machine does not have an ethernet card, or if the OS does not
|
|
support generating GUIDs, this routine will generate a pseudo-GUID
|
|
using a random number generator. A serial number is 16-bytes.
|
|
****************************************************************************/
|
|
RCODE FLMAPI f_createSerialNumber(
|
|
FLMBYTE * pszSerialNum)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
|
|
#if defined( FLM_WIN)
|
|
|
|
UUID uuidVal;
|
|
RPC_STATUS err = UuidCreate( &uuidVal);
|
|
|
|
if (err == RPC_S_OK || err == RPC_S_UUID_LOCAL_ONLY)
|
|
{
|
|
UD2FBA( (FLMUINT32)uuidVal.Data1, &pszSerialNum[ 0]);
|
|
UW2FBA( (FLMUINT16)uuidVal.Data2, &pszSerialNum[ 4]);
|
|
UW2FBA( (FLMUINT16)uuidVal.Data3, &pszSerialNum[ 6]);
|
|
f_memcpy( &pszSerialNum[ 8], (FLMBYTE *)uuidVal.Data4, 8);
|
|
goto Exit;
|
|
}
|
|
|
|
#elif defined( FLM_NLM)
|
|
|
|
NWGUID guidVal;
|
|
int err = SGUIDCreate( &guidVal);
|
|
|
|
if( !err || err == 1) // NOTE: 1 == SGUID_WARN_RANDOM_NODE
|
|
{
|
|
UD2FBA( guidVal.time_low, &pszSerialNum[ 0]);
|
|
UW2FBA( guidVal.time_mid, &pszSerialNum[ 4]);
|
|
UW2FBA( guidVal.time_hi_and_version, &pszSerialNum[ 6]);
|
|
pszSerialNum[ 8] = guidVal.clk_seq_hi_res;
|
|
pszSerialNum[ 9] = guidVal.clk_seq_low;
|
|
f_memcpy( &pszSerialNum[ 10], (FLMBYTE *)guidVal.node, 6);
|
|
goto Exit;
|
|
}
|
|
|
|
#elif defined( FLM_UNIX)
|
|
|
|
// Generate a pseudo GUID value
|
|
|
|
flmAssert( gv_hSerialMutex != F_MUTEX_NULL);
|
|
|
|
f_mutexLock( gv_hSerialMutex);
|
|
|
|
UD2FBA( (FLMUINT32)gv_pSerialRandom->getInt32(), &pszSerialNum[ 0]);
|
|
UD2FBA( (FLMUINT32)gv_pSerialRandom->getInt32(), &pszSerialNum[ 4]);
|
|
UD2FBA( (FLMUINT32)gv_pSerialRandom->getInt32(), &pszSerialNum[ 8]);
|
|
UD2FBA( (FLMUINT32)gv_pSerialRandom->getInt32(), &pszSerialNum[ 12]);
|
|
|
|
f_mutexUnlock( gv_hSerialMutex);
|
|
|
|
#endif
|
|
|
|
#if defined( FLM_WIN) || defined( FLM_NLM)
|
|
Exit:
|
|
#endif
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Generates a table of remainders for each 8-bit byte. The resulting
|
|
table is used by flmUpdateCRC to calculate a CRC value. The table
|
|
must be freed via a call to f_freeCRCTable.
|
|
*****************************************************************************/
|
|
RCODE f_initCRCTable(
|
|
FLMUINT32 ** ppui32CRCTbl)
|
|
{
|
|
RCODE rc = NE_FLM_OK;
|
|
FLMUINT32 * pTable;
|
|
FLMUINT32 ui32Val;
|
|
FLMUINT32 ui32Loop;
|
|
FLMUINT32 ui32SubLoop;
|
|
|
|
// Use the standard degree-32 polynomial used by
|
|
// Ethernet, PKZIP, etc. for computing the CRC of
|
|
// a data stream. This is the little-endian
|
|
// representation of the polynomial. The big-endian
|
|
// representation is 0x04C11DB7.
|
|
|
|
#define CRC_POLYNOMIAL ((FLMUINT32)0xEDB88320)
|
|
|
|
*ppui32CRCTbl = NULL;
|
|
|
|
if( RC_BAD( rc = f_alloc( 256 * sizeof( FLMUINT32), &pTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
for( ui32Loop = 0; ui32Loop < 256; ui32Loop++)
|
|
{
|
|
ui32Val = ui32Loop;
|
|
for( ui32SubLoop = 0; ui32SubLoop < 8; ui32SubLoop++)
|
|
{
|
|
if( ui32Val & 0x00000001)
|
|
{
|
|
ui32Val = CRC_POLYNOMIAL ^ (ui32Val >> 1);
|
|
}
|
|
else
|
|
{
|
|
ui32Val >>= 1;
|
|
}
|
|
}
|
|
|
|
pTable[ ui32Loop] = ui32Val;
|
|
}
|
|
|
|
*ppui32CRCTbl = pTable;
|
|
pTable = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pTable)
|
|
{
|
|
f_free( &pTable);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Computes the CRC of the passed-in data buffer. Multiple calls can
|
|
be made to this routine to build a CRC over multiple data buffers.
|
|
On the first call, *pui32CRC must be initialized to something
|
|
(0, etc.). For generating CRCs that are compatible with PKZIP,
|
|
*pui32CRC should be initialized to 0xFFFFFFFF and the ones complement
|
|
of the resulting CRC should be computed.
|
|
*****************************************************************************/
|
|
void f_updateCRC(
|
|
FLMUINT32 * pui32CRCTbl,
|
|
FLMBYTE * pucBlk,
|
|
FLMUINT uiBlkSize,
|
|
FLMUINT32 * pui32CRC)
|
|
{
|
|
FLMUINT32 ui32CRC = *pui32CRC;
|
|
FLMUINT uiLoop;
|
|
|
|
for( uiLoop = 0; uiLoop < uiBlkSize; uiLoop++)
|
|
{
|
|
ui32CRC = (ui32CRC >> 8) ^ pui32CRCTbl[
|
|
((FLMBYTE)(ui32CRC & 0x000000FF)) ^ pucBlk[ uiLoop]];
|
|
}
|
|
|
|
*pui32CRC = ui32CRC;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FLMUINT f_breakpoint(
|
|
FLMUINT uiBreakFlag)
|
|
{
|
|
if( uiBreakFlag)
|
|
{
|
|
#ifdef FLM_NLM
|
|
EnterDebugger();
|
|
#else
|
|
flmAssert( 0);
|
|
#endif
|
|
}
|
|
|
|
return( 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
void FLMAPI f_getenv(
|
|
const char * pszKey,
|
|
FLMBYTE * pszBuffer,
|
|
FLMUINT uiBufferSize,
|
|
FLMUINT * puiValueLen)
|
|
{
|
|
FLMUINT uiValueLen = 0;
|
|
|
|
if( !uiBufferSize)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pszBuffer[ 0] = 0;
|
|
|
|
#if defined( FLM_WIN) || defined( FLM_UNIX)
|
|
char * pszValue;
|
|
|
|
if( (pszValue = getenv( pszKey)) != NULL &&
|
|
(uiValueLen = f_strlen( pszValue)) < uiBufferSize)
|
|
{
|
|
f_strcpy( (char *)pszBuffer, pszValue);
|
|
}
|
|
#else
|
|
F_UNREFERENCED_PARM( pszKey);
|
|
#endif
|
|
|
|
Exit:
|
|
|
|
if( puiValueLen)
|
|
{
|
|
*puiValueLen = uiValueLen;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Sort an array of items
|
|
****************************************************************************/
|
|
void FLMAPI f_qsort(
|
|
void * pvBuffer,
|
|
FLMUINT uiLowerBounds,
|
|
FLMUINT uiUpperBounds,
|
|
F_SORT_COMPARE_FUNC fnCompare,
|
|
F_SORT_SWAP_FUNC fnSwap)
|
|
{
|
|
FLMUINT uiLBPos;
|
|
FLMUINT uiUBPos;
|
|
FLMUINT uiMIDPos;
|
|
FLMUINT uiCurrentPos;
|
|
FLMUINT uiLeftItems;
|
|
FLMUINT uiRightItems;
|
|
FLMINT iCompare;
|
|
|
|
Iterate_Larger_Half:
|
|
|
|
uiUBPos = uiUpperBounds;
|
|
uiLBPos = uiLowerBounds;
|
|
uiMIDPos = (uiUpperBounds + uiLowerBounds + 1) / 2;
|
|
uiCurrentPos = uiMIDPos;
|
|
|
|
for (;;)
|
|
{
|
|
while (uiLBPos == uiMIDPos ||
|
|
((iCompare =
|
|
fnCompare( pvBuffer, uiLBPos, uiCurrentPos)) < 0))
|
|
{
|
|
if( uiLBPos >= uiUpperBounds)
|
|
{
|
|
break;
|
|
}
|
|
uiLBPos++;
|
|
}
|
|
|
|
while( uiUBPos == uiMIDPos ||
|
|
(((iCompare =
|
|
fnCompare( pvBuffer, uiCurrentPos, uiUBPos)) < 0)))
|
|
{
|
|
if (!uiUBPos)
|
|
{
|
|
break;
|
|
}
|
|
uiUBPos--;
|
|
}
|
|
|
|
if( uiLBPos < uiUBPos)
|
|
{
|
|
// Exchange [uiLBPos] with [uiUBPos].
|
|
|
|
fnSwap( pvBuffer, uiLBPos, uiUBPos);
|
|
uiLBPos++;
|
|
uiUBPos--;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check for swap( LB, MID ) - cases 3 and 4
|
|
|
|
if( uiLBPos < uiMIDPos )
|
|
{
|
|
|
|
// Exchange [uiLBPos] with [uiMIDPos]
|
|
|
|
fnSwap( pvBuffer, uiMIDPos, uiLBPos);
|
|
uiMIDPos = uiLBPos;
|
|
}
|
|
else if( uiMIDPos < uiUBPos )
|
|
{
|
|
// Exchange [uUBPos] with [uiMIDPos]
|
|
|
|
fnSwap( pvBuffer, uiMIDPos, uiUBPos);
|
|
uiMIDPos = uiUBPos;
|
|
}
|
|
|
|
// Check the left piece.
|
|
|
|
uiLeftItems = (uiLowerBounds + 1 < uiMIDPos)
|
|
? uiMIDPos - uiLowerBounds
|
|
: 0;
|
|
|
|
uiRightItems = (uiMIDPos + 1 < uiUpperBounds)
|
|
? uiUpperBounds - uiMIDPos
|
|
: 0;
|
|
|
|
if( uiLeftItems < uiRightItems)
|
|
{
|
|
// Recurse on the LEFT side and goto the top on the RIGHT side.
|
|
|
|
if( uiLeftItems)
|
|
{
|
|
f_qsort( pvBuffer, uiLowerBounds, uiMIDPos - 1, fnCompare, fnSwap);
|
|
}
|
|
|
|
uiLowerBounds = uiMIDPos + 1;
|
|
goto Iterate_Larger_Half;
|
|
}
|
|
else if( uiLeftItems)
|
|
{
|
|
// Recurse on the RIGHT side and goto the top for the LEFT side.
|
|
|
|
if (uiRightItems )
|
|
{
|
|
f_qsort( pvBuffer, uiMIDPos + 1, uiUpperBounds, fnCompare, fnSwap);
|
|
}
|
|
|
|
uiUpperBounds = uiMIDPos - 1;
|
|
goto Iterate_Larger_Half;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FLMINT FLMAPI f_qsortUINTCompare(
|
|
void * pvBuffer,
|
|
FLMUINT uiPos1,
|
|
FLMUINT uiPos2)
|
|
{
|
|
FLMUINT uiLeft = *(((FLMUINT *)pvBuffer) + uiPos1);
|
|
FLMUINT uiRight = *(((FLMUINT *)pvBuffer) + uiPos2);
|
|
|
|
if( uiLeft < uiRight)
|
|
{
|
|
return( -1);
|
|
}
|
|
else if( uiLeft > uiRight)
|
|
{
|
|
return( 1);
|
|
}
|
|
|
|
return( 0);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
void FLMAPI f_qsortUINTSwap(
|
|
void * pvBuffer,
|
|
FLMUINT uiPos1,
|
|
FLMUINT uiPos2)
|
|
{
|
|
FLMUINT * puiArray = (FLMUINT *)pvBuffer;
|
|
FLMUINT uiTmp = puiArray[ uiPos1];
|
|
|
|
puiArray[ uiPos1] = puiArray[ uiPos2];
|
|
puiArray[ uiPos2] = uiTmp;
|
|
}
|