/* * $Id$ */ /* * Harbour Project source code: * Harbour common string functions (accessed from standalone utilities and the RTL) * * Copyright 1999-2001 Viktor Szakats * 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 * hb_stricmp() * * See doc/license.txt 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 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; } 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; } 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; } #if ! defined( HB__USE_OWN_SNPRINTF ) #undef _HB_SNPRINTF_ADD_EOS #undef hb_snprintf /* NOTE: The full size of the buffer is expected as nSize. [vszakats] */ ULONG hb_snprintf( char * buffer, ULONG nSize, const char * format, ... ) { va_list arglist; ULONG result; va_start( arglist, format ); #if defined( __DJGPP__ ) && ( __DJGPP__ < 2 || ( __DJGPP__ == 2 && __DJGPP_MINOR__ <= 3 ) ) /* Use vsprintf() for DJGPP <= 2.03. This is a temporary hack, should implement a C99 snprintf() ourselves. */ result = vsprintf( buffer, format, arglist ); #define _HB_SNPRINTF_ADD_EOS #elif defined( _MSC_VER ) && _MSC_VER >= 1400 result = _vsnprintf_s( buffer, nSize, _TRUNCATE, format, arglist ); #elif ( defined( _MSC_VER ) || defined( __DMC__ ) ) && !defined( __XCC__ ) result = _vsnprintf( buffer, nSize, format, arglist ); #define _HB_SNPRINTF_ADD_EOS #elif defined( __WATCOMC__ ) && __WATCOMC__ < 1200 result = _vbprintf( buffer, nSize, format, arglist ); #else result = vsnprintf( buffer, nSize, format, arglist ); #endif va_end( arglist ); #ifdef _HB_SNPRINTF_ADD_EOS if( buffer && nSize ) buffer[ nSize - 1 ] = '\0'; #endif return result; } #endif