* harbour/contrib/hbw32/dllcall.c
* minor cleanup in return values
* harbour/contrib/hbole/ole2.c
* cleaned casting in UNICODE conversions
* harbour/source/common/expropt2.c
* replicate CA-Cl*pper compile time optimization bugs:
"" $ <literString> => .T.
AT( "", <literString> ) => 1
CHR( 256 ) => ""
only when Harbour extensions (-kh) are not enabled, f.e.
in strict Clipper compatibility mode (-kc)
* harbour/utils/hbtest/rt_hvma.prg
* harbour/utils/hbtest/rt_str.prg
* updated to test Clipper and Harbour compile time modes in
the above situations
* harbour/common.mak
* harbour/source/rtl/Makefile
- harbour/source/rtl/strings.c
* harbour/source/common/hbstr.c
* moved hb_strEmpty() from RTL to COMMON library
* harbour/include/hbexprb.c
* harbour/include/hbexprop.h
* harbour/source/common/expropt2.c
+ added compile time optimization for EMPTY() function
; removed 'TODO: empty optimization' note
* harbour/source/rtl/itemseri.c
% compress trailing spaces during string item serialization
* harbour/include/hbapi.h
* harbour/source/vm/hashes.c
+ added hb_hashAddNew() - works like hb_hashAdd() but it adds item
only if new key is used
* harbour/source/vm/hvm.c
* use hb_hashAddNew() instead of hb_hashAdd() for HB_P_HASHGEN
I cannot revert the order of hash item during compilation because
it will also change the order of user expression evaluation.
1066 lines
28 KiB
C
1066 lines
28 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* Harbour common string functions (accessed from standalone utilities and the RTL)
|
|
*
|
|
* Copyright 1999-2001 Viktor Szakats <viktor.szakats@syenar.hu>
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* 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 software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* The following parts are Copyright of the individual authors.
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* Copyright 1999 David G. Holm <dholm@jsd-llc.com>
|
|
* hb_stricmp()
|
|
*
|
|
* See doc/license.txt for licensing terms.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <ctype.h> /* Needed by hb_strupr() */
|
|
|
|
#include "hbapi.h"
|
|
#include "hbmath.h"
|
|
|
|
const char * 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_EXPORT ULONG hb_strAt( const char * szSub, ULONG ulSubLen, const char * szText, ULONG ulLen )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strAt(%s, %lu, %s, %lu)", szSub, ulSubLen, szText, ulLen));
|
|
|
|
if( ulSubLen > 0 && ulLen >= ulSubLen )
|
|
{
|
|
ULONG ulPos = 0;
|
|
ULONG ulSubPos = 0;
|
|
|
|
while( ulPos < ulLen && ulSubPos < ulSubLen )
|
|
{
|
|
if( szText[ ulPos ] == szSub[ ulSubPos ] )
|
|
{
|
|
ulSubPos++;
|
|
ulPos++;
|
|
}
|
|
else if( ulSubPos )
|
|
{
|
|
/* Go back to the first character after the first match,
|
|
or else tests like "22345" $ "012223456789" will fail. */
|
|
ulPos -= ( ulSubPos - 1 );
|
|
ulSubPos = 0;
|
|
}
|
|
else
|
|
ulPos++;
|
|
}
|
|
|
|
return ( ulSubPos < ulSubLen ) ? 0 : ( ulPos - ulSubLen + 1 );
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
HB_EXPORT BOOL hb_strEmpty( const char * szText, ULONG ulLen )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strEmpty(%s, %lu)", szText, ulLen));
|
|
|
|
while( ulLen-- )
|
|
{
|
|
char c = szText[ ulLen ];
|
|
|
|
if( !HB_ISSPACE( c ) )
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HB_EXPORT char * hb_strupr( char * pszText )
|
|
{
|
|
char * pszPos;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strupr(%s)", pszText));
|
|
|
|
for( pszPos = pszText; *pszPos; pszPos++ )
|
|
*pszPos = ( char ) toupper( ( UCHAR ) *pszPos );
|
|
|
|
return pszText;
|
|
}
|
|
|
|
HB_EXPORT char * hb_strlow( char * pszText )
|
|
{
|
|
char * pszPos;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strlow(%s)", pszText));
|
|
|
|
for( pszPos = pszText; *pszPos; pszPos++ )
|
|
*pszPos = ( char ) tolower( ( UCHAR ) *pszPos );
|
|
|
|
return pszText;
|
|
}
|
|
|
|
HB_EXPORT char * hb_strdup( const char * pszText )
|
|
{
|
|
char * pszDup;
|
|
ULONG ulLen = strlen( pszText ) + 1;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strdup(%s, %ld)", pszText, ulLen));
|
|
|
|
pszDup = ( char * ) hb_xgrab( ulLen );
|
|
memcpy( pszDup, pszText, ulLen );
|
|
|
|
return pszDup;
|
|
}
|
|
|
|
HB_EXPORT char * hb_strndup( const char * pszText, ULONG ulLen )
|
|
{
|
|
char * pszDup;
|
|
ULONG ul;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strndup(%s, %ld)", pszText, ulLen));
|
|
|
|
ul = 0;
|
|
pszDup = ( char * ) pszText;
|
|
while( ulLen-- && *pszDup++ )
|
|
{
|
|
++ul;
|
|
}
|
|
|
|
pszDup = ( char * ) hb_xgrab( ul + 1 );
|
|
memcpy( pszDup, pszText, ul );
|
|
pszDup[ ul ] = '\0';
|
|
|
|
return pszDup;
|
|
}
|
|
|
|
HB_EXPORT ULONG hb_strnlen( const char * pszText, ULONG ulLen )
|
|
{
|
|
ULONG ul = 0;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strnlen(%s, %ld)", pszText, ulLen));
|
|
|
|
while( ulLen-- && *pszText++ )
|
|
{
|
|
++ul;
|
|
}
|
|
return ul;
|
|
}
|
|
|
|
HB_EXPORT int hb_stricmp( const char * s1, const char * s2 )
|
|
{
|
|
int rc = 0, c1, c2;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_stricmp(%s, %s)", s1, s2));
|
|
|
|
do
|
|
{
|
|
c1 = toupper( ( unsigned char ) *s1 );
|
|
c2 = 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 */
|
|
HB_EXPORT int hb_strnicmp( const char * s1, const char * s2, ULONG count )
|
|
{
|
|
ULONG ulCount;
|
|
int rc = 0;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strnicmp(%s, %s, %lu)", s1, s2, count));
|
|
|
|
for( ulCount = 0; ulCount < count; ulCount++ )
|
|
{
|
|
unsigned char c1 = ( char ) toupper( ( unsigned char ) s1[ ulCount ] );
|
|
unsigned char c2 = ( char ) toupper( ( unsigned char ) s2[ ulCount ] );
|
|
|
|
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.
|
|
*/
|
|
HB_EXPORT char * hb_xstrcat( char * szDest, const char * szSrc, ... )
|
|
{
|
|
char * szResult = szDest;
|
|
va_list va;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_xstrcat(%p, %p, ...)", szDest, 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().
|
|
*/
|
|
HB_EXPORT char * hb_xstrcpy( char * szDest, const char * szSrc, ... )
|
|
{
|
|
char * szResult;
|
|
va_list va;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_xstrcpy(%p, %p, ...)", szDest, szSrc));
|
|
|
|
if( szDest == NULL )
|
|
{
|
|
const char * szSrcPtr = szSrc;
|
|
ULONG ulSize = 1;
|
|
va_start( va, szSrc );
|
|
while( szSrcPtr )
|
|
{
|
|
ulSize += strlen( szSrcPtr );
|
|
szSrcPtr = va_arg( va, char * );
|
|
}
|
|
va_end( va );
|
|
szDest = ( char * ) hb_xgrab( ulSize );
|
|
}
|
|
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 );
|
|
}
|
|
|
|
HB_EXPORT double hb_numRound( double dNum, int iDec )
|
|
{
|
|
static const double doBase = 10.0f;
|
|
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 sth 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;
|
|
BOOL fNeg;
|
|
|
|
if( dNum < 0 )
|
|
{
|
|
fNeg = TRUE;
|
|
dNum = -dNum;
|
|
}
|
|
else
|
|
{
|
|
fNeg = 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.0f )
|
|
doComplete5 -= 5.0f;
|
|
else
|
|
doComplete5 += 5.0f;
|
|
#endif
|
|
|
|
doComplete5 /= doBase;
|
|
|
|
#if defined( HB_DBLFL_PREC_FACTOR ) && !defined( HB_C52_STRICT )
|
|
/* similar operation is done by Cl5.3
|
|
it's a hack to force rounding FL values UP */
|
|
doComplete5 *= HB_DBLFL_PREC_FACTOR;
|
|
#endif
|
|
|
|
modf( doComplete5, &doComplete5i );
|
|
|
|
#if defined( __XCC__ ) || defined( __POCC__ )
|
|
if( iDec < 16 )
|
|
{
|
|
if( iDec >= 0 )
|
|
return doComplete5i / (LONGLONG) dPow;
|
|
else if( iDec > -16 )
|
|
return doComplete5i * (LONGLONG) dPow;
|
|
}
|
|
#endif
|
|
if( iDec < 0 )
|
|
return doComplete5i * dPow;
|
|
else
|
|
return doComplete5i / dPow;
|
|
}
|
|
|
|
HB_EXPORT double hb_numInt( double dNum )
|
|
{
|
|
double dInt;
|
|
|
|
#if defined( HB_DBLFL_PREC_FACTOR ) && !defined( HB_C52_STRICT )
|
|
/* Similar hack as in round to make this functions compatible */
|
|
dNum *= HB_DBLFL_PREC_FACTOR;
|
|
#endif
|
|
modf( dNum, &dInt );
|
|
|
|
return dInt;
|
|
}
|
|
|
|
HB_EXPORT 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 );
|
|
}
|
|
|
|
static BOOL hb_str2number( BOOL fPCode, const char* szNum, ULONG ulLen, HB_LONG * lVal, double * dVal, int * piDec, int * piWidth )
|
|
{
|
|
BOOL fDbl = FALSE, fDec = FALSE, fNeg, fHex = FALSE;
|
|
ULONG ulPos = 0;
|
|
int c, iWidth, iDec = 0, iDecR = 0;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_str2number(%d, %p, %lu, %p, %p, %p, %p)", (int) fPCode, szNum, ulLen, lVal, dVal, piDec, piWidth ));
|
|
|
|
while( ulPos < ulLen && HB_ISSPACE( szNum[ulPos] ) )
|
|
ulPos++;
|
|
|
|
if( ulPos >= ulLen )
|
|
{
|
|
fNeg = FALSE;
|
|
}
|
|
else if( szNum[ulPos] == '-' )
|
|
{
|
|
fNeg = TRUE;
|
|
ulPos++;
|
|
}
|
|
else
|
|
{
|
|
fNeg = FALSE;
|
|
if( szNum[ulPos] == '+' )
|
|
ulPos++;
|
|
}
|
|
|
|
*lVal = 0;
|
|
|
|
/* Hex Number */
|
|
if( fPCode && ulPos + 1 < ulLen && szNum[ulPos] == '0' &&
|
|
( szNum[ulPos+1] == 'X' || szNum[ulPos+1] == 'x' ) )
|
|
{
|
|
ulPos += 2;
|
|
iWidth = HB_DEFAULT_WIDTH;
|
|
fHex = TRUE;
|
|
for( ; ulPos < ulLen; ulPos++ )
|
|
{
|
|
c = szNum[ulPos];
|
|
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_LONG lLimV;
|
|
int iLimC;
|
|
|
|
lLimV = HB_LONG_MAX / 10;
|
|
iLimC = ( int ) ( HB_LONG_MAX % 10 );
|
|
|
|
iWidth = ulPos;
|
|
|
|
for( ; ulPos < ulLen; ulPos++ )
|
|
{
|
|
c = szNum[ulPos];
|
|
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 = TRUE;
|
|
}
|
|
if( fDec )
|
|
iDec++;
|
|
else
|
|
iWidth++;
|
|
}
|
|
else if( c == '.' && !fDec )
|
|
{
|
|
fDec = TRUE;
|
|
}
|
|
else
|
|
{
|
|
while( !fDec && ulPos < ulLen )
|
|
{
|
|
if( szNum[ulPos++] == '.' )
|
|
fDec = TRUE;
|
|
else
|
|
iWidth++;
|
|
}
|
|
if( fDec )
|
|
iDecR = ulLen - ulPos;
|
|
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 = TRUE;
|
|
}
|
|
if( iDec )
|
|
{
|
|
#if defined( __XCC__ ) || defined( __POCC__ )
|
|
if( iDec < 16 )
|
|
*dVal /= ( 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 = ( int ) ulLen;
|
|
else if( iWidth == 0 )
|
|
*piWidth = 1;
|
|
else if( fNeg && iWidth == 1 && *dVal != 0 )
|
|
*piWidth = 2;
|
|
else
|
|
*piWidth = iWidth;
|
|
}
|
|
}
|
|
}
|
|
|
|
return fDbl;
|
|
}
|
|
|
|
HB_EXPORT BOOL hb_compStrToNum( const char* szNum, ULONG ulLen, HB_LONG * plVal, double * pdVal, int * piDec, int * piWidth )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_compStrToNum( %s, %lu, %p, %p, %p, %p)", szNum, ulLen, plVal, pdVal, piDec, piWidth ));
|
|
return hb_str2number( TRUE, szNum, ulLen, plVal, pdVal, piDec, piWidth );
|
|
}
|
|
|
|
HB_EXPORT BOOL hb_valStrnToNum( const char* szNum, ULONG ulLen, HB_LONG * plVal, double * pdVal, int * piDec, int * piWidth )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_valStrToNum( %s, %lu, %p, %p, %p, %p)", szNum, ulLen, plVal, pdVal, piDec, piWidth ));
|
|
return hb_str2number( FALSE, szNum, ulLen, plVal, pdVal, piDec, piWidth );
|
|
}
|
|
|
|
HB_EXPORT BOOL hb_strToNum( const char* szNum, HB_LONG * plVal, double * pdVal )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strToNum(%s, %p, %p)", szNum, plVal, pdVal ));
|
|
return hb_str2number( FALSE, szNum, strlen( szNum ), plVal, pdVal, NULL, NULL );
|
|
}
|
|
|
|
HB_EXPORT BOOL hb_strnToNum( const char* szNum, ULONG ulLen, HB_LONG * plVal, double * pdVal )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strToNum(%s, %lu, %p, %p)", szNum, ulLen, plVal, pdVal ));
|
|
return hb_str2number( FALSE, szNum, ulLen, plVal, pdVal, NULL, NULL );
|
|
}
|
|
|
|
/* returns the numeric value of a character string representation of a number */
|
|
HB_EXPORT double hb_strVal( const char * szText, ULONG ulLen )
|
|
{
|
|
HB_LONG lVal;
|
|
double dVal;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strVal(%s, %lu)", szText, ulLen));
|
|
|
|
if( ! hb_str2number( FALSE, szText, ulLen, &lVal, &dVal, NULL, NULL ) )
|
|
dVal = ( double ) lVal;
|
|
return dVal;
|
|
}
|
|
|
|
HB_EXPORT HB_LONG hb_strValInt( const char * szText, int * iOverflow )
|
|
{
|
|
HB_LONG lVal;
|
|
double dVal;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strValInt(%s)", szText));
|
|
|
|
if( hb_str2number( TRUE, szText, strlen( szText ), &lVal, &dVal, NULL, NULL ) )
|
|
{
|
|
*iOverflow = 1;
|
|
return 0;
|
|
}
|
|
*iOverflow = 0;
|
|
return lVal;
|
|
}
|
|
|
|
/*
|
|
* This function copies szText to destination buffer.
|
|
* NOTE: Unlike the documentation for strncpy, this routine will always append
|
|
* a null
|
|
*/
|
|
HB_EXPORT char * hb_strncpy( char * pDest, const char * pSource, ULONG ulLen )
|
|
{
|
|
char *pBuf = pDest;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strncpy(%p, %s, %lu)", pDest, pSource, ulLen));
|
|
|
|
pDest[ ulLen ] ='\0';
|
|
|
|
while( ulLen && ( *pDest++ = *pSource++ ) != '\0' )
|
|
{
|
|
ulLen--;
|
|
}
|
|
|
|
while(ulLen--)
|
|
{
|
|
*pDest++ = '\0';
|
|
}
|
|
|
|
return pBuf;
|
|
}
|
|
|
|
/*
|
|
* This function copies szText to destination buffer.
|
|
* NOTE: Unlike the documentation for strncat, this routine will always append
|
|
* a null and the ulLen param is pDest size not pSource limit
|
|
*/
|
|
HB_EXPORT char * hb_strncat( char * pDest, const char * pSource, ULONG ulLen )
|
|
{
|
|
char *pBuf = pDest;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strncpy(%p, %s, %lu)", pDest, pSource, ulLen));
|
|
|
|
pDest[ ulLen ] ='\0';
|
|
|
|
while( ulLen && *pDest )
|
|
{
|
|
pDest++;
|
|
ulLen--;
|
|
}
|
|
|
|
while( ulLen && ( *pDest++ = *pSource++ ) != '\0' )
|
|
{
|
|
ulLen--;
|
|
}
|
|
|
|
/* if someone will need this then please uncomment the cleaning the rest of
|
|
buffer. */
|
|
/*
|
|
while(ulLen--)
|
|
{
|
|
*pDest++ = '\0';
|
|
}
|
|
*/
|
|
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
|
|
*/
|
|
HB_EXPORT char * hb_strncpyLower( char * pDest, const char * pSource, ULONG ulLen )
|
|
{
|
|
char *pBuf = pDest;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strncpyLower(%p, %s, %lu)", pDest, pSource, ulLen));
|
|
|
|
pDest[ ulLen ] ='\0';
|
|
|
|
/* some compilers implement tolower as a macro, and this has side effects! */
|
|
/* *pDest++ = tolower( *pSource++ ); */
|
|
while( ulLen && ( *pDest++ = ( char ) tolower( ( UCHAR ) *pSource ) ) != '\0' )
|
|
{
|
|
ulLen--;
|
|
pSource++;
|
|
}
|
|
|
|
while( ulLen-- )
|
|
{
|
|
*pDest++ = '\0';
|
|
}
|
|
|
|
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
|
|
*/
|
|
HB_EXPORT char * hb_strncpyUpper( char * pDest, const char * pSource, ULONG ulLen )
|
|
{
|
|
char *pBuf = pDest;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strncpyUpper(%p, %s, %lu)", pDest, pSource, ulLen));
|
|
|
|
pDest[ ulLen ] ='\0';
|
|
|
|
/* some compilers implement toupper as a macro, and this has side effects! */
|
|
/* *pDest++ = toupper( *pSource++ ); */
|
|
while( ulLen && ( *pDest++ = ( char ) toupper( ( UCHAR ) *pSource ) ) != '\0' )
|
|
{
|
|
ulLen--;
|
|
pSource++;
|
|
}
|
|
|
|
while( ulLen-- )
|
|
{
|
|
*pDest++ = '\0';
|
|
}
|
|
|
|
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
|
|
*/
|
|
HB_EXPORT char * hb_strncpyUpperTrim( char * pDest, const char * pSource, ULONG ulLen )
|
|
{
|
|
char *pBuf = pDest;
|
|
ULONG ulSLen;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strncpyUpperTrim(%p, %s, %lu)", pDest, pSource, ulLen));
|
|
|
|
ulSLen = 0;
|
|
while( ulSLen < ulLen && pSource[ ulSLen ] )
|
|
{
|
|
ulSLen++;
|
|
}
|
|
while( ulSLen && pSource[ ulSLen - 1 ] == ' ')
|
|
{
|
|
ulSLen--;
|
|
}
|
|
|
|
pDest[ ulLen ] = '\0';
|
|
|
|
/* some compilers impliment toupper as a macro, and this has side effects! */
|
|
/* *pDest++ = toupper( *pSource++ ); */
|
|
while( ulLen && ulSLen &&
|
|
( *pDest++ = ( char ) toupper( ( UCHAR ) *pSource ) ) != '\0' )
|
|
{
|
|
ulSLen--;
|
|
ulLen--;
|
|
pSource++;
|
|
}
|
|
|
|
while( ulLen-- )
|
|
{
|
|
*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
|
|
*/
|
|
HB_EXPORT char * hb_strncpyTrim( char * pDest, const char * pSource, ULONG ulLen )
|
|
{
|
|
char *pBuf = pDest;
|
|
ULONG ulSLen;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strncpyTrim(%p, %s, %lu)", pDest, pSource, ulLen));
|
|
|
|
ulSLen = 0;
|
|
while( ulSLen < ulLen && pSource[ ulSLen ] )
|
|
{
|
|
ulSLen++;
|
|
}
|
|
while( ulSLen && pSource[ ulSLen - 1 ] == ' ' )
|
|
{
|
|
ulSLen--;
|
|
}
|
|
|
|
pDest[ ulLen ] ='\0';
|
|
|
|
/* some compilers impliment toupper as a macro, and this has side effects! */
|
|
/* *pDest++ = toupper( *pSource++ ); */
|
|
while( ulLen && ulSLen && ( *pDest++ = *pSource++ ) != '\0' )
|
|
{
|
|
ulSLen--;
|
|
ulLen--;
|
|
}
|
|
|
|
while( ulLen-- )
|
|
{
|
|
*pDest++ = '\0';
|
|
}
|
|
|
|
return pBuf;
|
|
}
|
|
|
|
HB_EXPORT char * hb_strRemEscSeq( char *str, ULONG *pLen )
|
|
{
|
|
ULONG ul = *pLen, ulStripped = 0;
|
|
char *ptr, *dst, ch;
|
|
|
|
ptr = dst = str;
|
|
while( ul )
|
|
{
|
|
if( *ptr == '\\' )
|
|
break;
|
|
++ptr; ++dst;
|
|
--ul;
|
|
}
|
|
|
|
while( ul-- )
|
|
{
|
|
ch = *ptr++;
|
|
if( ch == '\\' )
|
|
{
|
|
++ulStripped;
|
|
if( ul )
|
|
{
|
|
ul--;
|
|
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 '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
ch -= '0';
|
|
if( ul && *ptr >= '0' && *ptr <= '7' )
|
|
{
|
|
ch = ( ch << 3 ) | ( *ptr++ - '0' );
|
|
++ulStripped;
|
|
if( --ul && *ptr >= '0' && *ptr <= '7' )
|
|
{
|
|
ch = ( ch << 3 ) | ( *ptr++ - '0' );
|
|
++ulStripped;
|
|
--ul;
|
|
}
|
|
}
|
|
break;
|
|
case 'x':
|
|
ch = 0;
|
|
while( ul )
|
|
{
|
|
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;
|
|
++ulStripped;
|
|
--ul;
|
|
}
|
|
break;
|
|
case '\\':
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
|
|
}
|
|
*dst++ = ch;
|
|
}
|
|
|
|
if( ulStripped )
|
|
{
|
|
*dst = '\0';
|
|
*pLen -= ulStripped;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
char * hb_compEncodeString( int iMethod, const char * szText, ULONG * pulLen )
|
|
{
|
|
char * pBuffer = ( char * ) hb_xgrab( *pulLen + 1 );
|
|
|
|
memcpy( pBuffer, szText, *pulLen );
|
|
pBuffer[ *pulLen ] = '\0';
|
|
if( iMethod == 1 )
|
|
{
|
|
ULONG ul;
|
|
for( ul = 0; ul < *pulLen; ul++ )
|
|
pBuffer[ ul ] ^= 0xF3;
|
|
}
|
|
return pBuffer;
|
|
}
|
|
|
|
char * hb_compDecodeString( int iMethod, const char * szText, ULONG * pulLen )
|
|
{
|
|
char * pBuffer = ( char * ) hb_xgrab( *pulLen + 1 );
|
|
|
|
memcpy( pBuffer, szText, *pulLen );
|
|
pBuffer[ *pulLen ] = '\0';
|
|
if( iMethod == 1 )
|
|
{
|
|
ULONG ul;
|
|
for( ul = 0; ul < *pulLen; ul++ )
|
|
pBuffer[ ul ] ^= 0xF3;
|
|
}
|
|
return pBuffer;
|
|
}
|