Files
harbour-core/src/common/hbstr.c
2017-09-11 19:56:57 +00:00

1247 lines
34 KiB
C

/*
* Harbour common string functions (accessed from standalone utilities and the RTL)
*
* Copyright 1999-2001 Viktor Szakats (vszakats.net/harbour)
* Copyright 1999 David G. Holm <dholm@jsd-llc.com> (hb_stricmp())
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* 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; see the file LICENSE.txt. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#include "hbapi.h"
#include "hbmath.h"
const char * const hb_szAscii[ 256 ] = {
"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0A", "\x0B", "\x0C", "\x0D", "\x0E", "\x0F",
"\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1A", "\x1B", "\x1C", "\x1D", "\x1E", "\x1F",
"\x20", "\x21", "\x22", "\x23", "\x24", "\x25", "\x26", "\x27", "\x28", "\x29", "\x2A", "\x2B", "\x2C", "\x2D", "\x2E", "\x2F",
"\x30", "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37", "\x38", "\x39", "\x3A", "\x3B", "\x3C", "\x3D", "\x3E", "\x3F",
"\x40", "\x41", "\x42", "\x43", "\x44", "\x45", "\x46", "\x47", "\x48", "\x49", "\x4A", "\x4B", "\x4C", "\x4D", "\x4E", "\x4F",
"\x50", "\x51", "\x52", "\x53", "\x54", "\x55", "\x56", "\x57", "\x58", "\x59", "\x5A", "\x5B", "\x5C", "\x5D", "\x5E", "\x5F",
"\x60", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68", "\x69", "\x6A", "\x6B", "\x6C", "\x6D", "\x6E", "\x6F",
"\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78", "\x79", "\x7A", "\x7B", "\x7C", "\x7D", "\x7E", "\x7F",
"\x80", "\x81", "\x82", "\x83", "\x84", "\x85", "\x86", "\x87", "\x88", "\x89", "\x8A", "\x8B", "\x8C", "\x8D", "\x8E", "\x8F",
"\x90", "\x91", "\x92", "\x93", "\x94", "\x95", "\x96", "\x97", "\x98", "\x99", "\x9A", "\x9B", "\x9C", "\x9D", "\x9E", "\x9F",
"\xA0", "\xA1", "\xA2", "\xA3", "\xA4", "\xA5", "\xA6", "\xA7", "\xA8", "\xA9", "\xAA", "\xAB", "\xAC", "\xAD", "\xAE", "\xAF",
"\xB0", "\xB1", "\xB2", "\xB3", "\xB4", "\xB5", "\xB6", "\xB7", "\xB8", "\xB9", "\xBA", "\xBB", "\xBC", "\xBD", "\xBE", "\xBF",
"\xC0", "\xC1", "\xC2", "\xC3", "\xC4", "\xC5", "\xC6", "\xC7", "\xC8", "\xC9", "\xCA", "\xCB", "\xCC", "\xCD", "\xCE", "\xCF",
"\xD0", "\xD1", "\xD2", "\xD3", "\xD4", "\xD5", "\xD6", "\xD7", "\xD8", "\xD9", "\xDA", "\xDB", "\xDC", "\xDD", "\xDE", "\xDF",
"\xE0", "\xE1", "\xE2", "\xE3", "\xE4", "\xE5", "\xE6", "\xE7", "\xE8", "\xE9", "\xEA", "\xEB", "\xEC", "\xED", "\xEE", "\xEF",
"\xF0", "\xF1", "\xF2", "\xF3", "\xF4", "\xF5", "\xF6", "\xF7", "\xF8", "\xF9", "\xFA", "\xFB", "\xFC", "\xFD", "\xFE", "\xFF"
};
HB_SIZE hb_strAt( const char * szSub, HB_SIZE nSubLen, const char * szText, HB_SIZE nLen )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_strAt(%s, %" HB_PFS "u, %s, %" HB_PFS "u)", szSub, nSubLen, szText, nLen ) );
if( nSubLen > 0 && nLen >= nSubLen )
{
HB_SIZE nPos = 0;
nLen -= nSubLen;
do
{
if( szText[ nPos ] == *szSub )
{
HB_SIZE nSubPos = nSubLen;
do
{
if( --nSubPos == 0 )
return nPos + 1;
}
while( szText[ nPos + nSubPos ] == szSub[ nSubPos ] );
}
}
while( nPos++ < nLen );
}
return 0;
}
HB_SIZE hb_strAtI( const char * szSub, HB_SIZE nSubLen, const char * szText, HB_SIZE nLen )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_strAt(%s, %" HB_PFS "u, %s, %" HB_PFS "u)", szSub, nSubLen, szText, nLen ) );
if( nSubLen > 0 && nLen >= nSubLen )
{
HB_SIZE nPos = 0;
nLen -= nSubLen;
do
{
if( HB_TOUPPER( szText[ nPos ] ) == HB_TOUPPER( *szSub ) )
{
HB_SIZE nSubPos = nSubLen;
do
{
if( --nSubPos == 0 )
return nPos + 1;
}
while( HB_TOUPPER( szText[ nPos + nSubPos ] ) == HB_TOUPPER( szSub[ nSubPos ] ) );
}
}
while( nPos++ < nLen );
}
return 0;
}
HB_BOOL hb_strEmpty( const char * szText, HB_SIZE nLen )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_strEmpty(%s, %" HB_PFS "u)", szText, nLen ) );
while( nLen-- )
{
char c = szText[ nLen ];
if( ! HB_ISSPACE( c ) )
return HB_FALSE;
}
return HB_TRUE;
}
char * hb_strupr( char * pszText )
{
char * pszPos;
HB_TRACE( HB_TR_DEBUG, ( "hb_strupr(%s)", pszText ) );
for( pszPos = pszText; *pszPos; pszPos++ )
*pszPos = ( char ) HB_TOUPPER( ( HB_UCHAR ) *pszPos );
return pszText;
}
char * hb_strlow( char * pszText )
{
char * pszPos;
HB_TRACE( HB_TR_DEBUG, ( "hb_strlow(%s)", pszText ) );
for( pszPos = pszText; *pszPos; pszPos++ )
*pszPos = ( char ) HB_TOLOWER( ( HB_UCHAR ) *pszPos );
return pszText;
}
char * hb_strdup( const char * pszText )
{
char * pszDup;
HB_SIZE nLen;
HB_TRACE( HB_TR_DEBUG, ( "hb_strdup(%s)", pszText ) );
nLen = strlen( pszText ) + 1;
pszDup = ( char * ) hb_xgrab( nLen );
memcpy( pszDup, pszText, nLen );
return pszDup;
}
char * hb_strndup( const char * pszText, HB_SIZE nLen )
{
char * pszDup;
HB_SIZE nPos;
HB_TRACE( HB_TR_DEBUG, ( "hb_strndup(%.*s, %" HB_PFS "d)", ( int ) nLen, pszText, nLen ) );
nPos = 0;
while( nLen-- && pszText[ nPos ] )
++nPos;
pszDup = ( char * ) hb_xgrab( nPos + 1 );
memcpy( pszDup, pszText, nPos );
pszDup[ nPos ] = '\0';
return pszDup;
}
HB_SIZE hb_strnlen( const char * pszText, HB_SIZE nLen )
{
HB_SIZE nPos = 0;
HB_TRACE( HB_TR_DEBUG, ( "hb_strnlen(%.*s, %" HB_PFS "d)", ( int ) nLen, pszText, nLen ) );
while( nLen-- && *pszText++ )
++nPos;
return nPos;
}
char * hb_strduptrim( const char * pszText )
{
char * pszDup;
HB_SIZE nLen;
HB_TRACE( HB_TR_DEBUG, ( "hb_strduptrim(%s)", pszText ) );
while( pszText[ 0 ] == ' ' )
++pszText;
nLen = strlen( pszText );
while( nLen && pszText[ nLen - 1 ] == ' ' )
--nLen;
pszDup = ( char * ) hb_xgrab( nLen + 1 );
memcpy( pszDup, pszText, nLen );
pszDup[ nLen ] = '\0';
return pszDup;
}
HB_SIZE hb_strlentrim( const char * pszText )
{
HB_SIZE nPos = 0;
HB_TRACE( HB_TR_DEBUG, ( "hb_strlentrim(%s)", pszText ) );
while( pszText[ 0 ] == ' ' )
++pszText;
while( pszText[ nPos ] )
++nPos;
while( nPos && pszText[ nPos - 1 ] == ' ' )
--nPos;
return nPos;
}
int hb_stricmp( const char * s1, const char * s2 )
{
int rc = 0, c1;
HB_TRACE( HB_TR_DEBUG, ( "hb_stricmp(%s, %s)", s1, s2 ) );
do
{
int c2;
c1 = HB_TOUPPER( ( unsigned char ) *s1 );
c2 = HB_TOUPPER( ( unsigned char ) *s2 );
if( c1 != c2 )
{
rc = ( c1 < c2 ? -1 : 1 );
break;
}
s1++;
s2++;
}
while( c1 );
return rc;
}
/* Warning: It is not case sensitive */
int hb_strnicmp( const char * s1, const char * s2, HB_SIZE count )
{
HB_SIZE nCount;
int rc = 0;
HB_TRACE( HB_TR_DEBUG, ( "hb_strnicmp(%.*s, %.*s, %" HB_PFS "u)", ( int ) count, s1, ( int ) count, s2, count ) );
for( nCount = 0; nCount < count; nCount++ )
{
unsigned char c1 = ( char ) HB_TOUPPER( ( unsigned char ) s1[ nCount ] );
unsigned char c2 = ( char ) HB_TOUPPER( ( unsigned char ) s2[ nCount ] );
if( c1 != c2 )
{
rc = ( c1 < c2 ? -1 : 1 );
break;
}
else if( ! c1 )
break;
}
return rc;
}
/*
AJ: 2004-02-23
Concatenates multiple strings into a single result.
Eg. hb_xstrcat( buffer, "A", "B", NULL ) stores "AB" in buffer.
*/
char * hb_xstrcat( char * szDest, const char * szSrc, ... )
{
char * szResult = szDest;
va_list va;
HB_TRACE( HB_TR_DEBUG, ( "hb_xstrcat(%p, %p, ...)", ( void * ) szDest, ( const void * ) szSrc ) );
while( *szDest )
szDest++;
va_start( va, szSrc );
while( szSrc )
{
while( *szSrc )
*szDest++ = *szSrc++;
szSrc = va_arg( va, char * );
}
*szDest = '\0';
va_end( va );
return szResult;
}
/*
AJ: 2004-02-23
Concatenates multiple strings into a single result.
Eg. hb_xstrcpy( buffer, "A", "B", NULL ) stores "AB" in buffer.
Returns szDest.
Any existing contents of szDest are cleared. If the szDest buffer is NULL,
allocates a new buffer with the required length and returns that. The
buffer is allocated using hb_xgrab(), and should eventually be freed
using hb_xfree().
*/
char * hb_xstrcpy( char * szDest, const char * szSrc, ... )
{
char * szResult;
va_list va;
HB_TRACE( HB_TR_DEBUG, ( "hb_xstrcpy(%p, %p, ...)", ( void * ) szDest, ( const void * ) szSrc ) );
if( szDest == NULL )
{
const char * szSrcPtr = szSrc;
HB_SIZE nSize = 1;
va_start( va, szSrc );
while( szSrcPtr )
{
nSize += strlen( szSrcPtr );
szSrcPtr = va_arg( va, char * );
}
va_end( va );
szDest = ( char * ) hb_xgrab( nSize );
}
szResult = szDest;
va_start( va, szSrc );
while( szSrc )
{
while( *szSrc )
*szDest++ = *szSrc++;
szSrc = va_arg( va, char * );
}
*szDest = '\0';
va_end( va );
return szResult;
}
static double hb_numPow10( int nPrecision )
{
static const double s_dPow10[ 16 ] = { 1.0, /* 0 */
10.0, /* 1 */
100.0, /* 2 */
1000.0, /* 3 */
10000.0, /* 4 */
100000.0, /* 5 */
1000000.0, /* 6 */
10000000.0, /* 7 */
100000000.0, /* 8 */
1000000000.0, /* 9 */
10000000000.0, /* 10 */
100000000000.0, /* 11 */
1000000000000.0, /* 12 */
10000000000000.0, /* 13 */
100000000000000.0, /* 14 */
1000000000000000.0 }; /* 15 */
if( nPrecision < 16 )
{
if( nPrecision >= 0 )
return s_dPow10[ nPrecision ];
else if( nPrecision > -16 )
return 1.0 / s_dPow10[ ( unsigned int ) -nPrecision ];
}
return pow( 10.0, ( double ) nPrecision );
}
double hb_numRound( double dNum, int iDec )
{
static const double doBase = 10.0;
double doComplete5, doComplete5i, dPow;
HB_TRACE( HB_TR_DEBUG, ( "hb_numRound(%lf, %d)", dNum, iDec ) );
if( dNum == 0.0 )
return 0.0;
if( iDec < 0 )
{
dPow = hb_numPow10( -iDec );
doComplete5 = dNum / dPow * doBase;
}
else
{
dPow = hb_numPow10( iDec );
doComplete5 = dNum * dPow * doBase;
}
/*
* double precision if 15 digit the 16th one is usually wrong but
* can give some information about number,
* Clipper display 16 digit only others are set to 0
* many people don't know/understand FL arithmetic. They expect
* that it will behaves in the same way as real numbers. It's not
* true but in business application we can try to hide this problem
* for them. Usually they not need such big precision in presented
* numbers so we can decrease the precision to 15 digits and use
* the cut part for proper rounding. It should resolve
* most of problems. But if someone totally not understand FL
* and will try to convert big matrix or something like that it's quite
* possible that he chose one of the natural school algorithm which
* works nice with real numbers but can give very bad results in FL.
* In such case it could be good to decrease precision even more.
* It not fixes the used algorithm of course but will make many users
* happy because they can see nice (proper) result.
* So maybe it will be good to add SET PRECISION TO <n> for them and
* use the similar hack in ==, >=, <=, <, > operations if it's set.
*/
/* #define HB_NUM_PRECISION 16 */
#ifdef HB_NUM_PRECISION
/*
* this is a hack for people who cannot live without hacked FL values
* in rounding
*/
{
int iDecR, iPrec;
HB_BOOL fNeg;
if( dNum < 0 )
{
fNeg = HB_TRUE;
dNum = -dNum;
}
else
fNeg = HB_FALSE;
iDecR = ( int ) log10( dNum );
iPrec = iDecR + iDec;
if( iPrec < -1 )
{
return 0.0;
}
else
{
if( iPrec > HB_NUM_PRECISION )
{
iDec = HB_NUM_PRECISION - ( dNum < 1.0 ? 0 : 1 ) - iDecR;
iPrec = -1;
}
else
iPrec -= HB_NUM_PRECISION;
}
if( iDec < 0 )
{
dPow = hb_numPow10( -iDec );
doComplete5 = dNum / dPow * doBase + 5.0 + hb_numPow10( iPrec );
}
else
{
dPow = hb_numPow10( iDec );
doComplete5 = dNum * dPow * doBase + 5.0 + hb_numPow10( iPrec );
}
if( fNeg )
doComplete5 = -doComplete5;
}
#else
if( dNum < 0.0 )
doComplete5 -= 5.0;
else
doComplete5 += 5.0;
#endif
doComplete5 /= doBase;
#if defined( HB_DBLFL_PREC_FACTOR ) && ! defined( HB_CLP_STRICT )
/* similar operation is done by Cl5.3
it's a hack to force rounding FL values UP */
doComplete5 *= HB_DBLFL_PREC_FACTOR;
#endif
( void ) modf( doComplete5, &doComplete5i );
#if defined( __XCC__ ) || defined( __POCC__ )
if( iDec < 16 )
{
if( iDec >= 0 )
return doComplete5i / ( HB_LONGLONG ) dPow;
else if( iDec > -16 )
return doComplete5i * ( HB_LONGLONG ) dPow;
}
#endif
if( iDec < 0 )
return doComplete5i * dPow;
else
return doComplete5i / dPow;
}
double hb_numInt( double dNum )
{
double dInt;
#if defined( HB_DBLFL_PREC_FACTOR ) && ! defined( HB_CLP_STRICT )
/* Similar hack as in round to make this functions compatible */
dNum *= HB_DBLFL_PREC_FACTOR;
#endif
( void ) modf( dNum, &dInt );
return dInt;
}
double hb_numDecConv( double dNum, int iDec )
{
if( iDec > 0 )
return hb_numRound( dNum / hb_numPow10( iDec ), iDec );
else if( iDec < 0 )
return hb_numRound( dNum * hb_numPow10( -iDec ), 0 );
else
return hb_numRound( dNum, 0 );
}
double hb_numExpConv( double dNum, int iExp )
{
if( iExp > 0 )
return dNum / hb_numPow10( iExp );
else if( iExp < 0 )
return dNum * hb_numPow10( -iExp );
else
return dNum;
}
static HB_BOOL hb_str2number( HB_BOOL fPCode, const char * szNum, HB_SIZE nLen, HB_MAXINT * lVal, double * dVal, int * piDec, int * piWidth )
{
HB_BOOL fDbl = HB_FALSE, fDec = HB_FALSE, fNeg, fHex = HB_FALSE;
int iLen, iPos = 0;
int c, iWidth, iDec = 0, iDecR = 0;
HB_TRACE( HB_TR_DEBUG, ( "hb_str2number(%d, %p, %" HB_PFS "u, %p, %p, %p, %p)", ( int ) fPCode, ( const void * ) szNum, nLen, ( void * ) lVal, ( void * ) dVal, ( void * ) piDec, ( void * ) piWidth ) );
iLen = ( int ) nLen;
while( iPos < iLen && HB_ISSPACE( szNum[ iPos ] ) )
iPos++;
if( iPos >= iLen )
{
fNeg = HB_FALSE;
}
else if( szNum[ iPos ] == '-' )
{
fNeg = HB_TRUE;
iPos++;
}
else
{
fNeg = HB_FALSE;
if( szNum[ iPos ] == '+' )
iPos++;
}
*dVal = 0;
*lVal = 0;
/* Hex Number */
if( fPCode && iPos + 1 < iLen && szNum[ iPos ] == '0' &&
( szNum[ iPos + 1 ] == 'X' || szNum[ iPos + 1 ] == 'x' ) )
{
iPos += 2;
iWidth = HB_DEFAULT_WIDTH;
fHex = HB_TRUE;
for( ; iPos < iLen; iPos++ )
{
c = szNum[ iPos ];
if( c >= '0' && c <= '9' )
c -= '0';
else if( c >= 'A' && c <= 'F' )
c -= 'A' - 10;
else if( c >= 'a' && c <= 'f' )
c -= 'a' - 10;
else
break;
*lVal = ( *lVal << 4 ) + c;
}
}
else
{
HB_MAXINT lLimV;
int iLimC;
lLimV = HB_VMLONG_MAX / 10;
iLimC = ( int ) ( HB_VMLONG_MAX % 10 );
iWidth = iPos;
for( ; iPos < iLen; iPos++ )
{
c = szNum[ iPos ];
if( c >= '0' && c <= '9' )
{
if( fDbl )
{
*dVal = *dVal * 10.0 + ( c - '0' );
}
else if( *lVal < lLimV || ( *lVal <= lLimV && ( ( int ) ( c - '0' ) ) <= iLimC ) )
{
*lVal = *lVal * 10 + ( c - '0' );
}
else
{
*dVal = ( double ) *lVal * 10.0 + ( c - '0' );
fDbl = HB_TRUE;
}
if( fDec )
iDec++;
else
iWidth++;
}
else if( c == '.' && ! fDec )
{
fDec = HB_TRUE;
}
else
{
while( ! fDec && iPos < iLen )
{
if( szNum[ iPos++ ] == '.' )
fDec = HB_TRUE;
else
iWidth++;
}
if( fDec )
iDecR = iLen - iPos;
break;
}
}
}
if( fNeg )
{
if( fDbl )
*dVal = -*dVal;
else
*lVal = -*lVal;
}
if( ! fDbl && (
#if defined( PCODE_LONG_LIM )
( fPCode && ! fHex && ! PCODE_LONG_LIM( *lVal ) ) ||
#endif
fDec ) )
{
*dVal = ( double ) *lVal;
fDbl = HB_TRUE;
}
if( iDec )
{
#if defined( __XCC__ ) || defined( __POCC__ )
if( iDec < 16 )
*dVal /= ( HB_LONGLONG ) hb_numPow10( iDec );
else
#endif
*dVal /= hb_numPow10( iDec );
}
if( piDec )
*piDec = iDec + iDecR;
if( piWidth )
{
if( fHex )
*piWidth = iWidth;
else
{
if( fPCode )
{
if( iWidth < 10 || fNeg )
*piWidth = fDbl ? HB_DBL_LENGTH( *dVal ) : HB_LONG_LENGTH( *lVal );
else
*piWidth = iWidth + ( iDec == 0 ? 1 : 0 );
}
else if( iWidth > 10 )
{
*piWidth = fDbl ? HB_DBL_LENGTH( *dVal ) : HB_LONG_LENGTH( *lVal );
}
else
{
if( iDec + iDecR == 0 )
*piWidth = iLen;
else if( iWidth == 0 )
*piWidth = 1;
else if( fNeg && iWidth == 1 && *dVal != 0 )
*piWidth = 2;
else
*piWidth = iWidth;
}
}
}
return fDbl;
}
HB_BOOL hb_compStrToNum( const char * szNum, HB_SIZE nLen, HB_MAXINT * plVal, double * pdVal, int * piDec, int * piWidth )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_compStrToNum( %s, %" HB_PFS "u, %p, %p, %p, %p)", szNum, nLen, ( void * ) plVal, ( void * ) pdVal, ( void * ) piDec, ( void * ) piWidth ) );
return hb_str2number( HB_TRUE, szNum, nLen, plVal, pdVal, piDec, piWidth );
}
HB_BOOL hb_valStrnToNum( const char * szNum, HB_SIZE nLen, HB_MAXINT * plVal, double * pdVal, int * piDec, int * piWidth )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_valStrnToNum( %s, %" HB_PFS "u, %p, %p, %p, %p)", szNum, nLen, ( void * ) plVal, ( void * ) pdVal, ( void * ) piDec, ( void * ) piWidth ) );
return hb_str2number( HB_FALSE, szNum, nLen, plVal, pdVal, piDec, piWidth );
}
HB_BOOL hb_strToNum( const char * szNum, HB_MAXINT * plVal, double * pdVal )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_strToNum(%s, %p, %p)", szNum, ( void * ) plVal, ( void * ) pdVal ) );
return hb_str2number( HB_FALSE, szNum, strlen( szNum ), plVal, pdVal, NULL, NULL );
}
HB_BOOL hb_strnToNum( const char * szNum, HB_SIZE nLen, HB_MAXINT * plVal, double * pdVal )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_strnToNum(%.*s, %" HB_PFS "u, %p, %p)", ( int ) nLen, szNum, nLen, ( void * ) plVal, ( void * ) pdVal ) );
return hb_str2number( HB_FALSE, szNum, nLen, plVal, pdVal, NULL, NULL );
}
/* returns the numeric value of a character string representation of a number */
double hb_strVal( const char * szText, HB_SIZE nLen )
{
HB_MAXINT lVal;
double dVal;
HB_TRACE( HB_TR_DEBUG, ( "hb_strVal(%.*s, %" HB_PFS "u)", ( int ) nLen, szText, nLen ) );
if( ! hb_str2number( HB_FALSE, szText, nLen, &lVal, &dVal, NULL, NULL ) )
dVal = ( double ) lVal;
return dVal;
}
HB_MAXINT hb_strValInt( const char * szText, int * iOverflow )
{
HB_MAXINT lVal;
double dVal;
HB_TRACE( HB_TR_DEBUG, ( "hb_strValInt(%s)", szText ) );
if( hb_str2number( HB_TRUE, szText, strlen( szText ), &lVal, &dVal, NULL, NULL ) )
{
*iOverflow = 1;
return 0;
}
*iOverflow = 0;
return lVal;
}
char * hb_numToStr( char * szBuf, HB_SIZE nSize, HB_MAXINT lNumber )
{
int iPos = ( int ) nSize;
HB_BOOL fNeg = HB_FALSE;
HB_TRACE( HB_TR_DEBUG, ( "hb_numToStr(%p, %" HB_PFS "u, %" PFHL "i)", ( void * ) szBuf, nSize, lNumber ) );
szBuf[ --iPos ] = '\0';
if( lNumber < 0 )
{
fNeg = HB_TRUE;
lNumber = -lNumber;
}
while( --iPos >= 0 )
{
szBuf[ iPos ] = '0' + ( char ) ( lNumber % 10 );
lNumber /= 10;
if( lNumber == 0 )
break;
}
if( fNeg && --iPos >= 0 )
szBuf[ iPos ] = '-';
if( iPos > 0 )
memset( szBuf, ' ', iPos );
else if( iPos < 0 )
{
memset( szBuf, '*', nSize - 1 );
iPos = 0;
}
return &szBuf[ iPos ];
}
/* if you want to be sure that size of buffer is enough to hold each
double number with '\0' terminating character then it should have
at least HB_MAX_DOUBLE_LENGTH bytes. If buffer is not large enough
then NULL is returned */
char * hb_dblToStr( char * szBuf, HB_SIZE nSize, double dNumber, int iMaxDec )
{
double dInt, dFract, dDig, doBase = 10.0;
int iLen, iPos, iPrec;
char * szResult;
HB_BOOL fFirst;
HB_TRACE( HB_TR_DEBUG, ( "hb_dblToStr(%p, %" HB_PFS "u, %f, %d)", ( void * ) szBuf, nSize, dNumber, iMaxDec ) );
iLen = ( int ) ( nSize - 1 );
if( iLen <= 0 )
return NULL;
#ifdef HB_NUM_PRECISION
iPrec = HB_NUM_PRECISION;
#else
iPrec = 16;
#endif
szResult = szBuf;
if( dNumber < 0 )
{
dFract = modf( -dNumber, &dInt );
if( --iLen == 0 )
{
if( dInt < 1 && dFract < 0.5 )
{
szBuf[ 0 ] = '0';
szBuf[ 1 ] = '\0';
return szBuf;
}
return NULL;
}
*szBuf++ = '-';
}
else
dFract = modf( dNumber, &dInt );
iPos = iLen;
do
{
if( iPos == 0 )
return NULL;
dDig = modf( dInt / doBase + 0.01, &dInt ) * doBase;
szBuf[ --iPos ] = '0' + ( char ) ( dDig + 0.01 );
}
while( dInt >= 1 );
if( iPos > 0 )
memmove( szBuf, szBuf + iPos, HB_MIN( iLen - iPos, iPrec + 1 ) );
iPos = iLen - iPos;
fFirst = iPos > 1 || szBuf[ 0 ] != '0';
if( fFirst )
{
if( iPos >= iPrec )
{
fFirst = iPos == iPrec ? dFract >= 0.5 : szBuf[ iPrec ] >= '5';
if( iPrec < iPos )
memset( szBuf + iPrec , '0', iPos - iPrec );
if( fFirst )
{
for( ;; )
{
if( --iPrec < 0 )
{
if( iPos == iLen )
return NULL;
memmove( szBuf + 1, szBuf, iPos );
*szBuf = '1';
++iPos;
break;
}
if( szBuf[ iPrec ] != '9' )
{
++szBuf[ iPrec ];
break;
}
szBuf[ iPrec ] = '0';
}
}
iPrec = 0;
}
else
iPrec -= iPos;
}
if( iPrec > 0 && iLen - iPos > 1 && iMaxDec != 0 && dFract > 0 )
{
int iDec = iPos;
szBuf[ iPos ] = '.';
while( ++iPos < iLen && iPrec > 0 && iMaxDec-- != 0 )
{
dFract = modf( dFract * doBase, &dDig );
szBuf[ iPos ] = '0' + ( char ) ( dDig + 0.01 );
if( szBuf[ iPos ] != '0' )
fFirst = HB_TRUE;
if( fFirst )
--iPrec;
}
if( dFract > ( iPrec > 0 ? 0.5 - hb_numPow10( -iPrec ) : 0.2 ) )
{
iPrec = iPos;
for( ;; )
{
if( --iPrec < 0 )
{
memmove( szBuf + 1, szBuf, iPos );
*szBuf = '1';
if( iPos < iLen )
++iPos;
++iDec;
break;
}
if( iPrec == iDec )
--iPrec;
if( szBuf[ iPrec ] != '9' )
{
++szBuf[ iPrec ];
break;
}
szBuf[ iPrec ] = '0';
}
}
while( iPos > iDec && szBuf[ iPos - 1 ] == '0' )
--iPos;
if( szBuf[ iPos - 1 ] == '.' )
--iPos;
}
szBuf[ iPos ] = '\0';
return iPos == 1 && *szResult == '-' && *szBuf == '0' ? szBuf : szResult;
}
/* This function copies szText to destination buffer.
* NOTE: Unlike the documentation for strncpy, this routine will always append
* a null and the nLen param is pDest size not pSource limit
*/
char * hb_strncpy( char * pDest, const char * pSource, HB_SIZE nLen )
{
char * pBuf = pDest;
HB_TRACE( HB_TR_DEBUG, ( "hb_strncpy(%p, %.*s, %" HB_PFS "u)", ( void * ) pDest, ( int ) nLen, pSource, nLen ) );
pDest[ nLen ] = '\0';
while( nLen && ( *pDest++ = *pSource++ ) != '\0' )
nLen--;
return pBuf;
}
/* This function copies szText to destination buffer.
* NOTE: Unlike the documentation for strncat, this routine will always append
* a null and the nLen param is pDest size not pSource limit
*/
char * hb_strncat( char * pDest, const char * pSource, HB_SIZE nLen )
{
char * pBuf = pDest;
HB_TRACE( HB_TR_DEBUG, ( "hb_strncat(%p, %.*s, %" HB_PFS "u)", ( void * ) pDest, ( int ) nLen, pSource, nLen ) );
pDest[ nLen ] = '\0';
while( nLen && *pDest )
{
pDest++;
nLen--;
}
while( nLen && ( *pDest++ = *pSource++ ) != '\0' )
nLen--;
return pBuf;
}
/* This function copies and converts szText to lower case. */
/* NOTE: Unlike the documentation for strncpy, this routine will always append
* a null [pt]
*/
char * hb_strncpyLower( char * pDest, const char * pSource, HB_SIZE nLen )
{
char * pBuf = pDest;
HB_TRACE( HB_TR_DEBUG, ( "hb_strncpyLower(%p, %.*s, %" HB_PFS "u)", ( void * ) pDest, ( int ) nLen, pSource, nLen ) );
pDest[ nLen ] = '\0';
while( nLen && ( *pDest++ = ( char ) HB_TOLOWER( ( HB_UCHAR ) *pSource ) ) != '\0' )
{
nLen--;
pSource++;
}
return pBuf;
}
/* This function copies and converts szText to upper case. */
/* NOTE: Unlike the documentation for strncpy, this routine will always append
* a null [pt]
*/
char * hb_strncpyUpper( char * pDest, const char * pSource, HB_SIZE nLen )
{
char * pBuf = pDest;
HB_TRACE( HB_TR_DEBUG, ( "hb_strncpyUpper(%p, %.*s, %" HB_PFS "u)", ( void * ) pDest, ( int ) nLen, pSource, nLen ) );
pDest[ nLen ] = '\0';
while( nLen && ( *pDest++ = ( char ) HB_TOUPPER( ( HB_UCHAR ) *pSource ) ) != '\0' )
{
nLen--;
pSource++;
}
return pBuf;
}
/* This function copies and converts szText to upper case AND Trims it */
/* NOTE: Unlike the documentation for strncpy, this routine will always append
* a null [pt]
*/
char * hb_strncpyUpperTrim( char * pDest, const char * pSource, HB_SIZE nLen )
{
char * pBuf = pDest;
HB_SIZE nSLen;
HB_TRACE( HB_TR_DEBUG, ( "hb_strncpyUpperTrim(%p, %.*s, %" HB_PFS "u)", ( void * ) pDest, ( int ) nLen, pSource, nLen ) );
nSLen = 0;
while( nSLen < nLen && pSource[ nSLen ] )
nSLen++;
while( nSLen && pSource[ nSLen - 1 ] == ' ' )
nSLen--;
while( nLen && nSLen &&
( *pDest++ = ( char ) HB_TOUPPER( ( HB_UCHAR ) *pSource ) ) != '\0' )
{
nSLen--;
nLen--;
pSource++;
}
*pDest = '\0';
return pBuf;
}
/* This function copies trimed szText to destination buffer. */
/* NOTE: Unlike the documentation for strncpy, this routine will always append
* a null
*/
char * hb_strncpyTrim( char * pDest, const char * pSource, HB_SIZE nLen )
{
char * pBuf = pDest;
HB_SIZE nSLen;
HB_TRACE( HB_TR_DEBUG, ( "hb_strncpyTrim(%p, %.*s, %" HB_PFS "u)", ( void * ) pDest, ( int ) nLen, pSource, nLen ) );
nSLen = 0;
while( nSLen < nLen && pSource[ nSLen ] )
nSLen++;
while( nSLen && pSource[ nSLen - 1 ] == ' ' )
nSLen--;
while( nLen && nSLen && ( *pDest++ = *pSource++ ) != '\0' )
{
nSLen--;
nLen--;
}
*pDest = '\0';
return pBuf;
}
char * hb_strRemEscSeq( char * str, HB_SIZE * pnLen )
{
HB_SIZE nPos = *pnLen, nStripped = 0;
char * ptr, * dst;
ptr = dst = str;
while( nPos )
{
if( *ptr == '\\' )
break;
++ptr; ++dst;
--nPos;
}
while( nPos-- )
{
char ch = *ptr++;
if( ch == '\\' )
{
++nStripped;
if( nPos )
{
nPos--;
ch = *ptr++;
switch( ch )
{
case 'r':
ch = '\r';
break;
case 'n':
ch = '\n';
break;
case 't':
ch = '\t';
break;
case 'b':
ch = '\b';
break;
case 'f':
ch = '\f';
break;
case 'v':
ch = '\v';
break;
case 'a':
ch = '\a';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
ch -= '0';
if( nPos && *ptr >= '0' && *ptr <= '7' )
{
ch = ( ch << 3 ) | ( *ptr++ - '0' );
++nStripped;
if( --nPos && *ptr >= '0' && *ptr <= '7' )
{
ch = ( ch << 3 ) | ( *ptr++ - '0' );
++nStripped;
--nPos;
}
}
break;
case 'x':
ch = 0;
while( nPos )
{
if( *ptr >= '0' && *ptr <= '9' )
ch = ( ch << 4 ) | ( *ptr++ - '0' );
else if( *ptr >= 'A' && *ptr <= 'F' )
ch = ( ch << 4 ) | ( *ptr++ - 'A' + 10 );
else if( *ptr >= 'a' && *ptr <= 'f' )
ch = ( ch << 4 ) | ( *ptr++ - 'a' + 10 );
else
break;
++nStripped;
--nPos;
}
break;
case '\\':
default:
break;
}
}
else
break;
}
*dst++ = ch;
}
if( nStripped )
{
*dst = '\0';
*pnLen -= nStripped;
}
return str;
}
char * hb_compEncodeString( int iMethod, const char * szText, HB_SIZE * pnLen )
{
char * pBuffer = ( char * ) hb_xgrab( *pnLen + 1 );
memcpy( pBuffer, szText, *pnLen );
pBuffer[ *pnLen ] = '\0';
if( iMethod == 1 )
{
HB_SIZE nPos;
for( nPos = 0; nPos < *pnLen; nPos++ )
pBuffer[ nPos ] ^= 0xF3;
}
return pBuffer;
}
char * hb_compDecodeString( int iMethod, const char * szText, HB_SIZE * pnLen )
{
char * pBuffer = ( char * ) hb_xgrab( *pnLen + 1 );
memcpy( pBuffer, szText, *pnLen );
pBuffer[ *pnLen ] = '\0';
if( iMethod == 1 )
{
HB_SIZE nPos;
for( nPos = 0; nPos < *pnLen; nPos++ )
pBuffer[ nPos ] ^= 0xF3;
}
return pBuffer;
}
/* 'pDest' must be double the size of 'size'. [vszakats] */
void hb_strtohex( const char * pSource, HB_SIZE size, char * pDest )
{
HB_SIZE i;
for( i = 0; i < size; i++ )
{
int b;
b = ( ( HB_UCHAR ) pSource[ i ] >> 4 ) & 0x0F;
*pDest++ = ( char ) ( b + ( b > 9 ? 'a' - 10 : '0' ) );
b = ( HB_UCHAR ) pSource[ i ] & 0x0F;
*pDest++ = ( char ) ( b + ( b > 9 ? 'a' - 10 : '0' ) );
}
}