Files
mars-flaim/flaim/src/flutil.cpp
dsandersoremutah eb7a1e48b7 Added FLMEXP and FLMAPI to exported APIs.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@112 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-02-13 23:35:37 +00:00

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);
}