git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@112 0109f412-320b-0410-ab79-c3e0c5ffbbe6
707 lines
15 KiB
C++
707 lines
15 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Various utility functions
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1991-1993,1996-2000,2002-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: flutil.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
#define HANDLE_NEGATIVE \
|
|
if( value < 0) \
|
|
{ *ptr++ = '-'; \
|
|
absValue = (FLMUINT)(-(value)); \
|
|
} \
|
|
else absValue = (FLMUINT)value;
|
|
|
|
#define HANDLE_DNEGATIVE \
|
|
if( value < 0) \
|
|
{ *ptr++ = '-'; \
|
|
absValue = (FLMUINT)(-(value)); \
|
|
} \
|
|
else absValue = (FLMUINT)value;
|
|
|
|
#define PUSH_DIGITS( v) \
|
|
{register FLMUINT reg = v; \
|
|
do{ *sp++ = (FLMBYTE)((reg % 10) + '0'); \
|
|
} while( reg /= 10); \
|
|
}
|
|
|
|
#define POP_DIGITS \
|
|
while( stack < sp--)\
|
|
*ptr++ = *sp; \
|
|
*ptr = '\0';
|
|
|
|
#if defined( FLM_NLM) && defined ( __MWERKS__)
|
|
void abort(void);
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Unsigned word to NATIVE value - null terminate the native string
|
|
****************************************************************************/
|
|
FLMEXP char * FLMAPI f_uwtoa(
|
|
FLMUINT16 value,
|
|
char * ptr)
|
|
{
|
|
char stack[ 10];
|
|
char * sp = stack;
|
|
|
|
PUSH_DIGITS( value);
|
|
POP_DIGITS;
|
|
|
|
return( ptr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Native to UDWORD value. Supports 0x<HEX> codes. Non digits NOT ALLOWED
|
|
NO LEADING SPACES ALLOWED ! ! ! No checks for overflow over 4 bytes!
|
|
****************************************************************************/
|
|
FLMEXP FLMUINT FLMAPI f_atoud(
|
|
const char * pszBuf)
|
|
{
|
|
FLMUINT uiValue;
|
|
FLMBOOL bAllowHex = FALSE;
|
|
|
|
if( *pszBuf == NATIVE_ZERO &&
|
|
(*(pszBuf + 1) == NATIVE_LOWER_X || *(pszBuf + 1) == NATIVE_UPPER_X))
|
|
{
|
|
pszBuf += 2;
|
|
bAllowHex = TRUE;
|
|
}
|
|
|
|
uiValue = 0;
|
|
while( *pszBuf)
|
|
{
|
|
if( *pszBuf >= '0' && *pszBuf <= '9')
|
|
{
|
|
if( !bAllowHex)
|
|
{
|
|
uiValue *= 10;
|
|
}
|
|
else
|
|
{
|
|
uiValue <<= 4;
|
|
}
|
|
|
|
uiValue += (FLMUINT)(*pszBuf - '0');
|
|
}
|
|
else if( bAllowHex)
|
|
{
|
|
if( *pszBuf >= 'A' && *pszBuf <= 'F')
|
|
{
|
|
uiValue <<= 4;
|
|
uiValue += (FLMUINT)(*pszBuf - 'A') + 10;
|
|
}
|
|
else if( *pszBuf >= 'a' && *pszBuf <= 'f')
|
|
{
|
|
uiValue <<= 4;
|
|
uiValue += (FLMUINT)(*pszBuf - 'a') + 10;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
pszBuf++;
|
|
}
|
|
|
|
return( uiValue);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Unsigned double (4 byte) number to native value & null terminate
|
|
****************************************************************************/
|
|
FLMEXP char * FLMAPI f_udtoa(
|
|
FLMUINT value,
|
|
char * ptr)
|
|
{
|
|
char stack[ 10];
|
|
char * sp = stack;
|
|
|
|
PUSH_DIGITS( value);
|
|
POP_DIGITS;
|
|
|
|
return( ptr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Word to native value - null terminate the native string
|
|
****************************************************************************/
|
|
FLMEXP char * FLMAPI f_wtoa(
|
|
FLMINT16 value,
|
|
char * ptr)
|
|
{
|
|
char stack[ 10];
|
|
char * sp = stack;
|
|
FLMUINT absValue;
|
|
|
|
HANDLE_NEGATIVE;
|
|
PUSH_DIGITS( absValue);
|
|
POP_DIGITS;
|
|
|
|
return( ptr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Double (4 byte) number to native value - null terminate the string
|
|
****************************************************************************/
|
|
FLMEXP char * FLMAPI f_dtoa(
|
|
FLMINT value,
|
|
char * ptr)
|
|
{
|
|
char stack[ 10];
|
|
char * sp = stack;
|
|
FLMUINT absValue;
|
|
|
|
HANDLE_DNEGATIVE;
|
|
PUSH_DIGITS( absValue);
|
|
POP_DIGITS;
|
|
|
|
return( ptr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Ascii to integer
|
|
****************************************************************************/
|
|
FLMEXP FLMINT FLMAPI f_atoi(
|
|
const char * ptr)
|
|
{
|
|
return( f_atod( ptr));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: native to long
|
|
****************************************************************************/
|
|
FLMEXP FLMINT FLMAPI f_atol(
|
|
const char * ptr)
|
|
{
|
|
return( f_atod( ptr));
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Native to DWORD value. Supports 0x<HEX> codes. Non digits NOT ALLOWED
|
|
NO LEADING SPACES ALLOWED ! ! ! No checks for overflow over 4 bytes!
|
|
****************************************************************************/
|
|
FLMEXP FLMINT FLMAPI f_atod(
|
|
const char * pszBuf)
|
|
{
|
|
FLMINT iValue;
|
|
FLMBOOL bNeg = FALSE;
|
|
|
|
if( *pszBuf == '-')
|
|
{
|
|
bNeg = TRUE;
|
|
pszBuf++;
|
|
}
|
|
else if( *pszBuf == '+')
|
|
{
|
|
pszBuf++;
|
|
}
|
|
|
|
iValue = (FLMINT)f_atoud( pszBuf);
|
|
return( bNeg ? -iValue : iValue);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Utility function to return the maximum size of a hex number
|
|
represented as a string.
|
|
****************************************************************************/
|
|
FINLINE FLMUINT maxHexSize(
|
|
FLMUINT uiSizeOfPtr)
|
|
{
|
|
return uiSizeOfPtr * 2;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Utility function to return the maximum size of a decimal number
|
|
represented as a string.
|
|
****************************************************************************/
|
|
FINLINE FLMUINT maxDecimalSize(
|
|
FLMUINT uiSizeOfPtr)
|
|
{
|
|
switch (uiSizeOfPtr)
|
|
{
|
|
case 4:
|
|
return 10;
|
|
case 8:
|
|
return 20;
|
|
default:
|
|
flmAssert( 0);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Compares two Unicode strings
|
|
****************************************************************************/
|
|
FLMEXP FLMINT FLMAPI f_unicmp(
|
|
const FLMUNICODE * puzStr1,
|
|
const FLMUNICODE * puzStr2)
|
|
{
|
|
while( *puzStr1 == *puzStr2 && *puzStr1)
|
|
{
|
|
puzStr1++;
|
|
puzStr2++;
|
|
}
|
|
|
|
return( (FLMINT)*puzStr1 - (FLMINT)*puzStr2);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns the length of a unicode string
|
|
****************************************************************************/
|
|
FLMEXP FLMUINT FLMAPI f_unilen(
|
|
const FLMUNICODE * puzStr)
|
|
{
|
|
FLMUINT uiLen = 0;
|
|
|
|
if( !puzStr)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
while( *puzStr)
|
|
{
|
|
puzStr++;
|
|
uiLen++;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( uiLen);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Finds a substring
|
|
****************************************************************************/
|
|
FLMEXP FLMUNICODE * FLMAPI f_uniindex(
|
|
const FLMUNICODE * puzStr,
|
|
const FLMUNICODE * puzSearch)
|
|
{
|
|
const FLMUNICODE * puzSearchPos;
|
|
const FLMUNICODE * puzStrPos;
|
|
FLMUNICODE uFirstChar;
|
|
|
|
if( !puzStr || !puzSearch || (uFirstChar = *puzSearch) == 0)
|
|
{
|
|
return( NULL);
|
|
}
|
|
|
|
do
|
|
{
|
|
while( *puzStr)
|
|
{
|
|
if( *puzStr == uFirstChar)
|
|
{
|
|
break;
|
|
}
|
|
puzStr++;
|
|
}
|
|
|
|
if( *puzStr == 0)
|
|
{
|
|
return( NULL);
|
|
}
|
|
|
|
if( *(puzSearch + 1) == 0)
|
|
{
|
|
return( (FLMUNICODE *)puzStr);
|
|
}
|
|
|
|
for( puzSearchPos = puzSearch + 1, puzStrPos = puzStr + 1;
|
|
*puzSearchPos == *puzStrPos; puzSearchPos++, puzStrPos++)
|
|
{
|
|
if( puzSearchPos[ 1] == 0)
|
|
{
|
|
return( (FLMUNICODE *)puzStr);
|
|
}
|
|
}
|
|
|
|
puzStr++;
|
|
} while( *puzStr);
|
|
|
|
return( NULL);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: The equivalent of strncmp for unicode strings.
|
|
****************************************************************************/
|
|
FLMEXP FLMINT FLMAPI f_unincmp(
|
|
const FLMUNICODE * puzStr1,
|
|
const FLMUNICODE * puzStr2,
|
|
FLMUINT uiLen)
|
|
{
|
|
if( !uiLen)
|
|
{
|
|
return( 0);
|
|
}
|
|
|
|
while( *puzStr1 == *puzStr2 && *puzStr1 && --uiLen)
|
|
{
|
|
puzStr1++;
|
|
puzStr2++;
|
|
}
|
|
|
|
return( *puzStr1 - *puzStr2);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Compares two strings, one Unicode and one native
|
|
****************************************************************************/
|
|
FLMEXP FLMINT FLMAPI f_uninativecmp(
|
|
const FLMUNICODE * puzStr1,
|
|
const char * pszStr2)
|
|
{
|
|
while( *puzStr1 == ((FLMUNICODE)f_toascii( *pszStr2)) && *puzStr1)
|
|
{
|
|
puzStr1++;
|
|
pszStr2++;
|
|
}
|
|
|
|
return( (FLMINT)*puzStr1 - (FLMINT)*pszStr2);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Compares two strings, one Unicode and one native
|
|
****************************************************************************/
|
|
FLMEXP FLMINT FLMAPI f_uninativencmp(
|
|
const FLMUNICODE * puzStr1,
|
|
const char * pszStr2,
|
|
FLMUINT uiCount)
|
|
{
|
|
if( !uiCount)
|
|
{
|
|
return( 0);
|
|
}
|
|
|
|
while( uiCount &&
|
|
*puzStr1 == ((FLMUNICODE)f_toascii( *pszStr2)) && *puzStr1)
|
|
{
|
|
puzStr1++;
|
|
pszStr2++;
|
|
uiCount--;
|
|
}
|
|
|
|
return( uiCount ? ((FLMINT)*puzStr1 - (FLMINT)*pszStr2) : 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Copies a unicode string
|
|
****************************************************************************/
|
|
FLMEXP FLMUNICODE * FLMAPI f_unicpy(
|
|
FLMUNICODE * puzDestStr,
|
|
const FLMUNICODE * puzSrcStr)
|
|
{
|
|
const FLMUNICODE * puzSrc = puzSrcStr;
|
|
FLMUNICODE * puzDest = puzDestStr;
|
|
|
|
while( *puzSrc)
|
|
{
|
|
*puzDest++ = *puzSrc++;
|
|
}
|
|
|
|
*puzDest = 0;
|
|
return( puzDestStr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Copies a native string into a Unicode buffer
|
|
****************************************************************************/
|
|
FLMEXP void FLMAPI f_nativetounistrcpy(
|
|
FLMUNICODE * puzDest,
|
|
const char * pszSrc)
|
|
{
|
|
while( *pszSrc)
|
|
{
|
|
*puzDest++ = f_toascii( *pszSrc++);
|
|
}
|
|
*puzDest = 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Abort function. Required only when compiling with Codewarrior. For
|
|
some reason we don't have an implementation of this in any of the libraries
|
|
we are linking against.
|
|
****************************************************************************/
|
|
#if defined( FLM_NLM) && defined( __MWERKS__)
|
|
void abort(void)
|
|
{
|
|
flmAssert(0);
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
Desc: Sort an array of items
|
|
****************************************************************************/
|
|
void 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 flmQSortUINTCompare(
|
|
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 flmQSortUINTSwap(
|
|
void * pvBuffer,
|
|
FLMUINT uiPos1,
|
|
FLMUINT uiPos2)
|
|
{
|
|
FLMUINT * puiArray = (FLMUINT *)pvBuffer;
|
|
FLMUINT uiTmp = puiArray[ uiPos1];
|
|
|
|
puiArray[ uiPos1] = puiArray[ uiPos2];
|
|
puiArray[ uiPos2] = uiTmp;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Determine if a token is a number.
|
|
****************************************************************************/
|
|
FLMEXP FLMBOOL FLMAPI tokenIsNum(
|
|
const char * pszToken,
|
|
FLMUINT * puiNum)
|
|
{
|
|
FLMBOOL bIsNum = TRUE;
|
|
FLMUINT uiNum;
|
|
FLMBOOL bAllowHex = FALSE;
|
|
|
|
if (*pszToken == 0)
|
|
{
|
|
bIsNum = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (*pszToken == '0' &&
|
|
(*(pszToken + 1) == 'x' || *(pszToken + 1) == 'X'))
|
|
{
|
|
pszToken += 2;
|
|
bAllowHex = TRUE;
|
|
}
|
|
|
|
uiNum = 0;
|
|
while (*pszToken)
|
|
{
|
|
if (*pszToken >= '0' && *pszToken <= '9')
|
|
{
|
|
if (!bAllowHex)
|
|
{
|
|
if (uiNum > (FLMUINT)(-1) / 10)
|
|
{
|
|
|
|
// Number would overflow.
|
|
|
|
bIsNum = FALSE;
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
uiNum *= 10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (uiNum > (FLMUINT)(-1) >> 4)
|
|
{
|
|
|
|
// Number would overflow.
|
|
|
|
bIsNum = FALSE;
|
|
goto Exit;
|
|
}
|
|
uiNum <<= 4;
|
|
}
|
|
uiNum += (FLMUINT)(*pszToken - '0');
|
|
}
|
|
else if (bAllowHex)
|
|
{
|
|
if (uiNum > (FLMUINT)(-1) >> 4)
|
|
{
|
|
|
|
// Number would overflow.
|
|
|
|
bIsNum = FALSE;
|
|
goto Exit;
|
|
}
|
|
if (*pszToken >= 'A' && *pszToken <= 'F')
|
|
{
|
|
uiNum <<= 4;
|
|
uiNum += (FLMUINT)(*pszToken - 'A') + 10;
|
|
}
|
|
else if (*pszToken >= 'a' && *pszToken <= 'f')
|
|
{
|
|
uiNum <<= 4;
|
|
uiNum += (FLMUINT)(*pszToken - 'a') + 10;
|
|
}
|
|
else
|
|
{
|
|
bIsNum = FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bIsNum = FALSE;
|
|
goto Exit;
|
|
}
|
|
pszToken++;
|
|
}
|
|
|
|
*puiNum = uiNum;
|
|
|
|
Exit:
|
|
|
|
return( bIsNum);
|
|
}
|