Files
mars-flaim/ftk/src/ftkntab.cpp
ahodgkinson be994dc55c Fixed OS X warnings.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@458 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-05-24 20:17:01 +00:00

1899 lines
41 KiB
C++

//------------------------------------------------------------------------------
// Desc: Class for managing a name table.
//
// Tabs: 3
//
// Copyright (c) 1992, 1994-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: fntable.cpp 3114 2006-01-19 13:22:45 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "ftksys.h"
#if 0
#define MAX_ELEMENTS_TO_LOAD 0xFFFF
#define MAX_ATTRIBUTES_TO_LOAD 0xFFFF
typedef struct
{
FLMUINT uiType;
FLMUNICODE * puzTagName;
FLMUINT uiTagNum;
FLMUINT uiDataType;
FLMUNICODE * puzNamespace;
} FLM_TAG_INFO;
typedef FLMINT (* TAG_COMPARE_FUNC)(
FLM_TAG_INFO * pTagInfo1,
FLM_TAG_INFO * pTagInfo2);
FSTATIC FLMINT tagNameCompare(
const FLMUNICODE * puzName1,
const char * pszName1,
const FLMUNICODE * puzName2);
FSTATIC FLMINT compareTagTypeAndName(
FLM_TAG_INFO * pTagInfo1,
FLM_TAG_INFO * pTagInfo2);
FSTATIC FLMINT compareTagTypeAndNum(
FLM_TAG_INFO * pTagInfo1,
FLM_TAG_INFO * pTagInfo2);
FSTATIC void sortTagTbl(
FLM_TAG_INFO ** ppTagInfoTbl,
FLMUINT uiLowerBounds,
FLMUINT uiUpperBounds,
TAG_COMPARE_FUNC fnTagCompare);
/****************************************************************************
Desc: Class for name/number lookup.
****************************************************************************/
class F_NameTable : public IF_NameTable
{
public:
F_NameTable();
virtual ~F_NameTable();
void FLMAPI clearTable(
FLMUINT uiPoolBlkSize);
RCODE FLMAPI getNextTagTypeAndNumOrder(
FLMUINT uiType,
FLMUINT * puiNextPos,
FLMUNICODE * puzTagName = NULL,
char * pszTagName = NULL,
FLMUINT uiNameBufSize = 0,
FLMUINT * puiTagNum = NULL,
FLMUINT * puiDataType = NULL,
FLMUNICODE * puzNamespace = NULL,
FLMUINT uiNamespaceBufSize = 0,
FLMBOOL bTruncatedNamesOk = TRUE);
RCODE FLMAPI getNextTagTypeAndNameOrder(
FLMUINT uiType,
FLMUINT * puiNextPos,
FLMUNICODE * puzTagName = NULL,
char * pszTagName = NULL,
FLMUINT uiNameBufSize = 0,
FLMUINT * puiTagNum = NULL,
FLMUINT * puiDataType = NULL,
FLMUNICODE * puzNamespace = NULL,
FLMUINT uiNamespaceBufSize = 0,
FLMBOOL bTruncatedNamesOk = TRUE);
RCODE FLMAPI getFromTagTypeAndName(
FLMUINT uiType,
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMBOOL bMatchNamespace,
const FLMUNICODE * puzNamespace = NULL,
FLMUINT * puiTagNum = NULL,
FLMUINT * puiDataType = NULL);
RCODE FLMAPI getFromTagTypeAndNum(
FLMUINT uiType,
FLMUINT uiTagNum,
FLMUNICODE * puzTagName = NULL,
char * pszTagName = NULL,
FLMUINT * puiNameBufSize = NULL,
FLMUINT * puiDataType = NULL,
FLMUNICODE * puzNamespace = NULL,
char * pszNamespace = NULL,
FLMUINT * puiNamespaceBufSize = NULL,
FLMBOOL bTruncatedNamesOk = TRUE);
RCODE FLMAPI addTag(
FLMUINT uiType,
FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT uiTagNum,
FLMUINT uiDataType = 0,
FLMUNICODE * puzNamespace = NULL,
FLMBOOL bCheckDuplicates = TRUE);
void FLMAPI removeTag(
FLMUINT uiType,
FLMUINT uiTagNum);
RCODE FLMAPI cloneNameTable(
IF_NameTable ** ppNewNameTable);
FLMINT FLMAPI AddRef( void);
FLMINT FLMAPI Release( void);
private:
void sortTags( void);
RCODE allocTag(
FLMUINT uiType,
FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT uiTagNum,
FLMUINT uiDataType,
FLMUNICODE * puzNamespace,
FLM_TAG_INFO ** ppTagInfo);
RCODE reallocSortTables(
FLMUINT uiNewTblSize);
RCODE copyTagName(
FLMUNICODE * puzDestTagName,
char * pszDestTagName,
FLMUINT * puiDestBufSize,
FLMUNICODE * puzSrcTagName,
FLMBOOL bTruncatedNamesOk);
FLM_TAG_INFO * findTagByTypeAndNum(
FLMUINT uiType,
FLMUINT uiTagNum,
FLMUINT * puiInsertPos = NULL);
FLM_TAG_INFO * findTagByTypeAndName(
FLMUINT uiType,
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMBOOL bMatchNamespace,
const FLMUNICODE * puzNamespace,
FLMBOOL * pbAmbiguous,
FLMUINT * puiInsertPos = NULL);
RCODE insertTagInTables(
FLM_TAG_INFO * pTagInfo,
FLMUINT uiTagTypeAndNameTblInsertPos,
FLMUINT uiTagTypeAndNumTblInsertPos);
FLMUNICODE * findNamespace(
FLMUNICODE * puzNamespace,
FLMUINT * puiInsertPos);
RCODE insertNamespace(
FLMUNICODE * puzNamespace,
FLMUINT uiInsertPos);
F_Pool m_pool;
FLMUINT m_uiMemoryAllocated;
FLM_TAG_INFO ** m_ppSortedByTagTypeAndName;
FLM_TAG_INFO ** m_ppSortedByTagTypeAndNum;
FLMUINT m_uiTblSize;
FLMUINT m_uiNumTags;
FLMBOOL m_bTablesSorted;
FLMUNICODE ** m_ppuzNamespaces;
FLMUINT m_uiNamespaceTblSize;
FLMUINT m_uiNumNamespaces;
F_MUTEX m_hRefMutex;
};
/****************************************************************************
Desc:
****************************************************************************/
F_NameTable::F_NameTable()
{
m_pool.poolInit( 1024);
m_uiMemoryAllocated = 0;
m_ppSortedByTagTypeAndName = NULL;
m_ppSortedByTagTypeAndNum = NULL;
m_uiTblSize = 0;
m_uiNumTags = 0;
m_bTablesSorted = FALSE;
m_ppuzNamespaces = NULL;
m_uiNamespaceTblSize = 0;
m_uiNumNamespaces = 0;
m_hRefMutex = F_MUTEX_NULL;
}
/****************************************************************************
Desc:
****************************************************************************/
F_NameTable::~F_NameTable()
{
clearTable( 0);
if( m_hRefMutex)
{
f_mutexDestroy( &m_hRefMutex);
}
}
/****************************************************************************
Desc: Free everything in the table
****************************************************************************/
void FLMAPI F_NameTable::clearTable(
FLMUINT uiPoolBlkSize)
{
m_pool.poolFree();
if (uiPoolBlkSize)
{
m_pool.poolInit( uiPoolBlkSize);
}
m_uiMemoryAllocated = 0;
// NOTE: Only one allocation is used for m_ppSortedByTagTypeAndName and
// m_ppSortedByTagTypeAndNum - there is no
// need to free m_ppSortedByTagTypeAndNum
if (m_ppSortedByTagTypeAndName)
{
f_free( &m_ppSortedByTagTypeAndName);
m_ppSortedByTagTypeAndNum = NULL;
m_uiTblSize = 0;
m_uiNumTags = 0;
}
if (m_ppuzNamespaces)
{
f_free( &m_ppuzNamespaces);
m_ppuzNamespaces = NULL;
m_uiNamespaceTblSize = 0;
m_uiNumNamespaces = 0;
}
m_bTablesSorted = FALSE;
}
/****************************************************************************
Desc: Compare two tag names. Name1 can be NATIVE or UNICODE. If a non-NULL
UNICODE string is passed, it will be used. Otherwise, the NATIVE
string will be used.
Note: Comparison is case sensitive. Either or both names may be NULL.
Empty strings and NULL pointers are considered to be equal.
****************************************************************************/
FSTATIC FLMINT tagNameCompare(
const FLMUNICODE * puzName1, // If NULL, use pszName1 for comparison
const char * pszName1,
const FLMUNICODE * puzName2)
{
FLMUNICODE uzChar1;
FLMUNICODE uzChar2;
FLMUNICODE uzLowerChar1;
FLMUNICODE uzLowerChar2;
if (puzName1)
{
if (!puzName2)
{
if (*puzName1)
{
return( 1);
}
else
{
return( 0);
}
}
for (;;)
{
uzChar1 = *puzName1;
uzChar2 = *puzName2;
if (!uzChar1)
{
if (!uzChar2)
{
return( 0);
}
else
{
return( -1);
}
}
else if (!uzChar2)
{
return( 1);
}
else if (uzChar1 != uzChar2)
{
Test_Case:
uzLowerChar1 = f_unitolower( uzChar1);
uzLowerChar2 = f_unitolower( uzChar2);
if (uzLowerChar1 < uzLowerChar2)
{
return( -1);
}
else if (uzLowerChar1 > uzLowerChar2)
{
return( 1);
}
else if (uzLowerChar1 != uzChar1)
{
// Char1 is uppercase, char2 is lowercase
// Uppercase sorts before lowercase
return( -1);
}
else
{
// Char1 is lowercase, char2 is uppercase
// Lowercase sorts after uppercase
return( 1);
}
}
puzName1++;
puzName2++;
}
}
else if (pszName1)
{
if (!puzName2)
{
if (*pszName1)
{
return( 1);
}
else
{
return( 0);
}
}
for (;;)
{
uzChar1 = (FLMUNICODE)*pszName1;
uzChar2 = *puzName2;
if (!uzChar1)
{
if (!uzChar2)
{
return( 0);
}
else
{
return( -1);
}
}
else if (!uzChar2)
{
return( 1);
}
else if (uzChar1 != uzChar2)
{
goto Test_Case;
}
pszName1++;
puzName2++;
}
}
else if (puzName2)
{
// Both name1's are NULL.
if (*puzName2)
{
return( -1);
}
else
{
return( 0);
}
}
else
{
// Both name1 and name2 are NULL.
return( 0);
}
}
/****************************************************************************
Desc: Lookup a tag by type and tag number.
****************************************************************************/
FLM_TAG_INFO * F_NameTable::findTagByTypeAndNum(
FLMUINT uiType,
FLMUINT uiTagNum,
FLMUINT * puiInsertPos)
{
FLM_TAG_INFO * pTagInfo = NULL;
FLMUINT uiTblSize;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMUINT uiTblTagNum;
FLMUINT uiTblType;
if (!m_bTablesSorted)
{
sortTags();
}
// Do binary search in the table
if ((uiTblSize = m_uiNumTags) == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = --uiTblSize;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
uiTblType = m_ppSortedByTagTypeAndNum [uiMid]->uiType;
uiTblTagNum = m_ppSortedByTagTypeAndNum [uiMid]->uiTagNum;
if (uiTblType == uiType && uiTagNum == uiTblTagNum)
{
// Found Match
pTagInfo = m_ppSortedByTagTypeAndNum [uiMid];
if (puiInsertPos)
{
*puiInsertPos = uiMid;
}
goto Exit;
}
// Check if we are done
if (uiLow >= uiHigh)
{
// Done, item not found
if (puiInsertPos)
{
*puiInsertPos = (uiType < uiTblType ||
(uiType == uiTblType && uiTagNum < uiTblTagNum))
? uiMid
: uiMid + 1;
}
goto Exit;
}
if (uiType < uiTblType ||
(uiType == uiTblType && uiTagNum < uiTblTagNum))
{
if (uiMid == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiTblSize)
{
if (puiInsertPos)
{
*puiInsertPos = uiMid + 1;
}
goto Exit;
}
uiLow = uiMid + 1;
}
}
Exit:
return( pTagInfo);
}
/****************************************************************************
Desc: Lookup a tag by tag type and tag name. Tag name is passed in as a
UNICODE string or a NATIVE string. If a non-NULL UNICODE string is
passed in, it will be used. Otherwise, the NATIVE string will be used.
****************************************************************************/
FLM_TAG_INFO * F_NameTable::findTagByTypeAndName(
FLMUINT uiType,
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMBOOL bMatchNamespace,
const FLMUNICODE * puzNamespace,
FLMBOOL * pbAmbiguous,
FLMUINT * puiInsertPos)
{
FLM_TAG_INFO * pTagInfo = NULL;
FLMUINT uiTblType;
FLMUINT uiTblSize;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMINT iCmp;
if (!m_bTablesSorted)
{
sortTags();
}
// Do binary search in the table
*pbAmbiguous = FALSE;
if ((uiTblSize = m_uiNumTags) == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = --uiTblSize;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
uiTblType = m_ppSortedByTagTypeAndName [uiMid]->uiType;
if (uiType < uiTblType)
{
iCmp = -1;
}
else if (uiType > uiTblType)
{
iCmp = 1;
}
else if ((iCmp = tagNameCompare( puzTagName, pszTagName,
m_ppSortedByTagTypeAndName [uiMid]->puzTagName)) == 0)
{
if (!bMatchNamespace)
{
// Better not be trying to insert a new one in this case!
f_assert( puiInsertPos == NULL);
if ((uiMid &&
tagNameCompare( puzTagName, pszTagName,
m_ppSortedByTagTypeAndName [uiMid-1]->puzTagName) == 0) ||
(uiMid < m_uiNumTags - 1 &&
tagNameCompare( puzTagName, pszTagName,
m_ppSortedByTagTypeAndName [uiMid+1]->puzTagName) == 0))
{
*pbAmbiguous = TRUE;
}
}
else
{
iCmp = tagNameCompare( puzNamespace, NULL,
m_ppSortedByTagTypeAndName [uiMid]->puzNamespace);
}
if (iCmp == 0)
{
// Found Match
pTagInfo = m_ppSortedByTagTypeAndName [uiMid];
if (puiInsertPos)
{
*puiInsertPos = uiMid;
}
goto Exit;
}
}
// Check if we are done
if (uiLow >= uiHigh)
{
// Done, item not found
if (puiInsertPos)
{
*puiInsertPos = (iCmp < 0)
? uiMid
: uiMid + 1;
}
goto Exit;
}
if (iCmp < 0)
{
if (uiMid == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiTblSize)
{
if (puiInsertPos)
{
*puiInsertPos = uiMid + 1;
}
goto Exit;
}
uiLow = uiMid + 1;
}
}
Exit:
return( pTagInfo);
}
/****************************************************************************
Desc: Copy a tag name to a UNICODE or NATIVE buffer. Truncate if necessary.
If a non-NULL UNICODE string is passed in, it will be populated.
Otherwise, the NATIVE string will be populated.
****************************************************************************/
RCODE F_NameTable::copyTagName(
FLMUNICODE * puzDestTagName,
char * pszDestTagName,
FLMUINT * puiDestBufSize, // Bytes, must be enough for null terminator
FLMUNICODE * puzSrcTagName, // May be NULL
FLMBOOL bTruncatedNamesOk)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiDestCharCnt = *puiDestBufSize;
FLMUINT uiCharCnt;
if (puzDestTagName)
{
// Decrement name buffer size by sizeof( FLMUNICODE) to allow for a
// terminating NULL character. uiDestChars better be at least big
// enough for a null terminating character.
f_assert( uiDestCharCnt >= sizeof( FLMUNICODE));
uiDestCharCnt /= sizeof( FLMUNICODE);
uiDestCharCnt--;
if (puzSrcTagName)
{
// Copy the name to the UNICODE buffer.
uiCharCnt = 0;
while (uiCharCnt < uiDestCharCnt && *puzSrcTagName)
{
*puzDestTagName++ = *puzSrcTagName;
uiCharCnt++;
puzSrcTagName++;
}
*puzDestTagName = 0;
*puiDestBufSize = uiCharCnt;
if (!bTruncatedNamesOk && *puzSrcTagName)
{
rc = RC_SET( NE_FLM_CONV_DEST_OVERFLOW);
goto Exit;
}
}
else
{
*puzDestTagName = 0;
*puiDestBufSize = 0;
}
}
else
{
// Decrement name buffer size by one to allow for a terminating
// 0 character. uiDestCharCnt better be at list big
// enough for a 0 terminating character.
f_assert( uiDestCharCnt);
uiDestCharCnt--;
if (puzSrcTagName)
{
// Copy the name to the NATIVE buffer. Non-Ascii UNICODE characters
// will cause NE_FLM_CONV_ILLEGAL to be returned.
uiCharCnt = 0;
while (uiCharCnt < uiDestCharCnt && *puzSrcTagName)
{
if (*puzSrcTagName <= 0xFF)
{
*pszDestTagName++ =
(char)f_tonative( (FLMBYTE)*puzSrcTagName);
uiCharCnt++;
puzSrcTagName++;
}
else
{
rc = RC_SET( NE_FLM_CONV_ILLEGAL);
goto Exit;
}
}
*pszDestTagName = 0;
*puiDestBufSize = uiCharCnt;
if (!bTruncatedNamesOk && *puzSrcTagName)
{
rc = RC_SET( NE_FLM_CONV_DEST_OVERFLOW);
goto Exit;
}
}
else
{
*pszDestTagName = 0;
*puiDestBufSize = 0;
}
}
Exit:
return( rc);
}
/***************************************************************************
Desc: Swap two entries in tag info table during sort.
*****************************************************************************/
FINLINE void tagInfoSwap(
FLM_TAG_INFO * * ppTagInfoTbl,
FLMUINT uiPos1,
FLMUINT uiPos2
)
{
FLM_TAG_INFO * pTmpTagInfo = ppTagInfoTbl [uiPos1];
ppTagInfoTbl [uiPos1] = ppTagInfoTbl [uiPos2];
ppTagInfoTbl [uiPos2] = pTmpTagInfo;
}
/***************************************************************************
Desc: Comparison function for sorting by tag type and name.
****************************************************************************/
FSTATIC FLMINT compareTagTypeAndName(
FLM_TAG_INFO * pTagInfo1,
FLM_TAG_INFO * pTagInfo2)
{
FLMINT iCmp;
if (pTagInfo1->uiType < pTagInfo2->uiType)
{
return( -1);
}
else if (pTagInfo1->uiType > pTagInfo2->uiType)
{
return( 1);
}
else if ((iCmp = tagNameCompare( pTagInfo1->puzTagName, NULL,
pTagInfo2->puzTagName)) != 0)
{
return( iCmp);
}
else
{
return( tagNameCompare( pTagInfo1->puzNamespace, NULL,
pTagInfo2->puzNamespace));
}
}
/***************************************************************************
Desc: Comparison function for sorting by tag type and number.
****************************************************************************/
FSTATIC FLMINT compareTagTypeAndNum(
FLM_TAG_INFO * pTagInfo1,
FLM_TAG_INFO * pTagInfo2
)
{
if (pTagInfo1->uiType < pTagInfo2->uiType)
{
return( -1);
}
else if (pTagInfo1->uiType > pTagInfo2->uiType)
{
return( 1);
}
else if (pTagInfo1->uiTagNum < pTagInfo2->uiTagNum)
{
return( -1);
}
else if (pTagInfo1->uiTagNum > pTagInfo2->uiTagNum)
{
return( 1);
}
else
{
return( 0);
}
}
/***************************************************************************
Desc: Sort an array of SCACHE pointers by their block address.
****************************************************************************/
FSTATIC void sortTagTbl(
FLM_TAG_INFO * * ppTagInfoTbl,
FLMUINT uiLowerBounds,
FLMUINT uiUpperBounds,
TAG_COMPARE_FUNC fnTagCompare)
{
FLMUINT uiLBPos;
FLMUINT uiUBPos;
FLMUINT uiMIDPos;
FLMUINT uiLeftItems;
FLMUINT uiRightItems;
FLM_TAG_INFO * pCurTagInfo;
FLMINT iCompare;
Iterate_Larger_Half:
uiUBPos = uiUpperBounds;
uiLBPos = uiLowerBounds;
uiMIDPos = (uiUpperBounds + uiLowerBounds + 1) / 2;
pCurTagInfo = ppTagInfoTbl [uiMIDPos ];
for (;;)
{
while (uiLBPos == uiMIDPos || // Don't compare with target
((iCompare =
fnTagCompare( ppTagInfoTbl [uiLBPos], pCurTagInfo)) < 0))
{
if (uiLBPos >= uiUpperBounds)
{
break;
}
uiLBPos++;
}
while (uiUBPos == uiMIDPos || // Don't compare with target
(((iCompare =
fnTagCompare( pCurTagInfo, ppTagInfoTbl [uiUBPos])) < 0)))
{
if (!uiUBPos)
{
break;
}
uiUBPos--;
}
if (uiLBPos < uiUBPos ) // Interchange and continue loop.
{
// Exchange [uiLBPos] with [uiUBPos].
tagInfoSwap( ppTagInfoTbl, uiLBPos, uiUBPos);
uiLBPos++; // Scan from left to right.
uiUBPos--; // Scan from right to left.
}
else // Past each other - done
{
break;
}
}
// Check for swap( LB, MID ) - cases 3 and 4
if( uiLBPos < uiMIDPos )
{
// Exchange [uiLBPos] with [uiMIDPos]
tagInfoSwap( ppTagInfoTbl, uiMIDPos, uiLBPos);
uiMIDPos = uiLBPos;
}
else if( uiMIDPos < uiUBPos )
{
// Exchange [uUBPos] with [uiMIDPos]
tagInfoSwap( ppTagInfoTbl, uiMIDPos, uiUBPos);
uiMIDPos = uiUBPos;
}
// Check the left piece.
uiLeftItems = (uiLowerBounds + 1 < uiMIDPos )
? uiMIDPos - uiLowerBounds // 2 or more
: 0;
uiRightItems = (uiMIDPos + 1 < uiUpperBounds )
? uiUpperBounds - uiMIDPos // 2 or more
: 0;
if( uiLeftItems < uiRightItems )
{
// Recurse on the LEFT side and goto the top on the RIGHT side.
if (uiLeftItems )
{
sortTagTbl( ppTagInfoTbl, uiLowerBounds, uiMIDPos - 1, fnTagCompare);
}
uiLowerBounds = uiMIDPos + 1;
goto Iterate_Larger_Half;
}
else if (uiLeftItems ) // Compute a truth table to figure out this check.
{
// Recurse on the RIGHT side and goto the top for the LEFT side.
if (uiRightItems )
{
sortTagTbl( ppTagInfoTbl, uiMIDPos + 1, uiUpperBounds, fnTagCompare);
}
uiUpperBounds = uiMIDPos - 1;
goto Iterate_Larger_Half;
}
}
/****************************************************************************
Desc: Lookup a namespace - so we can reuse the memory.
****************************************************************************/
FLMUNICODE * F_NameTable::findNamespace(
FLMUNICODE * puzNamespace,
FLMUINT * puiInsertPos)
{
FLMUNICODE * puzFoundNamespace = NULL;
FLMUINT uiTblSize;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMINT iCmp;
// Do binary search in the table
if ((uiTblSize = m_uiNumNamespaces) == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = --uiTblSize;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
if ((iCmp = tagNameCompare( puzNamespace, NULL,
m_ppuzNamespaces [uiMid])) == 0)
{
// Found Match
puzFoundNamespace = m_ppuzNamespaces [uiMid];
if (puiInsertPos)
{
*puiInsertPos = uiMid;
}
goto Exit;
}
// Check if we are done
if (uiLow >= uiHigh)
{
// Done, item not found
if (puiInsertPos)
{
*puiInsertPos = (iCmp < 0)
? uiMid
: uiMid + 1;
}
goto Exit;
}
if (iCmp < 0)
{
if (uiMid == 0)
{
if (puiInsertPos)
{
*puiInsertPos = 0;
}
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiTblSize)
{
if (puiInsertPos)
{
*puiInsertPos = uiMid + 1;
}
goto Exit;
}
uiLow = uiMid + 1;
}
}
Exit:
return( puzFoundNamespace);
}
/****************************************************************************
Desc: Insert a tag info structure into the sorted tables at the specified
positions.
****************************************************************************/
RCODE F_NameTable::insertNamespace(
FLMUNICODE * puzNamespace,
FLMUINT uiInsertPos)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiLoop;
// See if we need to resize the table. Add 32 each time. There
// should not be that many different namespaces.
if (m_uiNumNamespaces == m_uiNamespaceTblSize)
{
FLMUINT uiNewSize = m_uiNamespaceTblSize + 32;
FLMUNICODE ** ppNewTbl;
if( RC_BAD( rc = f_alloc( sizeof( FLMUNICODE *) * uiNewSize, &ppNewTbl)))
{
goto Exit;
}
// Copy the old tables into the new.
if (m_uiNumNamespaces)
{
f_memcpy( ppNewTbl, m_ppuzNamespaces,
sizeof( FLMUNICODE *) * m_uiNumNamespaces);
f_free( &m_ppuzNamespaces);
}
m_ppuzNamespaces = ppNewTbl;
m_uiNamespaceTblSize = uiNewSize;
}
// Insert the new namespace into the table.
uiLoop = m_uiNumNamespaces;
while (uiLoop > uiInsertPos)
{
m_ppuzNamespaces [uiLoop] = m_ppuzNamespaces [uiLoop - 1];
uiLoop--;
}
m_ppuzNamespaces [uiInsertPos] = puzNamespace;
// Increment the total number of namespaces
m_uiNumNamespaces++;
Exit:
return( rc);
}
/****************************************************************************
Desc: Allocate a new tag info structure and set it up.
****************************************************************************/
RCODE F_NameTable::allocTag(
FLMUINT uiType,
FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT uiTagNum,
FLMUINT uiDataType,
FLMUNICODE * puzNamespace,
FLM_TAG_INFO ** ppTagInfo)
{
RCODE rc = NE_FLM_OK;
void * pvMark;
FLMUINT uiSaveMemoryAllocated;
FLM_TAG_INFO * pTagInfo;
FLMUINT uiNameSize;
FLMUNICODE * puzTmp;
FLMUNICODE * puzTblNamespace;
FLMUINT uiNamespaceInsertPos;
// Create a new tag info structure.
pvMark = m_pool.poolMark();
uiSaveMemoryAllocated = m_uiMemoryAllocated;
if (RC_BAD( rc = m_pool.poolCalloc( sizeof( FLM_TAG_INFO),
(void **)&pTagInfo)))
{
goto Exit;
}
m_uiMemoryAllocated += sizeof( FLM_TAG_INFO);
// Allocate the space for the tag name.
if (puzTagName)
{
uiNameSize = (f_unilen( puzTagName) + 1) * sizeof( FLMUNICODE);
if (RC_BAD( rc = m_pool.poolAlloc( uiNameSize,
(void **)&pTagInfo->puzTagName)))
{
goto Exit;
}
m_uiMemoryAllocated += uiNameSize;
f_memcpy( pTagInfo->puzTagName, puzTagName, uiNameSize);
}
else
{
uiNameSize = (f_strlen( pszTagName) + 1) * sizeof( FLMUNICODE);
if (RC_BAD( rc = m_pool.poolAlloc( uiNameSize,
(void **)&pTagInfo->puzTagName)))
{
goto Exit;
}
m_uiMemoryAllocated += uiNameSize;
puzTmp = pTagInfo->puzTagName;
while (*pszTagName)
{
*puzTmp++ = (FLMUNICODE)*pszTagName;
pszTagName++;
}
*puzTmp = 0;
}
pTagInfo->uiType = uiType;
pTagInfo->uiTagNum = uiTagNum;
pTagInfo->uiDataType = uiDataType;
if (puzNamespace && *puzNamespace)
{
// See if we have already allocated the namespace. If so, just
// point to it. Otherwise, allocate it and add it to the
// namespace table and then point to it.
if ((puzTblNamespace = findNamespace( puzNamespace,
&uiNamespaceInsertPos)) == NULL)
{
uiNameSize = (f_unilen( puzNamespace) + 1) * sizeof( FLMUNICODE);
if (RC_BAD( rc = m_pool.poolAlloc( uiNameSize,
(void **)&puzTblNamespace)))
{
goto Exit;
}
m_uiMemoryAllocated += uiNameSize;
f_memcpy( puzTblNamespace, puzNamespace, uiNameSize);
if (RC_BAD( rc = insertNamespace( puzTblNamespace,
uiNamespaceInsertPos)))
{
goto Exit;
}
// Need to re-mark the pool after this point, because
// we can now not afford to lose the namespace that was
// allocated if the pool is reset at Exit due to a later
// error.
pvMark = m_pool.poolMark();
uiSaveMemoryAllocated = m_uiMemoryAllocated;
}
pTagInfo->puzNamespace = puzTblNamespace;
}
Exit:
if (RC_BAD( rc))
{
m_pool.poolReset( pvMark);
m_uiMemoryAllocated = uiSaveMemoryAllocated;
pTagInfo = NULL;
}
*ppTagInfo = pTagInfo;
return( rc);
}
/****************************************************************************
Desc: Allocate the sort tables.
****************************************************************************/
RCODE F_NameTable::reallocSortTables(
FLMUINT uiNewTblSize)
{
RCODE rc = NE_FLM_OK;
FLM_TAG_INFO ** ppNewTbl;
if( RC_BAD( f_alloc(
sizeof( FLM_TAG_INFO *) * uiNewTblSize * 2, &ppNewTbl)))
{
goto Exit;
}
// Copy the old tables into the new.
if (m_uiNumTags)
{
f_memcpy( ppNewTbl, m_ppSortedByTagTypeAndName,
sizeof( FLM_TAG_INFO *) * m_uiNumTags);
f_memcpy( &ppNewTbl [uiNewTblSize],
m_ppSortedByTagTypeAndNum,
sizeof( FLM_TAG_INFO *) * m_uiNumTags);
f_free( &m_ppSortedByTagTypeAndName);
}
m_ppSortedByTagTypeAndName = ppNewTbl;
m_ppSortedByTagTypeAndNum = &ppNewTbl [uiNewTblSize];
m_uiTblSize = uiNewTblSize;
Exit:
return( rc);
}
/****************************************************************************
Desc: Get a tag name, number, etc. using type + tag number ordering.
Tag name is returned as a UNICODE string or NATIVE string. If a
non-NULL UNICODE string is passed in, it will be used.
Otherwise, the NATIVE string will be used.
****************************************************************************/
RCODE FLMAPI F_NameTable::getNextTagTypeAndNumOrder(
FLMUINT uiType,
FLMUINT * puiNextPos,
FLMUNICODE * puzTagName, // May be NULL
char * pszTagName, // May be NULL
FLMUINT uiNameBufSize,
FLMUINT * puiTagNum, // May be NULL
FLMUINT * puiDataType, // May be NULL
FLMUNICODE * puzNamespace, // May be NULL
FLMUINT uiNamespaceBufSize,
FLMBOOL bTruncatedNamesOk)
{
RCODE rc = NE_FLM_OK;
FLM_TAG_INFO * pTagInfo = NULL;
FLMBOOL bFound = FALSE;
if (!m_bTablesSorted)
{
sortTags();
}
while (*puiNextPos < m_uiNumTags)
{
pTagInfo = m_ppSortedByTagTypeAndNum [*puiNextPos];
if (pTagInfo->uiType == uiType)
{
bFound = TRUE;
if (puiTagNum)
{
*puiTagNum = pTagInfo->uiTagNum;
}
if( puzTagName || pszTagName)
{
if (RC_BAD( rc = copyTagName( puzTagName, pszTagName,
&uiNameBufSize,
pTagInfo->puzTagName, bTruncatedNamesOk)))
{
goto Exit;
}
}
if (puiDataType)
{
*puiDataType = pTagInfo->uiDataType;
}
if (puzNamespace)
{
if (RC_BAD( rc = copyTagName( puzNamespace, NULL,
&uiNamespaceBufSize,
pTagInfo->puzNamespace,
bTruncatedNamesOk)))
{
goto Exit;
}
}
// Returned *puiNextPos should be the next one to retrieve.
(*puiNextPos)++;
break;
}
else if (pTagInfo->uiType > uiType)
{
break;
}
else
{
(*puiNextPos)++;
}
}
if (!bFound)
{
rc = RC_SET( NE_FLM_EOF_HIT);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Get a tag name, number, etc. using type + tag name ordering.
Tag name is returned as a UNICODE string or NATIVE string. If a
non-NULL UNICODE string is passed in, it will be used.
Otherwise, the NATIVE string will be used.
****************************************************************************/
RCODE FLMAPI F_NameTable::getNextTagTypeAndNameOrder(
FLMUINT uiType,
FLMUINT * puiNextPos,
FLMUNICODE * puzTagName, // May be NULL
char * pszTagName, // May be NULL
FLMUINT uiNameBufSize,
FLMUINT * puiTagNum, // May be NULL
FLMUINT * puiDataType, // May be NULL
FLMUNICODE * puzNamespace, // May be NULL
FLMUINT uiNamespaceBufSize,
FLMBOOL bTruncatedNamesOk)
{
RCODE rc = NE_FLM_OK;
FLM_TAG_INFO * pTagInfo = NULL;
FLMBOOL bFound = FALSE;
if (!m_bTablesSorted)
{
sortTags();
}
while (*puiNextPos < m_uiNumTags)
{
pTagInfo = m_ppSortedByTagTypeAndName [*puiNextPos];
if (pTagInfo->uiType == uiType)
{
bFound = TRUE;
if (puiTagNum)
{
*puiTagNum = pTagInfo->uiTagNum;
}
if (puzTagName || pszTagName)
{
if (RC_BAD( rc = copyTagName( puzTagName, pszTagName,
&uiNameBufSize, pTagInfo->puzTagName,
bTruncatedNamesOk)))
{
goto Exit;
}
}
if (puiDataType)
{
*puiDataType = pTagInfo->uiDataType;
}
if (puzNamespace)
{
if (RC_BAD( rc = copyTagName( puzNamespace, NULL,
&uiNamespaceBufSize,
pTagInfo->puzNamespace,
bTruncatedNamesOk)))
{
goto Exit;
}
}
// Returned *puiNextPos should be the next one to retrieve.
(*puiNextPos)++;
break;
}
else if (pTagInfo->uiType > uiType)
{
break;
}
else
{
(*puiNextPos)++;
}
}
if (!bFound)
{
rc = RC_SET( NE_FLM_EOF_HIT);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Get a tag name from its tag type and number. Tag name is returned as a
UNICODE string or NATIVE string. If a non-NULL UNICODE string is passed
in, it will be used. Otherwise, the NATIVE string will be used.
****************************************************************************/
RCODE FLMAPI F_NameTable::getFromTagTypeAndNum(
FLMUINT uiType,
FLMUINT uiTagNum,
FLMUNICODE * puzTagName, // May be NULL
char * pszTagName, // May be NULL
FLMUINT * puiNameBufSize, // May be NULL, returns # characters
FLMUINT * puiDataType, // May be NULL
FLMUNICODE * puzNamespace, // May be NULL
char * pszNamespace, // May be NULL
FLMUINT * puiNamespaceBufSize, // May be NULL, returns # characters
FLMBOOL bTruncatedNamesOk)
{
RCODE rc = NE_FLM_OK;
FLM_TAG_INFO * pTagInfo;
FLMUNICODE * puzTmpNamespace = NULL;
FLMUNICODE * puzTmpName = NULL;
if ((pTagInfo = findTagByTypeAndNum( uiType, uiTagNum)) != NULL)
{
if( puzTagName || pszTagName)
{
if (RC_BAD( rc = copyTagName( puzTagName, pszTagName,
puiNameBufSize,
pTagInfo->puzTagName, bTruncatedNamesOk)))
{
goto Exit;
}
}
else if (puiNameBufSize)
{
*puiNameBufSize = f_unilen( pTagInfo->puzTagName);
}
if (puiDataType)
{
*puiDataType = pTagInfo->uiDataType;
}
if (puzNamespace || pszNamespace)
{
if (RC_BAD( rc = copyTagName( puzNamespace, pszNamespace,
puiNamespaceBufSize,
pTagInfo->puzNamespace,
bTruncatedNamesOk)))
{
goto Exit;
}
}
else if (puiNamespaceBufSize)
{
*puiNamespaceBufSize = f_unilen( pTagInfo->puzNamespace);
}
}
else
{
rc = RC_SET( NE_FLM_NOT_FOUND);
goto Exit;
}
Exit:
if (puzTmpName)
{
f_free( &puzTmpName);
}
if (puzTmpNamespace)
{
f_free( &puzTmpNamespace);
}
return( rc);
}
/****************************************************************************
Desc: Get a tag number from its tag name and type. Tag name is passed
in as a UNICODE or NATIVE string. If a non-NULL UNICODE string is
passed in, it will be used. Otherwise, the NATIVE string will
be used.
****************************************************************************/
RCODE FLMAPI F_NameTable::getFromTagTypeAndName(
FLMUINT uiType,
const FLMUNICODE * puzTagName,
const char * pszTagName,
FLMBOOL bMatchNamespace,
const FLMUNICODE * puzNamespace,
FLMUINT * puiTagNum, // May be NULL
FLMUINT * puiDataType) // May be NULL
{
RCODE rc = NE_FLM_OK;
FLM_TAG_INFO * pTagInfo;
FLMBOOL bAmbiguous;
if ((pTagInfo = findTagByTypeAndName( uiType,
puzTagName, pszTagName, bMatchNamespace,
puzNamespace,
&bAmbiguous)) != NULL)
{
if (puiTagNum)
{
*puiTagNum = pTagInfo->uiTagNum;
}
if (puiDataType)
{
*puiDataType = pTagInfo->uiDataType;
}
if (bAmbiguous)
{
rc = RC_SET( NE_FLM_MULTIPLE_MATCHES);
goto Exit;
}
}
else
{
rc = RC_SET( NE_FLM_NOT_FOUND);
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Insert a tag info structure into the sorted tables at the specified
positions.
****************************************************************************/
RCODE F_NameTable::insertTagInTables(
FLM_TAG_INFO * pTagInfo,
FLMUINT uiTagTypeAndNameTblInsertPos,
FLMUINT uiTagTypeAndNumTblInsertPos)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiLoop;
// See if we need to resize the tables. Start at 256. Double each
// time up to 2048. Then just add 2048 at a time.
if (m_uiNumTags == m_uiTblSize)
{
FLMUINT uiNewSize;
if (!m_uiTblSize)
{
uiNewSize = 256;
}
else if (m_uiTblSize < 2048)
{
uiNewSize = m_uiTblSize * 2;
}
else
{
uiNewSize = m_uiTblSize + 2048;
}
if (RC_BAD( rc = reallocSortTables( uiNewSize)))
{
goto Exit;
}
}
// Insert into the sorted-by-tag-type-and-name table
uiLoop = m_uiNumTags;
while (uiLoop > uiTagTypeAndNameTblInsertPos)
{
m_ppSortedByTagTypeAndName [uiLoop] =
m_ppSortedByTagTypeAndName [uiLoop - 1];
uiLoop--;
}
m_ppSortedByTagTypeAndName [uiTagTypeAndNameTblInsertPos] = pTagInfo;
// Insert into the sorted-by-tag-type-and-num table
uiLoop = m_uiNumTags;
while (uiLoop > uiTagTypeAndNumTblInsertPos)
{
m_ppSortedByTagTypeAndNum [uiLoop] =
m_ppSortedByTagTypeAndNum [uiLoop - 1];
uiLoop--;
}
m_ppSortedByTagTypeAndNum [uiTagTypeAndNumTblInsertPos] = pTagInfo;
// Increment the total number of tags
m_uiNumTags++;
Exit:
return( rc);
}
/****************************************************************************
Desc: Add a tag to the table. Tag name is passed in as a UNICODE string or
NATIVE string. If a non-NULL UNICODE string is passed in, it will
be used. Otherwise, the NATIVE string will be used.
****************************************************************************/
RCODE FLMAPI F_NameTable::addTag(
FLMUINT uiType,
FLMUNICODE * puzTagName,
const char * pszTagName,
FLMUINT uiTagNum,
FLMUINT uiDataType,
FLMUNICODE * puzNamespace,
FLMBOOL bCheckDuplicates)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiTagTypeAndNameTblInsertPos;
FLMUINT uiTagTypeAndNumTblInsertPos;
FLM_TAG_INFO * pTagInfo;
FLMBOOL bAmbiguous;
// Must have a non-NULL tag name. Use UNICODE string if it is
// non-NULL. Otherwise, use NATIVE string.
if (puzTagName && *puzTagName)
{
pszTagName = NULL;
}
else if (pszTagName && *pszTagName)
{
puzTagName = NULL;
}
else
{
rc = RC_SET_AND_ASSERT( NE_FLM_INVALID_PARM);
goto Exit;
}
// Tag number of zero not allowed.
if (!uiTagNum)
{
rc = RC_SET_AND_ASSERT( NE_FLM_INVALID_PARM);
goto Exit;
}
// Tables must be sorted in order for this to work
if (bCheckDuplicates)
{
// Make sure that the tag type + name is not already used.
if (findTagByTypeAndName( uiType, puzTagName, pszTagName,
TRUE, puzNamespace,
&bAmbiguous, &uiTagTypeAndNameTblInsertPos))
{
rc = RC_SET( NE_FLM_EXISTS);
goto Exit;
}
// Make sure that the tag type + number is not already used.
if (findTagByTypeAndNum( uiType, uiTagNum,
&uiTagTypeAndNumTblInsertPos))
{
rc = RC_SET( NE_FLM_EXISTS);
goto Exit;
}
}
else
{
uiTagTypeAndNameTblInsertPos = uiTagTypeAndNumTblInsertPos = m_uiNumTags;
m_bTablesSorted = FALSE;
}
// Create a new tag info structure.
if (RC_BAD( rc = allocTag( uiType, puzTagName, pszTagName, uiTagNum,
uiDataType, puzNamespace, &pTagInfo)))
{
goto Exit;
}
// Insert the tag structure into the appropriate places in the
// sorted tables.
if (RC_BAD( rc = insertTagInTables( pTagInfo,
uiTagTypeAndNameTblInsertPos,
uiTagTypeAndNumTblInsertPos)))
{
goto Exit;
}
Exit:
return( rc);
}
/****************************************************************************
Desc: Sort the tag tables according to their respective criteria.
****************************************************************************/
void F_NameTable::sortTags( void)
{
if (!m_bTablesSorted && m_uiNumTags > 1)
{
sortTagTbl( m_ppSortedByTagTypeAndName, 0, m_uiNumTags - 1,
compareTagTypeAndName);
sortTagTbl( m_ppSortedByTagTypeAndNum, 0, m_uiNumTags - 1,
compareTagTypeAndNum);
}
m_bTablesSorted = TRUE;
}
/****************************************************************************
Desc: Remove a tag from the table
****************************************************************************/
void FLMAPI F_NameTable::removeTag(
FLMUINT uiType,
FLMUINT uiTagNum)
{
FLM_TAG_INFO * pTagInfo;
FLMUINT uiTagTypeAndNameTblPos;
FLMUINT uiTagTypeAndNumTblPos;
FLMBOOL bAmbiguous;
FLMBOOL bMatchNamespace;
FLMUNICODE * puzNamespace;
if ((pTagInfo = findTagByTypeAndNum( uiType, uiTagNum,
&uiTagTypeAndNumTblPos)) != NULL)
{
puzNamespace = pTagInfo->puzNamespace;
bMatchNamespace = TRUE;
if (findTagByTypeAndName( uiType, pTagInfo->puzTagName,
NULL, bMatchNamespace,
puzNamespace, &bAmbiguous,
&uiTagTypeAndNameTblPos) == NULL)
{
// It should have been in the name table too!
f_assert( 0);
}
// Shift everything in the sorted number table that is above
// the found position down one.
if (uiTagTypeAndNumTblPos < m_uiNumTags - 1)
{
f_memmove( &m_ppSortedByTagTypeAndNum [uiTagTypeAndNumTblPos],
&m_ppSortedByTagTypeAndNum [uiTagTypeAndNumTblPos + 1],
sizeof( FLM_TAG_INFO *) *
(m_uiNumTags - 1 - uiTagTypeAndNumTblPos));
}
// Shift everything in the sorted name table that is above
// the found position down one.
if (uiTagTypeAndNameTblPos < m_uiNumTags - 1)
{
f_memmove( &m_ppSortedByTagTypeAndName [uiTagTypeAndNameTblPos],
&m_ppSortedByTagTypeAndName [uiTagTypeAndNameTblPos + 1],
sizeof( FLM_TAG_INFO *) *
(m_uiNumTags - 1 - uiTagTypeAndNameTblPos));
}
m_uiNumTags--;
}
}
/****************************************************************************
Desc: Create a clone of this name table
****************************************************************************/
RCODE FLMAPI F_NameTable::cloneNameTable(
IF_NameTable ** ppNewNameTable)
{
RCODE rc = NE_FLM_OK;
FLMUINT uiLoop;
FLM_TAG_INFO * pTagInfo;
FLMUINT uiPoolBlkSize;
F_NameTable * pNewNameTable = NULL;
// Allocate a new name table
if( (pNewNameTable = f_new F_NameTable) == NULL)
{
rc = RC_SET( NE_FLM_MEM);
goto Exit;
}
// Set the pool size to be as optimal as possible.
uiPoolBlkSize = m_uiMemoryAllocated / 8;
if (uiPoolBlkSize < 1024)
{
uiPoolBlkSize = 1024;
}
else if (uiPoolBlkSize > 65536)
{
uiPoolBlkSize = 65536;
}
pNewNameTable->clearTable( uiPoolBlkSize);
// Pre-allocate exactly enough table space
if (RC_BAD( rc = pNewNameTable->reallocSortTables( m_uiNumTags)))
{
goto Exit;
}
// Add all of the tags
for (uiLoop = 0; uiLoop < m_uiNumTags; uiLoop++)
{
pTagInfo = m_ppSortedByTagTypeAndNum [uiLoop];
if (RC_BAD( rc = pNewNameTable->addTag(
pTagInfo->uiType, pTagInfo->puzTagName, NULL, pTagInfo->uiTagNum,
pTagInfo->uiDataType, pTagInfo->puzNamespace, FALSE)))
{
goto Exit;
}
}
pNewNameTable->sortTags();
*ppNewNameTable = pNewNameTable;
pNewNameTable = NULL;
Exit:
if( pNewNameTable)
{
pNewNameTable->Release();
}
return( rc);
}
/****************************************************************************
Desc: Increment use count on this object.
****************************************************************************/
FLMINT FLMAPI F_NameTable::AddRef( void)
{
return( f_atomicInc( &m_refCnt));
}
/****************************************************************************
Desc: Decrement the use count and delete if use count goes to zero.
****************************************************************************/
FLMINT FLMAPI F_NameTable::Release( void)
{
FLMINT iRefCnt;
if ((iRefCnt = f_atomicDec( &m_refCnt)) == 0)
{
delete this;
}
return( iRefCnt);
}
#endif
#if defined( FLM_WATCOM_NLM) || defined( FLM_OSX)
void gv_ftkntab( void)
{
}
#endif