- source
+ src
* src/Makefile
* src/dynlib/mt/Makefile
* src/dynlib/Makefile
* INSTALL
* Makefile
* ChangeLog
* harbour.spec
* mpkg_tgz.sh
* Renamed 'source' dir to 'src' to move closer to other FOSS
projects. It's also easier to type, plus it has the side
effect that some cmdlines will be shorter in the
build process.
1107 lines
29 KiB
C
1107 lines
29 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* Harbour common string functions (accessed from standalone utilities and the RTL)
|
|
*
|
|
* Copyright 1999-2001 Viktor Szakats (harbour.01 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 COPYING for licensing terms.
|
|
*
|
|
*/
|
|
|
|
#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" };
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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( ( 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( ( UCHAR ) *pszPos );
|
|
|
|
return pszText;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
char * hb_strduptrim( const char * pszText )
|
|
{
|
|
char * pszDup;
|
|
ULONG ulLen;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strduptrim(%s)", pszText));
|
|
|
|
while( pszText[ 0 ] == ' ' )
|
|
++pszText;
|
|
|
|
ulLen = strlen( pszText );
|
|
while( ulLen && pszText[ ulLen - 1 ] == ' ' )
|
|
--ulLen;
|
|
|
|
pszDup = ( char * ) hb_xgrab( ulLen + 1 );
|
|
memcpy( pszDup, pszText, ulLen );
|
|
pszDup[ ulLen ] = '\0';
|
|
|
|
return pszDup;
|
|
}
|
|
|
|
ULONG hb_strlentrim( const char * pszText )
|
|
{
|
|
ULONG ul = 0;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_strlentrim(%s)", pszText));
|
|
|
|
while( pszText[ 0 ] == ' ' )
|
|
++pszText;
|
|
|
|
while( pszText[ ul] )
|
|
++ul;
|
|
|
|
while( ul && pszText[ ul - 1 ] == ' ' )
|
|
--ul;
|
|
|
|
return ul;
|
|
}
|
|
|
|
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 = 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, 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 ) HB_TOUPPER( ( unsigned char ) s1[ ulCount ] );
|
|
unsigned char c2 = ( char ) HB_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.
|
|
*/
|
|
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().
|
|
*/
|
|
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 );
|
|
}
|
|
|
|
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_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
|
|
|
|
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;
|
|
}
|
|
|
|
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
|
|
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 );
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
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 */
|
|
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_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;
|
|
}
|
|
|
|
char * hb_numToStr( char * szBuf, ULONG ulSize, HB_LONG lNumber )
|
|
{
|
|
int iPos = ( int ) ulSize;
|
|
BOOL fNeg = FALSE;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_numToStr(%p, %lu, %" PFHL "i)", szBuf, ulSize, lNumber));
|
|
|
|
szBuf[ --iPos ] = '\0';
|
|
if( lNumber < 0 )
|
|
{
|
|
fNeg = 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, '*', ulSize - 1 );
|
|
iPos = 0;
|
|
}
|
|
|
|
return &szBuf[ iPos ];
|
|
}
|
|
|
|
/*
|
|
* This function copies szText to destination buffer.
|
|
* NOTE: Unlike the documentation for strncpy, this routine will always append
|
|
* a null
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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';
|
|
|
|
while( ulLen && ( *pDest++ = ( char ) HB_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
|
|
*/
|
|
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';
|
|
|
|
while( ulLen && ( *pDest++ = ( char ) HB_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
|
|
*/
|
|
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';
|
|
|
|
while( ulLen && ulSLen &&
|
|
( *pDest++ = ( char ) HB_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
|
|
*/
|
|
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';
|
|
|
|
while( ulLen && ulSLen && ( *pDest++ = *pSource++ ) != '\0' )
|
|
{
|
|
ulSLen--;
|
|
ulLen--;
|
|
}
|
|
|
|
while( ulLen-- )
|
|
*pDest++ = '\0';
|
|
|
|
return pBuf;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* 'pDest' must be double the size of 'size'. [vszakats] */
|
|
void hb_strtohex( const char * pSource, ULONG size, char * pDest )
|
|
{
|
|
ULONG i;
|
|
|
|
for( i = 0; i < size; i++ )
|
|
{
|
|
int b;
|
|
b = ( ( UCHAR ) pSource[ i ] >> 4 ) & 0x0F;
|
|
*pDest++ = ( char ) ( b + ( b > 9 ? 'a' - 10 : '0' ) );
|
|
b = ( UCHAR ) pSource[ i ] & 0x0F;
|
|
*pDest++ = ( char ) ( b + ( b > 9 ? 'a' - 10 : '0' ) );
|
|
}
|
|
}
|